Compare commits

..

33 Commits

Author SHA1 Message Date
a6783692c5 animation: Set size through CSS
Pretty much the same case of the previous commit: we want this size
to be scale-dependant, and using the width and height properties of
ClutterActor doesn't automatically update.

Use CSS to set the width and height.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1176
2020-04-06 14:37:35 -03:00
1c27b68bcc appDisplay: Set the folder icon geometry through CSS
The CSS engine is scale-aware, whereas simply setting the
width and height properties directly isn't.

Use CSS to set the folder icon.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1176
2020-04-06 14:37:35 -03:00
717c05a288 st/theme-node: Use the node's scale factor
Each node stores the scale factor in place when it was created.
Creating nodes with the same style, but with different scale
factors, yields different nodes.

Use the node's scale factor instead of retrieving the context's
one.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1176
2020-04-06 14:37:35 -03:00
e68604b1aa st/theme-node: Consider scale factor when comparing
The CSS engine of St is scale-aware, which means every length
and size it produces is multiplied by the current scale factor.

However, the individual nodes aren't aware of the scale factor
when they compare to each other.

Store and compare the scale factors in the nodes themselves.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1635

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1176
2020-04-06 14:37:35 -03:00
0368ad29e9 st/theme-context: Add a getter for the scale-factor property
Will be used by the next commit to avoid going through the GObject
machinery when retrieving the scale factor.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1176
2020-04-06 14:37:35 -03:00
b982ce394e shell-app: Use container widget for fallback X11 app icons
Just like StIcon does, we should use a container widget for the fallback
app icon that we get using the cairo surface property. It's needed
because the widget returned by shell_app_create_icon_texture() can be
resized freely, while we want the aspect ratio of the actual texture to
remain the same.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2578


(cherry picked from commit 85846d88f0)
2020-04-06 15:00:05 +00:00
025647f585 st/theme-context: Also invalidate root node on stylesheet changes
Since commit 6a42d77261 we invalidate the
cached properties for each theme node on stylesheet changes by iterating
over the hashtable of the theme context instead of listening to the
signal in each individual theme node.

That commit forgot one particular node though that's not stored in the
hashtable, but using the `priv->root_node` property instead: The theme
node that belongs to the stage.

So make sure we also invalidate the cached properties of the stage theme
node on stylesheet changes. This fixes various crashes that happened
with extensions providing custom stylesheets (emitting the
"custom-stylesheets-changed" signal on every extension enable/disable),
trying to access an already freed CSS property of the stage.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2584


(cherry picked from commit bc973b80d7)
2020-04-06 14:59:45 +00:00
7125b726ad data: Add extension-portal desktop file
Now that the extension preference dialog is opened by a separate
D-Bus service rather than the Extensions app, it can be opened
without a parent window that provides name and icon.

Fix this by adding back a hidden .desktop file.

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


(cherry picked from commit 6b7c85b079)
2020-04-05 13:48:39 +00:00
aebfab7207 extensions-app: Add category in .desktop file
Predefined categories aren't a great way for organizing installed
applications, but they have their use in "stores" like Software
or flathub.

Not listing any category means we fall through the cracks, so
pick the (hopefully) least inappropriate one ...

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1160


(cherry picked from commit 360f5b1642)
2020-04-05 12:46:11 +00:00
698bd5b3a9 st/icon: Use a static GIcon for the missing-image icon
Don't create a new GIcon for the "missing-image" texture but simply
create it once statically instead and always use that.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1179


(cherry picked from commit 1ca39e8586)
2020-04-04 19:40:10 +00:00
51e9f19f2f st/icon: Always show empty texture if both gicons are NULL
Commit 7ff7fb5d3b forgot to clear the
`priv->icon_texture` actor when returning from st_icon_update(), which
means we don't always switch to an empty icon if both gicon properties
are set to NULL.

Fix this and destroy the actor before returning early from
st_icon_update().

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1178


(cherry picked from commit 07deda593a)
2020-04-04 19:30:49 +00:00
6d38a4a7b3 Update Latvian translation 2020-04-04 16:14:40 +00:00
dfcc5ffb1e screenShield: Wake up on deactivate()
Usually the screen is woken up before the shield is deactivated, but
it is also possible to unlock the session programmatically via the
org.gnome.ScreenSaver D-Bus API.

The intention is very likely not to unlock a turned off screen in
that case. Nor does it seem like a good idea to change the lock
state without any indication.

Waking up the screen is more likely to meet expectations and is
more reasonable too, so do that.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1158


(cherry picked from commit fbe2e30f38)
2020-04-03 15:09:24 +00:00
8b80a4cf4d screenShield: Switch lightboxes off before unlock transition
There is no point in animating a transition with fullscreen black
rectangles stacked on top, so switch them off before rather than
after the transition.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1158


(cherry picked from commit fb6ead2881)
2020-04-03 15:08:58 +00:00
01e894c028 st/icon: Only load default fallback icon if an icon was set and failed to load
Commit c89d6a633 introduced a default fallback icon that would be displayed in
case the main gicon or the fallback gicon wasn't set or failed to load.

This broke the use case where a StIcon is created but no main icon or
fallback icon are set on purpose, for example the appindicator extension
which always creates a StIcon to represent icons in menu items but the
actual icons are only set if the application provides one, leaving the
menu showing the default fallback ("image-missing") icon for all menu
entries that don't actually have an icon provided by the application.

Fix that by only using the default fallback icon if the provided one
failed to load.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1173

(cherry picked from commit 7ff7fb5d3b)
2020-04-03 17:00:30 +02:00
856adfd1f1 extensionUtils: Add openPrefs() convenience method
Opening their own preferences is a reasonable desire for extensions,
so make up for breaking it by adding a convenience method for that
action.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1163

(cherry picked from commit 8030d9ad32)
2020-04-03 17:00:07 +02:00
efee3aa749 extensionSystem: Add method for opening extension prefs
Extension that want to expose their own preferences (for example as menu
items) do that by passing their UUID to gnome-shell-extension-prefs.

But since 3.36.1 the app is optional and no longer accepts arguments on
the command line. To adjust, extensions now need to make a D-Bus call
the extensions portal, just like the app and gnome-shell.

We will add a convenience method for that purpose, so it makes
sense to share the existing code. As it's extension-related, the
extension manager looks like the right place ...

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1163

(cherry picked from commit 45bc850715)
2020-04-03 16:58:15 +02:00
15e72da648 workspace: Fix chaining up
Gah, accidentally dropped the 'vfunc' prefix :-(

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1172
2020-04-03 15:47:01 +02:00
3f8bd1db25 extensions-app: Do not expand headerbar switch
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2563
2020-04-03 15:47:01 +02:00
3a863ee341 js: Account for promisified call() method
A promisified method expects the callback parameter to be either
a function (in which case the original method is called normally)
or omitted altogether (in which case a Promise is returned).

The call to open application details in Software does neither and
passes null instead, which will result in a warning (because no
function argument means a promise will be used, but not omitting
the parameter means we end up with too many arguments).

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2551
2020-04-03 02:03:18 +00:00
654a7af929 environment: Move g_dbus_connection_call() promisification
Commit 83c6b2ab promisified the method in endSessionDialog, which means
that after the module is imported, every caller will get the promisifed
version. That can be a bit surprising in completely unrelated modules,
so commit 764527c8 (on master) moved the promisification of more common
methods into environment, as that's initialized early and expected to be
shared between anything else.

Do the same for the call() method on the stable branch.

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2551
2020-04-03 02:03:18 +00:00
8dd9cbac7f app-cache: Fix cache for folder translations
The app-cache code currently stores the folder translations in a hash
that can be accessed via shell_util_get_translated_folder_name().
This hash uses the filename (inc. extension) for the "desktop-directory"
as key which causes an issue when trying to find the translation
on AppDisplay._findBestFolderName() which gets categories (folder names)
from the app info which doesn't contain the ".directory" extension.

Fix that by storing the filename without extension as the hash key for
the cached folder translations.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1168


(cherry picked from commit 343b3351f1)
2020-04-03 00:40:34 +00:00
331db650dd appDisplay: Don't clear signal handler id before emitting
Otherwise we won't clear the 'view-loaded' handler after it was emitted.

Also move field initialization to the correct place, i.e. the init
function of the base class.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1169


(cherry picked from commit a9df4e7516)
2020-04-02 21:10:30 +00:00
428d38179d Update Serbian translation 2020-04-02 19:43:03 +00:00
fe9708ebd8 Update Basque translation 2020-04-02 16:15:32 +00:00
8398769321 Update Finnish translation 2020-04-02 09:44:36 +00:00
768c08ba9d main: Don't override DesktopAppInfo desktop if already GNOME
During the shell initialization we call the (deprecated) function to
override the Desktop environment in Gio DesktopAppInfo to make sure that
applications are correctly shown (as per commit b2fbf5a2), however this
might break the cases in which $XDG_CURRENT_DESKTOP is already set and
contains GNOME (given that is now a list).

In Ubuntu this is in fact set to: ubuntu:GNOME.
Now, if an application contains NotShowIn=ubuntu, the key will be ignored by
the shell, and the application is still listed everywhere.

So, override the DesktopAppInfo desktop environment only in the case that
the current desktop is not already GNOME.

At the current date I think we could just safely get rid of this override at
all, but there could be still cases where it still might be useful, like when
running as nested in some other environment, so keeping it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/1156


(cherry picked from commit a0def23940)
2020-04-01 03:58:56 +00:00
69426cbfda Update Persian translation 2020-04-01 01:42:46 +00:00
9f968e7378 appDisplay: Clear animateLater callbacks when unmapping
In some situations we could end up not with lingering 'view-loaded'
handler. This could result in delayed spring animate-in being initiated,
e.g. after a minute after the activities overview was already closed.

Fix this by removing any lingering signal or later handlers when
unmapping.

Fixes: 5c33fe4a0a

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1155


(cherry picked from commit f49b58cf97)
2020-03-31 17:12:35 +00:00
1ab5e6973a Update Chinese (Taiwan) translation 2020-03-31 16:07:19 +00:00
1dea3341ec Update Friulian translation 2020-03-31 11:14:15 +00:00
8fda054dc5 Bump version to 3.36.1
Update NEWS.
2020-03-31 00:27:47 +02:00
e989684602 extensions-app/metainfo: Point screenshots to stable branch 2020-03-30 21:32:17 +02:00
272 changed files with 24206 additions and 32674 deletions

1
.gitignore vendored
View File

@ -60,6 +60,7 @@ src/calendar-server/evolution-calendar.desktop
src/calendar-server/org.gnome.Shell.CalendarServer.service src/calendar-server/org.gnome.Shell.CalendarServer.service
src/gnome-shell src/gnome-shell
src/gnome-shell-calendar-server src/gnome-shell-calendar-server
src/gnome-shell-extension-prefs
src/gnome-shell-extension-tool src/gnome-shell-extension-tool
src/gnome-shell-hotplug-sniffer src/gnome-shell-hotplug-sniffer
src/gnome-shell-perf-helper src/gnome-shell-perf-helper

View File

@ -9,6 +9,7 @@ stages:
variables: variables:
BUNDLE: "extensions-git.flatpak" BUNDLE: "extensions-git.flatpak"
JS_LOG: "js-report.txt" JS_LOG: "js-report.txt"
POT_LOG: "pot-update.txt"
.only_default: &only_default .only_default: &only_default
only: only:
@ -17,7 +18,7 @@ variables:
- merge_requests - merge_requests
check_commit_log: check_commit_log:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: review stage: review
variables: variables:
GIT_DEPTH: "100" GIT_DEPTH: "100"
@ -27,10 +28,10 @@ check_commit_log:
- merge_requests - merge_requests
js_check: js_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- find js -name '*.js' -exec js68 -c -s '{}' ';' 2>&1 | tee $JS_LOG - find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
- (! grep -q . $JS_LOG) - (! grep -q . $JS_LOG)
<<: *only_default <<: *only_default
artifacts: artifacts:
@ -39,7 +40,7 @@ js_check:
when: on_failure when: on_failure
eslint: eslint:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- ./.gitlab-ci/run-eslint.sh - ./.gitlab-ci/run-eslint.sh
@ -50,23 +51,22 @@ eslint:
when: always when: always
potfile_check: potfile_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- ./.gitlab-ci/check-potfiles.sh - ./.gitlab-ci/check-potfiles.sh
<<: *only_default <<: *only_default
no_template_check: no_template_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- ./.gitlab-ci/check-template-strings.sh - ./.gitlab-ci/check-template-strings.sh
<<: *only_default <<: *only_default
build: build:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: build stage: build
needs: []
before_script: before_script:
- .gitlab-ci/checkout-mutter.sh - .gitlab-ci/checkout-mutter.sh
- meson mutter mutter/build --prefix=/usr -Dtests=false - meson mutter mutter/build --prefix=/usr -Dtests=false
@ -83,9 +83,8 @@ build:
- build - build
test: test:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: test stage: test
needs: ["build"]
variables: variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir" XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
NO_AT_BRIDGE: "1" NO_AT_BRIDGE: "1"
@ -100,9 +99,24 @@ test:
- build/meson-logs/testlog.txt - build/meson-logs/testlog.txt
when: on_failure when: on_failure
test-pot:
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: test
before_script:
- ninja -C mutter/build install
script:
# Check that pot files are generated correctly:
# https://savannah.gnu.org/bugs/?50920#comment5
- ninja -C build gnome-shell-pot 2>&1 | awk '
BEGIN { start=0; }
start==1 { print $0; }
/gnome-shell-pot/ { start=1; }
' | tee $POT_LOG
- (! grep -q . $POT_LOG)
<<: *only_default
flatpak: flatpak:
stage: build stage: build
needs: []
variables: variables:
SUBPROJECT: "subprojects/extensions-app" SUBPROJECT: "subprojects/extensions-app"
# Your manifest path # Your manifest path
@ -110,7 +124,11 @@ flatpak:
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo" RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
FLATPAK_MODULE: "gnome-extensions-app" FLATPAK_MODULE: "gnome-extensions-app"
APP_ID: "org.gnome.Extensions" APP_ID: "org.gnome.Extensions"
MESON_ARGS: "$SUBPROJECT"
extends: .flatpak extends: .flatpak
before_script:
- flatpak run --command=$SUBPROJECT/generate-translations.sh
--filesystem=host org.gnome.Sdk//master
<<: *only_default <<: *only_default
nightly: nightly:

View File

@ -1,24 +0,0 @@
# Rebuild and push with
#
# cd .gitlab-ci/
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 .
# podman push registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
#
FROM registry.fedoraproject.org/fedora:32
RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(copr)' git && \
# For syntax checks with `find . -name '*.js' -exec js68 -c -s '{}' ';'`
dnf install -y findutils mozjs68-devel && \
# For static analysis with eslint
dnf install -y nodejs && \
npm install -g eslint && \
# Shameless plug for my own tooling; useful for generating zip
dnf copr enable -y fmuellner/gnome-shell-ci && \
dnf install -y gnome-extensions-tool meson && \
dnf clean all

View File

@ -0,0 +1,18 @@
FROM registry.fedoraproject.org/fedora:latest
RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(copr)' git && \
# For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'`
dnf install -y findutils mozjs60-devel && \
# For static analysis with eslint
dnf install -y nodejs && \
npm install -g eslint && \
# Shameless plug for my own tooling; useful for generating zip
dnf copr enable -y fmuellner/gnome-shell-ci && \
dnf install -y gnome-extensions-tool meson && \
dnf clean all && \
rm -rf /var/cache/dnf

View File

@ -6,11 +6,6 @@ globs=('*.js' '*.c')
# find source files that contain gettext keywords # find source files that contain gettext keywords
files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs) files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs)
# filter out excluded files
if [ -f po/POTFILES.skip ]; then
files=$(for f in $files; do ! grep -q ^$f po/POTFILES.skip && echo $f; done)
fi
# find those that aren't listed in POTFILES.in # find those that aren't listed in POTFILES.in
missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done) missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done)

View File

@ -18,14 +18,12 @@ run_eslint() {
local extra_args=ARGS_$1 local extra_args=ARGS_$1
local output_var=OUTPUT_$1 local output_var=OUTPUT_$1
local output=${!output_var} local output=${!output_var}
local cache=.eslintcache-${1,,}
# ensure output exists even if eslint doesn't report any errors # ensure output exists even if eslint doesn't report any errors
mkdir -p $(dirname $output) mkdir -p $(dirname $output)
touch $output touch $output
eslint -f unix --cache --cache-location $cache ${!extra_args} -o $output \ eslint -f unix ${!extra_args} -o $output js subprojects/extensions-app/js
js subprojects/extensions-app/js
} }
list_commit_range_additions() { list_commit_range_additions() {

198
NEWS
View File

@ -1,154 +1,60 @@
3.37.90 3.36.1
=======
* Fix extension updates when many extensions are installed [Jeremias; !1363]
* Fix missing icons in on-screen keyboard [Emre; #2631, #3007]
* Fix delay when showing calendar events [Sebastian; #2992]
* Allow rearranging items in app picker [Georges; !1284]
* Fix top bar navigation when NumLock is active [Olivier; #550]
* Delay login animation until wallpaper has loaded [Michael; #734996]
* Reset auth prompt on login screen on VT switch before fade in [Ray; #2997]
* Move screencasting into a separate service [Jonas Å.; !1372]
* Replace loaded terms with more descriptive one [Olivier; !1393]
* Add "Boot Options" support to restart dialog [Hans; !199]
* Move "Restart" into a separate menu item/dialog [Florian; #2202]
* Default to not installing updates on low battery [Michael; #2717]
* Misc. bug fixes and cleanups [Florian, Daniel V., Georges, Jonas Å.,
Daniel G., Carlos, Benjamin, Piotr, Andre, Jonas D., Andy; !1357, !1356,
#2969, #2969, !1358, !1371, #3005, !1380, #3022, !1381, !895, !1387, !1386,
!1385, #3037, !1389, !1390, !1391, !1383, !1399, #2983, !1403]
Contributors:
Jonas Ådahl, Benjamin Berg, Michael Catanzaro, Piotr Drąg, Jonas Dreßler,
Olivier Fourdan, Carlos Garnacho, Hans de Goede, Andy Holmes,
Sebastian Keller, Andre Moreira Magalhaes, Daniel García Moreno,
Florian Müllner, Georges Basile Stavracas Neto, Jeremias Ortega, Ray Strode,
Emre Uyguroglu, Daniel van Vugt
Translators:
Tim Sabsch [de], Boyuan Yang [zh_CN], Fabio Tomat [fur],
Efstathios Iosifidis [el], Rafael Fontenelle [pt_BR], Yuri Chornoivan [uk],
Daniel Șerbănescu [ro], Jordi Mas [ca], Daniel Mustieles [es],
Emin Tufan Çetin [tr], Asier Sarasua Garmendia [eu]
3.37.3
====== ======
* Refactor and clean up window picker * Improve app folders [Jonas D.; !1011]
[Jonas D., Florian; !1297, !1298, !1305, !1345, !1353] * Fix launching ibus daemon [Alynx; !1080]
* Move calendar events out of notifications list [Florian; !1282] * Do not shutdown ibus/xsettings on X11 compositor restart [Carlos; #2329]
* Refine app folder dialogs [Georges; !1301] * Hide hint text in entries when preedit is used [Carlos; !1084]
* Hide switch-user button on lock screen if unsupported [Chingkai; #2687] * Do not load app infos on main thread [Christian; #2282]
* Refactor and clean up app picker pagination [Georges; !1271] * Don't expose FDO Notifications interface on main bus name [Florian; !547]
* Add API to retrieve specified mimetypes from clipboards [Carlos; !1321] * Fix icon of mobile broadband connections [Cosimo, Reik; !1097, !1105]
* Support prepending workspace with horizontal layouts [Florian; #2916] * Fix high-contrast/symbolic icon mix-up [Florian; #2414]
* Update microphone icon on input volume changes [fludixx; #2902] * Don't ellipsize times in world clock [Florian; !1090]
* Cache labels on GPU [Daniel; !1329] * Only check for extension updates if there are any extensions [Florian; !1100]
* Fix regressions in redesigned modal dialogs [Florian, Jonas D.; #2491, !1336] * Fix crash when trying to update removed extensions [Florian; #2343]
* Use GIcon for all application icons [Florian; !1342] * Make Extensions app available as flatpak [Florian; !1081, !1106, !1087, !1133]
* Support pre-authenticated logins in vmware environments [yun341; #1983] * Display fractional timezones as hours:minutes [Jonas D.; #2438]
* Better support sandboxed apps with multiple .desktop files [Florian; #219] * Fix assigning pad keybindings [Carlos; #2451]
* Fix on-screen keyboard size in portrait orientation [Florian; #2349] * Handle embedded newlines in lock screen notifications [Florian; #2463]
* Plugged leaks [Sebastian, Daniel, Florian; !1306, !1319, !1341] * Fix OSK layout fallback for unsupported variants [Florian; #2471]
* Misc. bug fixes and cleanups [Jonas D., Georges, Marco, Florian, Sebastian, * Do not apply text color to color glyphs (emojis) [Carlos; #850]
MOZGIII, Daniel, Mariana, Jonas Å.; !1296, !1295, #2643, !1300, !1309, * Check "Install pending software updates" by default [Michael; #2427]
!1119, #2901, !1313, !1251, !1285, !1307, !1318, !1310, !1320, !1327, !1315, * Do not warn about missing GDM on each login [Florian; #2432]
!1289, !1331, !1332, !1333, !1334, !1340, !1287, !1308, !1346, !1299, !1343, * Fix telepathy chat notifications [Marco; !1112]
!1351, !1352, !1322] * Fix offline updates support in end session dialog [Michael; #2276]
* Fix activating notifications by keyboard [Florian; #2319]
* Remove handling of 'blacklisted' extensions [Florian; !1132]
* Only update extensions if Extensions app is installed [Florian; #2346]
* Improve Norwegian on-screen-keyboard layout [Bjørn; !1073]
* Fix IM support for deleting surrounding text [Takao; !477]
* Fix blur effect with fractional scaling [Jonas D.; !1000]
* Use better location name in weather section [Florian; #2468]
* Fix glitch in sound feedback on volume changes [Florian; !1147]
* Fix on-screen keyboard regressions [Jonas D.; !1142]
* Improve screen-reader support [Luke; #2508, #2517]
* Fix password entry resize on login/lock screen [Florian; #2423]
* Fix crash when opening app picker [Jonas Å.; !1154]
* Misc. bug fixes and cleanups [Florian, Sebastian, Jan, Daniel, Philip, Mario,
Ray, Marco, Jonas D., Carlos, Georges; #2298, #2305, !1078, !1077, #2334,
#2381, !1093, !1098, #2386, !1108, !1109, !1114, !1076, !1072, !1115, !1088,
!1101, #2467, !1121, !1122, #2476, !1123, !1117, !1129, !1113, !1102, !1127,
#2238, !1131, !1135, !1136, !849, #2504, #2371, !1146, !1141, #2510, !1150]
Contributors: Contributors:
Marco Trevisan (Treviño), Chingkai, Jonas Dreßler, Carlos Garnacho, Marco Trevisan (Treviño), Michael Catanzaro, Cosimo Cecchi, Jonas Dreßler,
Sebastian Keller, MOZGIII, Florian Müllner, Georges Basile Stavracas Neto, Takao Fujiwara, Carlos Garnacho, Christian Hergert, Sebastian Keller,
Mariana Picolo, Daniel van Vugt, fludixx, yun341, Jonas Ådahl Reik Keutterling, Bjørn Lie, Florian Müllner, Jwtiyar Nariman,
Georges Basile Stavracas Neto, Mario Sanchez Prada, Ray Strode, Jan Tojnar,
Daniel van Vugt, Philip Withnall, Luke Yelavich, Alynx Zhou, Jonas Ådahl
Translators: Translators:
Daniel Mustieles [es], Boyuan Yang [zh_CN], Yuri Chornoivan [uk], Марко Костић [sr], Jordi Mas [ca], sicklylife [ja], Marek Černocký [cs],
Jordi Mas [ca], sicklylife [ja], Emin Tufan Çetin [tr], Daniel Rusek [cs], Kjartan Maraas [nb], Tim Sabsch [de], Stas Solovey [ru],
Baurzhan Muftakhidinov [kk], Florentina Mușat [ro], Aurimas Černius [lt], Peter Mráz [sk], Rafael Fontenelle [pt_BR], Piotr Drąg [pl],
Rūdolfs Mazurs [lv] Milo Casagrande [it], Anders Jonsson [sv], Yuri Chornoivan [uk],
Kukuh Syafaat [id], Guillaume Bernard [fr], Daniel Mustieles [es],
3.37.2 Danial Behzadi [fa], Goran Vidović [hr], Yosef Or Boczko [he],
====== Emin Tufan Çetin [tr], Wolfgang Stöggl [de], Ibai Oihanguren Sala [eu],
* Add support for "PrefersNonDefaultGPU" desktop key [Bastien; !1226] Jwtiyar Nariman [ckb], Aurimas Černius [lt]
* Only start systemd units when running under systemd
[Carlos, Florian; #2755, !1242, !1252]
* Fix "ghost" media controls [Bryan; #2776]
* Fix zombie sockets from extensions downloader [Michael; #2774]
* Update world clocks offsets when timezone changes [Bryan; #2209]
* Support scrolling anywhere in slider menu items [Peter; #2795]
* Fix "Do Not Disturb" setting getting reset on startup [Florian; #2804]
* Only allow updates for extensions that aren't cached [Florian; !1248]
* Fix matching notifications by PID [Florian; #2592]
* Indicate extension errors in Extensions app [Florian; #2337]
* Add clipboard API for querying supported mimetypes [Andy; #2819]
* Add preview to color picker [Florian; #451]
* Improve world clocks styling [PrOF-kk; #2825]
* Remove Frequent view from app picker [Georges; !880]
* Fix pad OSD glitches [Carlos; !1290]
* Expose actor tree in looking glass [Georges; !1292]
* Fixed crashes [Jonas D., Florian; #2709, #2757]
* Misc. bug fixes and cleanups [Florian, AsciiWolf, Michael, Piotr, Ting-Wei,
Amr, Alexander, Bryan, Georges, Jonas D., Andy, Björn, Koki, Carlos; !1229,
!1231, !1233, !1235, #2578, #2735, #2751, #2602, #2777, !1249, #2796, !1268,
!1269, !1265, !1245, !1273, #2816, !1274, !1263, !1188, !1276, #2652, !1277,
!1281, #2286, !1267, !1286, !1279, !1288, !1293, !1294, !1291]
Contributors:
AsciiWolf, Michael Catanzaro, Björn Daase, Jonas Dreßler, Bryan Dunsmore,
Koki Fukuda, Carlos Garnacho, Andy Holmes, Amr Ibrahim, Soslan Khubulov,
Ting-Wei Lan, Michael Lass, Alexander Mikhaylenko, Florian Müllner,
Georges Basile Stavracas Neto, Bastien Nocera, PrOF-kk, Peter Simonyi
Translators:
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Yuri Chornoivan [uk],
Dušan Kazik [sk], Piotr Drąg [pl], Soslan Khubulov [os],
Daniel Mustieles [es], Nathan Follens [nl], Bruce Cowan [en_GB],
Florentina Mușat [ro], Milo Casagrande [it], Anders Jonsson [sv],
Charles Monzat [fr], Danial Behzadi [fa], sicklylife [ja], Kukuh Syafaat [id],
Jordi Mas [ca], Emin Tufan Çetin [tr], Jiri Grönroos [fi], Марко Костић [sr],
Christian Kirbach [de], Changwoo Ryu [ko], Matej Urbančič [sl]
3.37.1
======
* Improve bluetooth submenu title [Mariana; #2340]
* Add openPrefs() convenience method for extensions [Florian; !1163]
* Bring back support for empty StIcons [Andre, Jonas D.; !1173, !1178]
* Wake up screen when unlocking programmatically [Florian; !1158]
* Improve extensions tool error reporting [Florian; #2391]
* Improve handling of scale-factor changes [Georges; !1176]
* Tone down weekend days with events in calendar [Jakub; #2588]
* Fix showing bluetooth submenu when devices were set up [Florian; !1174]
* Add support for parental controls filtering [Philip W.; !465]
* Provide alternative extension templates [Florian; !812]
* Improve weather section's empty state [Mariana; #2179]
* Fix translations of folder names [Florian; #2623]
* Drop Tweener [Jonas Å.; !1200]
* Match ASCII alternatives of system actions [Will; #2688]
* Fix delay on lock screen after entering wrong password [Jonas D.; #2655]
* Use globalThis instead of window [Andy; #2322]
* Inhibit remote access when disabled by session mode [Jonas Å.; !1210]
* Improve calendar-server performance [Milan; #1875]
* Add gnome-shell-extension-prefs wrapper for compatibility [Florian; !1220]
* Fix stuck lock screen after unlock [Jonas D., Florian; #2446]
* Fixed crashes [Jonas D., Florian, Carlos; #2584, #2625, !1223, !1218]
* Misc. bug fixes and cleanups [Florian, Jonas Å., Marco, Andre, Georges,
Jonas D., Jan, Philip Ch.,, Xiaoguang, Will, Jordan, Matthew, qarmin;
!1126, !1155, !1156, !1165, !1168, !1169, #2551, #2563, !1172, !1175, !1179,
!1160, #2562, #2578, !1184, #2559, !1186, #2607, !1191, !1194, !1199, !1203,
#2649, #2628, !1205, !1206, !1208, !1207, !1211, !1214, !1213, !1192, !1217,
!1219, #1615, #2691, !1094, !1177]
Contributors:
Marco Trevisan (Treviño), Philip Chimento, Milan Crha, Jonas Dreßler,
Carlos Garnacho, Andy Holmes, Matthew Leeds, Andre Moreira Magalhaes,
Florian Müllner, Georges Basile Stavracas Neto, Jordan Petridis,
Mariana Picolo, Jakub Steiner, Will Thompson, Jan Tojnar, Xiaoguang Wang,
Philip Withnall, qarmin, Jonas Ådahl
Translators:
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Danial Behzadi [fa],
Jiri Grönroos [fi], Ibai Oihanguren Sala [eu], Марко Костић [sr],
Rūdolfs Mazurs [lv], Yuri Chornoivan [uk], Carmen Bianca BAKKER [eo],
Dingzhong Chen [zh_CN], Rafael Fontenelle [pt_BR], Petr Kovář [cs],
Asier Sarasua Garmendia [eu], Daniel Mustieles [es], Emin Tufan Çetin [tr]
3.36.0 3.36.0
====== ======

View File

@ -20,12 +20,6 @@
<method name="ListSessions"> <method name="ListSessions">
<arg name="sessions" type="a(susso)" direction="out"/> <arg name="sessions" type="a(susso)" direction="out"/>
</method> </method>
<method name="CanRebootToBootLoaderMenu">
<arg type="s" direction="out"/>
</method>
<method name="SetRebootToBootLoaderMenu">
<arg type="t" direction="in"/>
</method>
<signal name="PrepareForSleep"> <signal name="PrepareForSleep">
<arg type="b" direction="out"/> <arg type="b" direction="out"/>
</signal> </signal>

View File

@ -1,191 +0,0 @@
<!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.Mutter.ScreenCast:
@short_description: Screen cast interface
This API is private and not intended to be used outside of the integrated
system that uses libmutter. No compatibility between versions are
promised.
-->
<interface name="org.gnome.Mutter.ScreenCast">
<!--
CreateSession:
@properties: Properties
@session_path: Path to the new session object
* "remote-desktop-session-id" (s): The ID of a remote desktop session.
Remote desktop driven screen casts
are started and stopped by the remote
desktop session.
* "disable-animations" (b): Set to "true" if the screen cast application
would prefer animations to be globally
disabled, while the session is running. Default
is "false". Available since version 3.
-->
<method name="CreateSession">
<arg name="properties" type="a{sv}" direction="in" />
<arg name="session_path" type="o" direction="out" />
</method>
<!--
Version:
@short_description: API version
-->
<property name="Version" type="i" access="read" />
</interface>
<!--
org.gnome.Mutter.ScreenCast.Session:
@short_description: Screen cast session
-->
<interface name="org.gnome.Mutter.ScreenCast.Session">
<!--
Start:
Start the screen cast session
-->
<method name="Start" />
<!--
Stop:
Stop the screen cast session
-->
<method name="Stop" />
<!--
Closed:
The session has closed.
-->
<signal name="Closed" />
<!--
RecordMonitor:
@connector: Connector of the monitor to record
@properties: Properties
@stream_path: Path to the new stream object
Record a single monitor.
Available @properties include:
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
Available since API version 2.
* "is-recording" (b): Whether this is a screen recording. May be
be used for choosing panel icon.
Default: false. Available since API version 4.
Available cursor mode values:
0: hidden - cursor is not included in the stream
1: embedded - cursor is included in the framebuffer
2: metadata - cursor is included as metadata in the PipeWire stream
-->
<method name="RecordMonitor">
<arg name="connector" type="s" direction="in" />
<arg name="properties" type="a{sv}" direction="in" />
<arg name="stream_path" type="o" direction="out" />
</method>
<!--
RecordWindow:
@properties: Properties used determining what window to select
@stream_path: Path to the new stream object
Supported since API version 2.
Record a single window. The cursor will not be included.
Available @properties include:
* "window-id" (t): Id of the window to record.
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see RecordMonitor).
* "is-recording" (b): Whether this is a screen recording. May be
be used for choosing panel icon.
Default: false. Available since API version 4.
-->
<method name="RecordWindow">
<arg name="properties" type="a{sv}" direction="in" />
<arg name="stream_path" type="o" direction="out" />
</method>
<!--
RecordArea:
@x: X position of the recorded area
@y: Y position of the recorded area
@width: width of the recorded area
@height: height of the recorded area
@properties: Properties
@stream_path: Path to the new stream object
Record an area of the stage. The coordinates are in stage coordinates.
The size of the stream does not necessarily match the size of the
recorded area, and will depend on DPI scale of the affected monitors.
Available @properties include:
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
Available since API version 2.
* "is-recording" (b): Whether this is a screen recording. May be
be used for choosing panel icon.
Default: false. Available since API version 4.
Available cursor mode values:
0: hidden - cursor is not included in the stream
1: embedded - cursor is included in the framebuffer
2: metadata - cursor is included as metadata in the PipeWire stream
-->
<method name="RecordArea">
<arg name="x" type="i" direction="in" />
<arg name="y" type="i" direction="in" />
<arg name="width" type="i" direction="in" />
<arg name="height" type="i" direction="in" />
<arg name="properties" type="a{sv}" direction="in" />
<arg name="stream_path" type="o" direction="out" />
</method>
</interface>
<!--
org.gnome.Mutter.ScreenCast.Stream:
@short_description: Screen cast stream
-->
<interface name="org.gnome.Mutter.ScreenCast.Stream">
<!--
PipeWireStreamAdded:
@short_description: Pipewire stream added
A signal emitted when PipeWire stream for the screen cast stream has
been created. The @node_id corresponds to the PipeWire stream node.
-->
<signal name="PipeWireStreamAdded">
<annotation name="org.gtk.GDBus.C.Name" value="pipewire-stream-added"/>
<arg name="node_id" type="u" direction="out" />
</signal>
<!--
Parameters:
@short_description: Optional stream parameters
Available parameters include:
* "position" (ii): Position of the source of the stream in the
compositor coordinate space.
* "size" (ii): Size of the source of the stream in the compositor
coordinate space.
-->
<property name="Parameters" type="a{sv}" access="read" />
</interface>
</node>

View File

@ -1,19 +1,12 @@
<node> <node>
<interface name="org.gnome.Shell.CalendarServer"> <interface name="org.gnome.Shell.CalendarServer">
<method name="SetTimeRange"> <method name="GetEvents">
<arg type="x" name="since" direction="in"/> <arg type="x" direction="in" />
<arg type="x" name="until" direction="in"/> <arg type="x" direction="in" />
<arg type="b" name="force_reload" direction="in"/> <arg type="b" direction="in" />
<arg type="a(sssbxxa{sv})" direction="out" />
</method> </method>
<signal name="EventsAddedOrUpdated">
<arg type="a(ssbxxa{sv})" name="events" direction="out"/>
</signal>
<signal name="EventsRemoved">
<arg type="as" name="ids" direction="out"/>
</signal>
<signal name="ClientDisappeared">
<arg type="s" name="source_uid" direction="out"/>
</signal>
<property name="HasCalendars" type="b" access="read" /> <property name="HasCalendars" type="b" access="read" />
<signal name="Changed" />
</interface> </interface>
</node> </node>

View File

@ -70,14 +70,6 @@
--> -->
<property name="AnimationsEnabled" type="b" access="read"/> <property name="AnimationsEnabled" type="b" access="read"/>
<!--
ScreenSize:
@short_description: The size of the screen
Since: 3
-->
<property name="ScreenSize" type="(ii)" access="read"/>
<property name="version" type="u" access="read"/> <property name="version" type="u" access="read"/>
</interface> </interface>
</node> </node>

View File

@ -2,6 +2,7 @@
<gresources> <gresources>
<gresource prefix="/org/gnome/shell/dbus-interfaces"> <gresource prefix="/org/gnome/shell/dbus-interfaces">
<file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file> <file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file>
<file preprocess="xml-stripblanks">net.hadess.SwitcherooControl.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.Application.xml</file> <file preprocess="xml-stripblanks">org.freedesktop.Application.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file> <file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Manager.xml</file> <file preprocess="xml-stripblanks">org.freedesktop.bolt1.Manager.xml</file>
@ -28,7 +29,6 @@
<file preprocess="xml-stripblanks">org.freedesktop.UPower.xml</file> <file preprocess="xml-stripblanks">org.freedesktop.UPower.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Magnifier.xml</file> <file preprocess="xml-stripblanks">org.gnome.Magnifier.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Magnifier.ZoomRegion.xml</file> <file preprocess="xml-stripblanks">org.gnome.Magnifier.ZoomRegion.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Mutter.ScreenCast.xml</file>
<file preprocess="xml-stripblanks">org.gnome.ScreenSaver.xml</file> <file preprocess="xml-stripblanks">org.gnome.ScreenSaver.xml</file>
<file preprocess="xml-stripblanks">org.gnome.SessionManager.EndSessionDialog.xml</file> <file preprocess="xml-stripblanks">org.gnome.SessionManager.EndSessionDialog.xml</file>
<file preprocess="xml-stripblanks">org.gnome.SessionManager.Inhibitor.xml</file> <file preprocess="xml-stripblanks">org.gnome.SessionManager.Inhibitor.xml</file>

View File

@ -6,25 +6,24 @@
<file>checkbox-off-focused.svg</file> <file>checkbox-off-focused.svg</file>
<file>checkbox-off.svg</file> <file>checkbox-off.svg</file>
<file>checkbox.svg</file> <file>checkbox.svg</file>
<file alias="icons/scalable/actions/color-pick.svg">color-pick.svg</file>
<file>dash-placeholder.svg</file> <file>dash-placeholder.svg</file>
<file>gnome-shell.css</file> <file>gnome-shell.css</file>
<file>gnome-shell-high-contrast.css</file> <file>gnome-shell-high-contrast.css</file>
<file alias="icons/scalable/status/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file> <file alias="icons/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file>
<file>no-events.svg</file> <file>no-events.svg</file>
<file>no-notifications.svg</file> <file>no-notifications.svg</file>
<file>pad-osd.css</file> <file>pad-osd.css</file>
<file alias="icons/scalable/status/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file> <file alias="icons/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file>
<file alias="icons/scalable/status/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file> <file alias="icons/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file> <file alias="icons/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file> <file alias="icons/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file> <file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file> <file alias="icons/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-caps-lock-filled-symbolic.svg">keyboard-caps-lock-filled-symbolic.svg</file> <file alias="icons/keyboard-caps-lock-filled-symbolic.svg">keyboard-caps-lock-filled-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-enter-symbolic.svg">keyboard-enter-symbolic.svg</file> <file alias="icons/keyboard-enter-symbolic.svg">keyboard-enter-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-hide-symbolic.svg">keyboard-hide-symbolic.svg</file> <file alias="icons/keyboard-hide-symbolic.svg">keyboard-hide-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-layout-filled-symbolic.svg">keyboard-layout-filled-symbolic.svg</file> <file alias="icons/keyboard-layout-filled-symbolic.svg">keyboard-layout-filled-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-shift-filled-symbolic.svg">keyboard-shift-filled-symbolic.svg</file> <file alias="icons/keyboard-shift-filled-symbolic.svg">keyboard-shift-filled-symbolic.svg</file>
<file>process-working.svg</file> <file>process-working.svg</file>
<file>toggle-off.svg</file> <file>toggle-off.svg</file>
<file>toggle-off-dark.svg</file> <file>toggle-off-dark.svg</file>

View File

@ -1,7 +1,7 @@
[Unit] [Unit]
Description=GNOME Shell on Wayland Description=GNOME Shell on Wayland
# On wayland, force a session shutdown # On wayland, force a session shutdown
OnFailure=org.gnome.Shell-disable-extensions.service gnome-session-shutdown.target OnFailure=gnome-shell-disable-extensions.service gnome-session-shutdown.target
OnFailureJobMode=replace-irreversibly OnFailureJobMode=replace-irreversibly
CollectMode=inactive-or-failed CollectMode=inactive-or-failed
RefuseManualStart=on RefuseManualStart=on
@ -13,21 +13,18 @@ Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target Before=gnome-session-initialized.target
# The units already conflict because they use the same BusName
#Conflicts=gnome-shell-x11.service
[Service] [Service]
Slice=session.slice
Type=notify Type=notify
# NOTE: This can be replaced with ConditionEnvironment=XDG_SESSION_TYPE=%I
# with systemd >= 245. Also, the current solution is kind of painful
# as systemd had a bug where it retries the condition.
# Only start if the template instance matches the session type.
ExecCondition=/bin/sh -c 'test "$XDG_SESSION_TYPE" = "%I" || exit 2'
ExecStart=@bindir@/gnome-shell ExecStart=@bindir@/gnome-shell
# Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1
# unset some environment variables that were set by the shell and won't work now that the shell is gone # unset some environment variables that were set by the shell and won't work now that the shell is gone
ExecStopPost=-systemctl --user unset-environment GNOME_SETUP_DISPLAY WAYLAND_DISPLAY DISPLAY XAUTHORITY ExecStopPost=-systemctl --user unset-environment GNOME_SETUP_DISPLAY WAYLAND_DISPLAY DISPLAY XAUTHORITY
# Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1
# On wayland we cannot restart # On wayland we cannot restart
Restart=no Restart=no
# Kill any stubborn child processes after this long # Kill any stubborn child processes after this long

View File

@ -6,5 +6,5 @@ Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target Before=gnome-session-initialized.target
Wants=org.gnome.Shell@wayland.service Requires=gnome-shell-wayland.service
Wants=org.gnome.Shell@x11.service After=gnome-shell-wayland.service

View File

@ -1,7 +1,7 @@
[Unit] [Unit]
Description=GNOME Shell on X11 Description=GNOME Shell on X11
# On X11, try to show the GNOME Session Failed screen # On X11, try to show the GNOME Session Failed screen
OnFailure=org.gnome.Shell-disable-extensions.service gnome-session-failed.target OnFailure=gnome-shell-disable-extensions.service gnome-session-failed.target
OnFailureJobMode=replace OnFailureJobMode=replace
CollectMode=inactive-or-failed CollectMode=inactive-or-failed
RefuseManualStart=on RefuseManualStart=on
@ -13,24 +13,18 @@ Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target Before=gnome-session-initialized.target
# The units already conflict because they use the same BusName
#Conflicts=gnome-shell-wayland.service
# Limit startup frequency more than the default # Limit startup frequency more than the default
StartLimitIntervalSec=15s StartLimitIntervalSec=15s
StartLimitBurst=3 StartLimitBurst=3
[Service] [Service]
Slice=session.slice
Type=notify Type=notify
# NOTE: This can be replaced with ConditionEnvironment=XDG_SESSION_TYPE=%I
# with systemd >= 245. Also, the current solution is kind of painful
# as systemd had a bug where it retries the condition.
# Only start if the template instance matches the session type.
ExecCondition=/bin/sh -c 'test "$XDG_SESSION_TYPE" = "%I" || exit 2'
ExecStart=@bindir@/gnome-shell ExecStart=@bindir@/gnome-shell
# Exit code 1 means we are probably *not* dealing with an extension failure # Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1 SuccessExitStatus=1
# On X11 we do not need to unset any variables
# On X11 we want to restart on-success (Alt+F2 + r) and on-failure. # On X11 we want to restart on-success (Alt+F2 + r) and on-failure.
Restart=always Restart=always
# Do not wait before restarting the shell # Do not wait before restarting the shell

View File

@ -0,0 +1,10 @@
[Unit]
Description=GNOME Shell on X11
DefaultDependencies=no
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
Requires=gnome-shell-x11.service
After=gnome-shell-x11.service

View File

@ -101,21 +101,22 @@ if have_systemd
unitconf.set('bindir', bindir) unitconf.set('bindir', bindir)
configure_file( configure_file(
input: 'org.gnome.Shell@x11.service.in', input: 'gnome-shell-x11.service.in',
output: 'org.gnome.Shell@x11.service', output: 'gnome-shell-x11.service',
configuration: unitconf, configuration: unitconf,
install_dir: systemduserunitdir install_dir: systemduserunitdir
) )
configure_file( configure_file(
input: 'org.gnome.Shell@wayland.service.in', input: 'gnome-shell-wayland.service.in',
output: 'org.gnome.Shell@wayland.service', output: 'gnome-shell-wayland.service',
configuration: unitconf, configuration: unitconf,
install_dir: systemduserunitdir install_dir: systemduserunitdir
) )
units = files('org.gnome.Shell.target', units = files('gnome-shell-x11.target',
'org.gnome.Shell-disable-extensions.service') 'gnome-shell-wayland.target',
'gnome-shell-disable-extensions.service')
install_data(units, install_dir: systemduserunitdir) install_data(units, install_dir: systemduserunitdir)
endif endif

View File

@ -109,17 +109,6 @@
the shell. the shell.
</description> </description>
</key> </key>
<key name="app-picker-layout" type="aa{sv}">
<default>[]</default>
<summary>Layout of the app picker</summary>
<description>
Layout of the app picker. Each entry in the array is a page. Pages are
stored in the order they appear in GNOME Shell. Each page contains an
“application id” → 'data' pair. Currently, the following values are
stored as 'data':
• “position”: the position of the application icon in the page
</description>
</key>
<child name="keybindings" schema="org.gnome.shell.keybindings"/> <child name="keybindings" schema="org.gnome.shell.keybindings"/>
</schema> </schema>

View File

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="5.4116011mm"
height="5.1374583mm"
viewBox="0 0 5.4116011 5.1374583"
version="1.1"
id="svg5595"
inkscape:version="0.92.4 (unknown)"
sodipodi:docname="color-pick.svg">
<defs
id="defs5589">
<filter
inkscape:collect="always"
x="-0.10291173"
width="1.2058235"
y="-0.065432459"
height="1.1308649"
id="filter5601"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.610872"
id="feGaussianBlur5603" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:cx="39.387731"
inkscape:cy="12.554326"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5592">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-103.12753,-146.26461)">
<circle
r="8.4810486"
cy="9.82623"
cx="10.226647"
id="circle7584"
style="color:#000000;display:inline;overflow:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter:url(#filter5601)"
transform="matrix(0.26458333,0,0,0.26458333,103.12753,146.26461)" />
<path
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26399338;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 108.07728,148.64122 c 0,1.2393 -1.00465,2.24394 -2.24395,2.24394 -1.23929,0 -2.24716,-1.00465 -2.25221,-2.24394 l -0.009,-2.24458 2.26136,6.4e-4 c 1.2393,3.4e-4 2.24395,1.00464 2.24395,2.24394 z"
id="path7523-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssscss" />
<circle
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#50dbb5;fill-opacity:1;stroke:none;stroke-width:0.36885914;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="path7482-1"
cx="105.83707"
cy="148.64352"
r="1.844296" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1,15 +1,21 @@
/* App Grid */ /* App Grid */
$app_icon_size: 96px; $app_icon_size: 96px;
$app_icon_padding: 24px;
// app icons // app icons
.icon-grid { .icon-grid {
row-spacing: $base_spacing * 6; -shell-grid-horizontal-item-size: $app_icon_size + $app_icon_padding * 2;
column-spacing: $base_spacing * 6; -shell-grid-vertical-item-size: $app_icon_size + $app_icon_padding * 2;
max-row-spacing: $base_spacing * 12; spacing: $base_spacing * 6;
max-column-spacing: $base_spacing * 12;
.overview-icon {
icon-size: $app_icon_size;
}
} }
//.app-display { spacing: 20px; }
/* App Icons */ /* App Icons */
$app_grid_fg_color: #fff; $app_grid_fg_color: #fff;
@ -38,8 +44,8 @@ $app_grid_fg_color: #fff;
.app-folder-dialog { .app-folder-dialog {
border-radius: $modal_radius * 1.5; border-radius: $modal_radius * 1.5;
border: 1px solid $osd_outer_borders_color; border: 1px solid $osd_outer_borders_color;
spacing: 12px;
background-color: transparentize(darken($osd_bg_color,10%), 0.05); background-color: transparentize(darken($osd_bg_color,10%), 0.05);
padding: 12px;
& .folder-name-container { & .folder-name-container {
padding: 24px 36px 0; padding: 24px 36px 0;
@ -48,7 +54,7 @@ $app_grid_fg_color: #fff;
& .folder-name-label, & .folder-name-label,
& .folder-name-entry { & .folder-name-entry {
font-size: 18pt; font-size: 18pt;
font-weight: 800; font-weight: bold;
} }
& .folder-name-entry { width: 300px } & .folder-name-entry { width: 300px }
@ -67,24 +73,11 @@ $app_grid_fg_color: #fff;
& > StIcon { icon-size: 16px } & > StIcon { icon-size: 16px }
} }
} }
& .icon-grid {
row-spacing: $base_spacing * 2;
column-spacing: $base_spacing * 5;
}
& .page-indicators {
margin-bottom: 18px;
.page-indicator {
padding: 15px 12px;
}
}
} }
.app-folder-dialog-container { .app-folder-dialog-container {
padding: 12px; padding: 12px;
width: 620px; width: 800px;
height: 620px; height: 600px;
} }
.app-folder-icon { .app-folder-icon {
@ -130,11 +123,15 @@ $app_grid_fg_color: #fff;
} }
// Some hacks I don't even know // Some hacks I don't even know
.all-apps { .all-apps,
.frequent-apps > StBoxLayout {
// horizontal padding to make sure scrollbars or dash don't overlap content // horizontal padding to make sure scrollbars or dash don't overlap content
padding: 0px 88px 10px 88px; padding: 0px 88px 10px 88px;
} }
// Label when no frequent apps
.no-frequent-applications-label { @extend %status_text; }
// shutdown and other actions in the grid // shutdown and other actions in the grid
.system-action-icon { .system-action-icon {
background-color: rgba(0,0,0,0.8); background-color: rgba(0,0,0,0.8);
@ -142,3 +139,44 @@ $app_grid_fg_color: #fff;
border-radius: 99px; border-radius: 99px;
icon-size: $app_icon_size * 0.5; icon-size: $app_icon_size * 0.5;
} }
/* Frequent | All toggle */
// container
.app-view-controls {
padding-bottom: 32px;
}
// buttons
.app-view-control {
padding: 4px 32px;
margin: 0 4px;
&, &:hover, &:checked {
@include button(undecorated);
color: darken($osd_fg_color, 25%);
}
&:hover {
color: $osd_fg_color;
box-shadow: inset 0 -2px darken($osd_fg_color, 25%);
}
&:active {
box-shadow: inset 0 -2px $osd_fg_color;
}
&:checked {
color: $osd_fg_color;
box-shadow: inset 0 -2px $selected_bg_color;
}
&:first-child {
border-right-width: 0;
border-radius: 0;
}
&:last-child {
border-radius: 0;
}
}

View File

@ -153,11 +153,9 @@
} }
.calendar-day-with-events { .calendar-day-with-events {
background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
&.calendar-work-day {
color: lighten($fg_color,10%); color: lighten($fg_color,10%);
font-weight: bold; font-weight: bold;
} background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
} }
.calendar-other-month-day { .calendar-other-month-day {
@ -177,32 +175,6 @@
} }
} }
/* Events */
.events-button {
@include notification_bubble;
padding: $base_padding * 2;
.events-box {
spacing: $base_spacing;
}
.events-list {
spacing: 2 * $base_spacing;
}
.events-title {
color: desaturate(darken($fg_color,40%), 10%);
font-weight: bold;
margin-bottom: $base_margin;
}
.event-time {
color: darken($fg_color,20%);
font-feature-settings: "tnum";
@include fontsize($base_font_size - 1);
}
}
/* World clocks */ /* World clocks */
.world-clocks-button { .world-clocks-button {
@include notification_bubble; @include notification_bubble;
@ -230,11 +202,9 @@
.world-clocks-time { .world-clocks-time {
font-weight: bold; font-weight: bold;
color: $fg_color; color: $fg_color;
font-feature-settings: "tnum"; font-feature-settings: "lnum";
@include fontsize($base_font_size); @include fontsize($base_font_size);
text-align: right;
&:ltr { text-align: right; }
&:rtl { text-align: left; }
} }
// timezone offset label // timezone offset label

View File

@ -138,10 +138,11 @@
.user-widget.horizontal .user-widget-label { .user-widget.horizontal .user-widget-label {
@include fontsize($base_font_size + 2); @include fontsize($base_font_size + 2);
font-weight: bold; font-weight: bold;
text-align: left;
padding-left: 15px; padding-left: 15px;
&:ltr { padding-left: 14px; text-align: left; } &:ltr { padding-left: 14px; }
&:rtl { padding-right: 14px; text-align: right; } &:rtl { padding-right: 14px; }
} }
.user-widget.vertical .user-widget-label { .user-widget.vertical .user-widget-label {

View File

@ -1,7 +1,5 @@
/* Looking Glass */ /* Looking Glass */
$text_fg_color: #ccc;
// Dialog // Dialog
#LookingGlassDialog { #LookingGlassDialog {
background-color: $osd_bg_color; background-color: $osd_bg_color;
@ -54,11 +52,6 @@ $text_fg_color: #ccc;
&:hover { color: lighten($link_color, 10%); } &:hover { color: lighten($link_color, 10%); }
&:active { color: darken($link_color, 10%); } &:active { color: darken($link_color, 10%); }
} }
.actor-link {
color: $text_fg_color;
&:hover { color: lighten($text_fg_color, 20%); }
&:active { color: darken($text_fg_color, 20%); }
}
} }
.lg-completions-text { .lg-completions-text {

View File

@ -71,11 +71,9 @@
> .event-time { > .event-time {
color: transparentize($fg_color, 0.5); color: transparentize($fg_color, 0.5);
@include fontsize($base_font_size - 2); @include fontsize($base_font_size - 2);
text-align: right;
/* HACK: the label should be baseline-aligned with a 1em label, fake this with some bottom padding */ /* HACK: the label should be baseline-aligned with a 1em label, fake this with some bottom padding */
padding-bottom: 0.13em; padding-bottom: 0.13em;
&:ltr { text-align: right };
&:rtl { text-align: left };
} }
} }

View File

@ -76,10 +76,8 @@ $popover_arrow_height: 12px;
// container for radio and check boxes // container for radio and check boxes
.popup-menu-ornament { .popup-menu-ornament {
text-align: right;
width: 1.2em; width: 1.2em;
&:ltr { text-align: right };
&:rtl { text-align: left };
} }
// separator // separator

View File

@ -54,10 +54,6 @@
@extend %status_text; @extend %status_text;
} }
.grid-search-results {
spacing: $base_spacing * 6;
}
// Search results with icons // Search results with icons
.grid-search-result { .grid-search-result {
@extend %app-well-app; @extend %app-well-app;

View File

@ -1,20 +1,19 @@
/* Window Picker */ /* Window Picker */
$window_picker_spacing: $base_spacing; // 6px $window_picker_spacing: $base_spacing * 2; // 16px
$window_picker_padding: $base_padding * 2; // 12px $window_picker_padding: $base_padding * 2; // 16px
$window_thumbnail_border_color:transparentize($selected_fg_color, 0.65); $window_thumbnail_border_color:transparentize($selected_fg_color, 0.65);
$window_close_button_size: 24px; $window_close_button_size: 24px;
$window_close_button_padding: 3px; $window_close_button_padding: 3px;
$window_clone_border_size: 6px;
// Window picker // Window picker
.window-picker { .window-picker {
// Space between window thumbnails // Space between window thumbnails
spacing: $window_picker_spacing; -horizontal-spacing: $window_picker_spacing;
-vertical-spacing: $window_picker_spacing;
// Padding for container around window thumbnails // Padding for container around window thumbnails
padding: $window_picker_padding; padding: $window_picker_padding;
@ -23,7 +22,7 @@ $window_clone_border_size: 6px;
// Borders on window thumbnails // Borders on window thumbnails
.window-clone-border { .window-clone-border {
border-width: $window_clone_border_size; border-width: 6px;
border-style: solid; border-style: solid;
border-color: $window_thumbnail_border_color; border-color: $window_thumbnail_border_color;
border-radius: $base_border_radius + 2; border-radius: $base_border_radius + 2;
@ -55,6 +54,8 @@ $window_clone_border_size: 6px;
width: $window_close_button_size; width: $window_close_button_size;
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5); box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5);
-shell-close-overlap: $window_close_button_size * 0.5;
&:hover { &:hover {
background-color: lighten($selected_bg_color, 5%); background-color: lighten($selected_bg_color, 5%);
} }

View File

@ -3,8 +3,13 @@ private_headers = [
'gactionobservable.h', 'gactionobservable.h',
'gactionobserver.h', 'gactionobserver.h',
'shell-network-agent.h', 'shell-network-agent.h',
'shell-recorder-src.h'
] ]
if not enable_recorder
private_headers += 'shell-recorder.h'
endif
exclude_directories = [ exclude_directories = [
'calendar-server', 'calendar-server',
'hotplug-sniffer', 'hotplug-sniffer',

View File

@ -25,8 +25,6 @@ var ServiceImplementation = class {
// subclasses may override this to disable automatic shutdown // subclasses may override this to disable automatic shutdown
this._autoShutdown = true; this._autoShutdown = true;
this._queueShutdownCheck();
} }
// subclasses may override this to own additional names // subclasses may override this to own additional names

View File

@ -8,12 +8,6 @@ dbus_services = {
'org.gnome.Shell.Notifications': 'notifications', 'org.gnome.Shell.Notifications': 'notifications',
} }
if enable_recorder
dbus_services += {
'org.gnome.Shell.Screencast': 'screencast',
}
endif
config_dir = '@0@/..'.format(meson.current_build_dir()) config_dir = '@0@/..'.format(meson.current_build_dir())
foreach service, dir : dbus_services foreach service, dir : dbus_services

View File

@ -9,8 +9,6 @@ const { ServiceImplementation } = imports.dbusService;
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications'); const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface); const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
var NotificationDaemon = class extends ServiceImplementation { var NotificationDaemon = class extends ServiceImplementation {
constructor() { constructor() {
super(NotificationsIface, '/org/freedesktop/Notifications'); super(NotificationsIface, '/org/freedesktop/Notifications');
@ -44,15 +42,7 @@ var NotificationDaemon = class extends ServiceImplementation {
null, null); null, null);
} }
async NotifyAsync(params, invocation) { NotifyAsync(params, invocation) {
const pid = await this._getSenderPid(invocation.get_sender());
const hints = params[6];
params[6] = {
...hints,
'sender-pid': new GLib.Variant('u', pid),
};
this._proxy.NotifyRemote(...params, (res, error) => { this._proxy.NotifyRemote(...params, (res, error) => {
if (this._handleError(invocation, error)) if (this._handleError(invocation, error))
return; return;
@ -87,19 +77,4 @@ var NotificationDaemon = class extends ServiceImplementation {
invocation.return_value(new GLib.Variant('(ssss)', res)); invocation.return_value(new GLib.Variant('(ssss)', res));
}); });
} }
async _getSenderPid(sender) {
const res = await Gio.DBus.session.call(
'org.freedesktop.DBus',
'/',
'org.freedesktop.DBus',
'GetConnectionUnixProcessID',
new GLib.Variant('(s)', [sender]),
new GLib.VariantType('(u)'),
Gio.DBusCallFlags.NONE,
-1,
null);
const [pid] = res.deepUnpack();
return pid;
}
}; };

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Shell/Screencast/js">
<file>main.js</file>
<file>screencastService.js</file>
<file>dbusService.js</file>
<file>misc/config.js</file>
<file>misc/fileUtils.js</file>
</gresource>
</gresources>

View File

@ -1,11 +0,0 @@
/* exported main */
const { DBusService } = imports.dbusService;
const { ScreencastService } = imports.screencastService;
function main() {
const service = new DBusService(
'org.gnome.Shell.Screencast',
new ScreencastService());
service.run();
}

View File

@ -1,458 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ScreencastService */
const { Gio, GLib, Gst } = imports.gi;
const { loadInterfaceXML, loadSubInterfaceXML } = imports.misc.fileUtils;
const { ServiceImplementation } = imports.dbusService;
const ScreencastIface = loadInterfaceXML('org.gnome.Shell.Screencast');
const IntrospectIface = loadInterfaceXML('org.gnome.Shell.Introspect');
const IntrospectProxy = Gio.DBusProxy.makeProxyWrapper(IntrospectIface);
const ScreenCastIface = loadSubInterfaceXML(
'org.gnome.Mutter.ScreenCast', 'org.gnome.Mutter.ScreenCast');
const ScreenCastSessionIface = loadSubInterfaceXML(
'org.gnome.Mutter.ScreenCast.Session', 'org.gnome.Mutter.ScreenCast');
const ScreenCastStreamIface = loadSubInterfaceXML(
'org.gnome.Mutter.ScreenCast.Stream', 'org.gnome.Mutter.ScreenCast');
const ScreenCastProxy = Gio.DBusProxy.makeProxyWrapper(ScreenCastIface);
const ScreenCastSessionProxy = Gio.DBusProxy.makeProxyWrapper(ScreenCastSessionIface);
const ScreenCastStreamProxy = Gio.DBusProxy.makeProxyWrapper(ScreenCastStreamIface);
const DEFAULT_PIPELINE = 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux';
const DEFAULT_FRAMERATE = 30;
const DEFAULT_DRAW_CURSOR = true;
const PipelineState = {
INIT: 0,
PLAYING: 1,
FLUSHING: 2,
STOPPED: 3,
};
const SessionState = {
INIT: 0,
ACTIVE: 1,
STOPPED: 2,
};
var Recorder = class {
constructor(sessionPath, x, y, width, height, filePath, options,
invocation,
onErrorCallback) {
this._startInvocation = invocation;
this._dbusConnection = invocation.get_connection();
this._onErrorCallback = onErrorCallback;
this._stopInvocation = null;
this._pipelineIsPlaying = false;
this._sessionIsActive = false;
this._x = x;
this._y = y;
this._width = width;
this._height = height;
this._filePath = filePath;
this._pipelineString = DEFAULT_PIPELINE;
this._framerate = DEFAULT_FRAMERATE;
this._drawCursor = DEFAULT_DRAW_CURSOR;
this._applyOptions(options);
this._watchSender(invocation.get_sender());
this._initSession(sessionPath);
}
_applyOptions(options) {
for (const option in options)
options[option] = options[option].deep_unpack();
if (options['pipeline'] !== undefined)
this._pipelineString = options['pipeline'];
if (options['framerate'] !== undefined)
this._framerate = options['framerate'];
if ('draw-cursor' in options)
this._drawCursor = options['draw-cursor'];
}
_watchSender(sender) {
this._nameWatchId = this._dbusConnection.watch_name(
sender,
Gio.BusNameWatcherFlags.NONE,
null,
this._senderVanished.bind(this));
}
_unwatchSender() {
if (this._nameWatchId !== 0) {
this._dbusConnection.unwatch_name(this._nameWatchId);
this._nameWatchId = 0;
}
}
_senderVanished() {
this._unwatchSender();
this.stopRecording(null);
}
_notifyStopped() {
this._unwatchSender();
if (this._onStartedCallback)
this._onStartedCallback(this, false);
else if (this._onStoppedCallback)
this._onStoppedCallback(this);
else
this._onErrorCallback(this);
}
_onSessionClosed() {
switch (this._pipelineState) {
case PipelineState.STOPPED:
break;
default:
this._pipeline.set_state(Gst.State.NULL);
log(`Unexpected pipeline state: ${this._pipelineState}`);
break;
}
this._notifyStopped();
}
_initSession(sessionPath) {
this._sessionProxy = new ScreenCastSessionProxy(Gio.DBus.session,
'org.gnome.Mutter.ScreenCast',
sessionPath);
this._sessionProxy.connectSignal('Closed', this._onSessionClosed.bind(this));
}
_startPipeline(nodeId) {
this._ensurePipeline(nodeId);
const bus = this._pipeline.get_bus();
bus.add_watch(bus, this._onBusMessage.bind(this));
this._pipeline.set_state(Gst.State.PLAYING);
this._pipelineState = PipelineState.PLAYING;
this._onStartedCallback(this, true);
this._onStartedCallback = null;
}
startRecording(onStartedCallback) {
this._onStartedCallback = onStartedCallback;
const [streamPath] = this._sessionProxy.RecordAreaSync(
this._x, this._y,
this._width, this._height,
{
'is-recording': GLib.Variant.new('b', true),
'cursor-mode': GLib.Variant.new('u', this._drawCursor ? 1 : 0),
});
this._streamProxy = new ScreenCastStreamProxy(Gio.DBus.session,
'org.gnome.ScreenCast.Stream',
streamPath);
this._streamProxy.connectSignal('PipeWireStreamAdded',
(proxy, sender, params) => {
const [nodeId] = params;
this._startPipeline(nodeId);
});
this._sessionProxy.StartSync();
this._sessionState = SessionState.ACTIVE;
}
stopRecording(onStoppedCallback) {
this._pipelineState = PipelineState.FLUSHING;
this._onStoppedCallback = onStoppedCallback;
this._pipeline.send_event(Gst.Event.new_eos());
}
_stopSession() {
this._sessionProxy.StopSync();
this._sessionState = SessionState.STOPPED;
}
_onBusMessage(bus, message, _) {
switch (message.type) {
case Gst.MessageType.EOS:
this._pipeline.set_state(Gst.State.NULL);
switch (this._pipelineState) {
case PipelineState.FLUSHING:
this._pipelineState = PipelineState.STOPPED;
break;
default:
break;
}
switch (this._sessionState) {
case SessionState.ACTIVE:
this._stopSession();
break;
case SessionState.STOPPED:
this._notifyStopped();
break;
default:
break;
}
break;
default:
break;
}
return true;
}
_substituteThreadCount(pipelineDescr) {
const numProcessors = GLib.get_num_processors();
const numThreads = Math.min(Math.max(1, numProcessors), 64);
return pipelineDescr.replace(/%T/, numThreads);
}
_ensurePipeline(nodeId) {
const framerate = this._framerate;
let fullPipeline = `
pipewiresrc path=${nodeId}
do-timestamp=true
keepalive-time=1000
resend-last=true !
video/x-raw,max-framerate=${framerate}/1 !
videoconvert !
${this._pipelineString} !
filesink location="${this._filePath}"`;
fullPipeline = this._substituteThreadCount(fullPipeline);
this._pipeline = Gst.parse_launch_full(fullPipeline,
null,
Gst.ParseFlags.FATAL_ERRORS);
}
};
var ScreencastService = class extends ServiceImplementation {
constructor() {
super(ScreencastIface, '/org/gnome/Shell/Screencast');
Gst.init(null);
this._recorders = new Map();
this._senders = new Map();
this._lockdownSettings = new Gio.Settings({
schema_id: 'org.gnome.desktop.lockdown',
});
this._proxy = new ScreenCastProxy(Gio.DBus.session,
'org.gnome.Mutter.ScreenCast',
'/org/gnome/Mutter/ScreenCast');
this._introspectProxy = new IntrospectProxy(Gio.DBus.session,
'org.gnome.Shell.Introspect',
'/org/gnome/Shell/Introspect');
}
_removeRecorder(sender) {
this._recorders.delete(sender);
if (this._recorders.size === 0)
this.release();
}
_addRecorder(sender, recorder) {
this._recorders.set(sender, recorder);
if (this._recorders.size === 1)
this.hold();
}
_getAbsolutePath(filename) {
if (GLib.path_is_absolute(filename))
return filename;
let videoDir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS);
if (!GLib.file_test(videoDir, GLib.FileTest.EXISTS))
videoDir = GLib.get_home_dir();
return GLib.build_filenamev([videoDir, filename]);
}
_generateFilePath(template) {
let filename = '';
let escape = false;
[...template].forEach(c => {
if (escape) {
switch (c) {
case '%':
filename += '%';
break;
case 'd': {
const datetime = GLib.DateTime.new_now_local();
const datestr = datetime.format('%0x');
const datestrEscaped = datestr.replace(/\//g, '-');
filename += datestrEscaped;
break;
}
case 't': {
const datetime = GLib.DateTime.new_now_local();
const datestr = datetime.format('%0X');
const datestrEscaped = datestr.replace(/\//g, ':');
filename += datestrEscaped;
break;
}
default:
log(`Warning: Unknown escape ${c}`);
}
escape = false;
} else if (c === '%') {
escape = true;
} else {
filename += c;
}
});
if (escape)
filename += '%';
return this._getAbsolutePath(filename);
}
ScreencastAsync(params, invocation) {
let returnValue = [false, ''];
if (this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const sender = invocation.get_sender();
if (this._recorders.get(sender)) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const [sessionPath] = this._proxy.CreateSessionSync({});
const [fileTemplate, options] = params;
const [screenWidth, screenHeight] = this._introspectProxy.ScreenSize;
const filePath = this._generateFilePath(fileTemplate);
let recorder;
try {
recorder = new Recorder(
sessionPath,
0, 0,
screenWidth, screenHeight,
fileTemplate,
options,
invocation,
_recorder => this._removeRecorder(sender));
} catch (error) {
log(`Failed to create recorder: ${error.message}`);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
this._addRecorder(sender, recorder);
try {
recorder.startRecording(
(_, result) => {
if (result) {
returnValue = [true, filePath];
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
} else {
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
});
} catch (error) {
log(`Failed to start recorder: ${error.message}`);
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
}
ScreencastAreaAsync(params, invocation) {
let returnValue = [false, ''];
if (this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const sender = invocation.get_sender();
if (this._recorders.get(sender)) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const [sessionPath] = this._proxy.CreateSessionSync({});
const [x, y, width, height, fileTemplate, options] = params;
const filePath = this._generateFilePath(fileTemplate);
let recorder;
try {
recorder = new Recorder(
sessionPath,
x, y,
width, height,
filePath,
options,
invocation,
_recorder => this._removeRecorder(sender));
} catch (error) {
log(`Failed to create recorder: ${error.message}`);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
this._addRecorder(sender, recorder);
try {
recorder.startRecording(
(_, result) => {
if (result) {
returnValue = [true, filePath];
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
} else {
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
});
} catch (error) {
log(`Failed to start recorder: ${error.message}`);
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
}
StopScreencastAsync(params, invocation) {
const sender = invocation.get_sender();
const recorder = this._recorders.get(sender);
if (!recorder) {
invocation.return_value(GLib.Variant.new('(b)', [false]));
return;
}
recorder.stopRecording(() => {
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(b)', [true]));
});
}
};

View File

@ -71,7 +71,7 @@ var AuthPrompt = GObject.registerClass({
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)); this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
this._userVerifier.connect('reset', this._onReset.bind(this)); this._userVerifier.connect('reset', this._onReset.bind(this));
this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this)); this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this));
this._userVerifier.connect('credential-manager-authenticated', this._onCredentialManagerAuthenticated.bind(this)); this._userVerifier.connect('ovirt-user-authenticated', this._onOVirtUserAuthenticated.bind(this));
this.smartcardDetected = this._userVerifier.smartcardDetected; this.smartcardDetected = this._userVerifier.smartcardDetected;
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
@ -184,7 +184,7 @@ var AuthPrompt = GObject.registerClass({
}); });
this._defaultButtonWell.add_constraint(new Clutter.BindConstraint({ this._defaultButtonWell.add_constraint(new Clutter.BindConstraint({
source: this.cancelButton, source: this.cancelButton,
coordinate: Clutter.BindCoordinate.WIDTH, coordinate: Clutter.BindCoordinate.SIZE,
})); }));
this._mainBox.add_child(this._defaultButtonWell); this._mainBox.add_child(this._defaultButtonWell);
@ -242,7 +242,7 @@ var AuthPrompt = GObject.registerClass({
this.emit('prompted'); this.emit('prompted');
} }
_onCredentialManagerAuthenticated() { _onOVirtUserAuthenticated() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset(); this.reset();
} }
@ -424,13 +424,7 @@ var AuthPrompt = GObject.registerClass({
} }
updateSensitivity(sensitive) { updateSensitivity(sensitive) {
if (this._entry.reactive === sensitive)
return;
this._entry.reactive = sensitive; this._entry.reactive = sensitive;
if (sensitive)
this._entry.grab_key_focus();
} }
vfunc_hide() { vfunc_hide() {

View File

@ -1,24 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported CredentialManager */
class CredentialManager {
constructor(service) {
this._token = null;
this._service = service;
this._authenticatedSignalId = null;
}
get token() {
return this._token;
}
set token(t) {
this._token = t;
if (this._token)
this.emit('user-authenticated', this._token);
}
get service() {
return this._service;
}
}

View File

@ -589,8 +589,8 @@ var LoginDialog = GObject.registerClass({
return actorBox; return actorBox;
} }
vfunc_allocate(dialogBox) { vfunc_allocate(dialogBox, flags) {
this.set_allocation(dialogBox); this.set_allocation(dialogBox, flags);
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
dialogBox = themeNode.get_content_box(dialogBox); dialogBox = themeNode.get_content_box(dialogBox);
@ -719,19 +719,19 @@ var LoginDialog = GObject.registerClass({
// Finally hand out the allocations // Finally hand out the allocations
if (bannerAllocation) if (bannerAllocation)
this._bannerView.allocate(bannerAllocation); this._bannerView.allocate(bannerAllocation, flags);
if (authPromptAllocation) if (authPromptAllocation)
this._authPrompt.allocate(authPromptAllocation); this._authPrompt.allocate(authPromptAllocation, flags);
if (userSelectionAllocation) if (userSelectionAllocation)
this._userSelectionBox.allocate(userSelectionAllocation); this._userSelectionBox.allocate(userSelectionAllocation, flags);
if (logoAllocation) if (logoAllocation)
this._logoBin.allocate(logoAllocation); this._logoBin.allocate(logoAllocation, flags);
if (sessionMenuButtonAllocation) if (sessionMenuButtonAllocation)
this._sessionMenuButton.allocate(sessionMenuButtonAllocation); this._sessionMenuButton.allocate(sessionMenuButtonAllocation, flags);
} }
_ensureUserListLoaded() { _ensureUserListLoaded() {
@ -810,13 +810,12 @@ var LoginDialog = GObject.registerClass({
return; return;
this._logoBin.destroy_all_children(); this._logoBin.destroy_all_children();
const resourceScale = this._logoBin.get_resource_scale(); if (this._logoFile && this._logoBin.resource_scale > 0) {
if (this._logoFile) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile, this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
-1, -1, -1, -1,
scaleFactor, scaleFactor,
resourceScale)); this._logoBin.resource_scale));
} }
} }
@ -953,15 +952,16 @@ var LoginDialog = GObject.registerClass({
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING) if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
return; return;
if (this._authPrompt.verificationStatus !== AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
this._bindOpacity(); this._bindOpacity();
this.ease({ this.ease({
opacity: 255, opacity: 255,
duration: _FADE_ANIMATION_TIME, duration: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._unbindOpacity(), onComplete: () => {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
this._unbindOpacity();
},
}); });
} }

View File

@ -3,9 +3,6 @@
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Signals = imports.signals; const Signals = imports.signals;
const Credential = imports.gdm.credentialManager;
var SERVICE_NAME = 'gdm-ovirtcred';
const OVirtCredentialsIface = ` const OVirtCredentialsIface = `
<node> <node>
@ -31,14 +28,30 @@ function OVirtCredentials() {
return self; return self;
} }
var OVirtCredentialsManager = class OVirtCredentialsManager extends Credential.CredentialManager { var OVirtCredentialsManager = class {
constructor() { constructor() {
super(SERVICE_NAME); this._token = null;
this._credentials = new OVirtCredentials(); this._credentials = new OVirtCredentials();
this._credentials.connectSignal('UserAuthenticated', this._credentials.connectSignal('UserAuthenticated',
(proxy, sender, [token]) => { this._onUserAuthenticated.bind(this));
this.token = token; }
});
_onUserAuthenticated(proxy, sender, [token]) {
this._token = token;
this.emit('user-authenticated', token);
}
hasToken() {
return this._token != null;
}
getToken() {
return this._token;
}
resetToken() {
this._token = null;
} }
}; };
Signals.addSignalMethods(OVirtCredentialsManager.prototype); Signals.addSignalMethods(OVirtCredentialsManager.prototype);

View File

@ -2,29 +2,20 @@
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY, /* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */ DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
const { Clutter, Gdm, Gio, GLib } = imports.gi; const { Clutter, Gio, GLib } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint; const Fprint = imports.gdm.fingerprint;
const OVirt = imports.gdm.oVirt; const OVirt = imports.gdm.oVirt;
const Vmware = imports.gdm.vmware;
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const SmartcardManager = imports.misc.smartcardManager; const SmartcardManager = imports.misc.smartcardManager;
Gio._promisify(Gdm.Client.prototype,
'open_reauthentication_channel', 'open_reauthentication_channel_finish');
Gio._promisify(Gdm.Client.prototype,
'get_user_verifier', 'get_user_verifier_finish');
Gio._promisify(Gdm.UserVerifierProxy.prototype,
'call_begin_verification_for_user', 'call_begin_verification_for_user_finish');
Gio._promisify(Gdm.UserVerifierProxy.prototype,
'call_begin_verification', 'call_begin_verification_finish');
var PASSWORD_SERVICE_NAME = 'gdm-password'; var PASSWORD_SERVICE_NAME = 'gdm-password';
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
var OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
var FADE_ANIMATION_TIME = 160; var FADE_ANIMATION_TIME = 160;
var CLONE_FADE_ANIMATION_TIME = 250; var CLONE_FADE_ANIMATION_TIME = 250;
@ -160,20 +151,13 @@ var ShellUserVerifier = class {
this._failCounter = 0; this._failCounter = 0;
this._credentialManagers = {}; this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
this._credentialManagers[OVirt.SERVICE_NAME] = OVirt.getOVirtCredentialsManager();
this._credentialManagers[Vmware.SERVICE_NAME] = Vmware.getVmwareCredentialsManager();
for (let service in this._credentialManagers) { if (this._oVirtCredentialsManager.hasToken())
if (this._credentialManagers[service].token) { this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
this._onCredentialManagerAuthenticated(this._credentialManagers[service],
this._credentialManagers[service].token);
}
this._credentialManagers[service]._authenticatedSignalId = this._oVirtUserAuthenticatedId = this._oVirtCredentialsManager.connect('user-authenticated',
this._credentialManagers[service].connect('user-authenticated', this._oVirtUserAuthenticated.bind(this));
this._onCredentialManagerAuthenticated.bind(this));
}
} }
begin(userName, hold) { begin(userName, hold) {
@ -184,12 +168,14 @@ var ShellUserVerifier = class {
this._checkForFingerprintReader(); this._checkForFingerprintReader();
if (userName) {
// If possible, reauthenticate an already running session, // If possible, reauthenticate an already running session,
// so any session specific credentials get updated appropriately // so any session specific credentials get updated appropriately
if (userName) this._client.open_reauthentication_channel(userName, this._cancellable,
this._openReauthenticationChannel(userName); this._reauthenticationChannelOpened.bind(this));
else } else {
this._getUserVerifier(); this._client.get_user_verifier(this._cancellable, this._userVerifierGot.bind(this));
}
} }
cancel() { cancel() {
@ -229,11 +215,8 @@ var ShellUserVerifier = class {
this._smartcardManager.disconnect(this._smartcardRemovedId); this._smartcardManager.disconnect(this._smartcardRemovedId);
this._smartcardManager = null; this._smartcardManager = null;
for (let service in this._credentialManagers) { this._oVirtCredentialsManager.disconnect(this._oVirtUserAuthenticatedId);
let credentialManager = this._credentialManagers[service]; this._oVirtCredentialsManager = null;
credentialManager.disconnect(credentialManager._authenticatedSignalId);
credentialManager = null;
}
} }
answerQuery(serviceName, answer) { answerQuery(serviceName, answer) {
@ -321,9 +304,9 @@ var ShellUserVerifier = class {
}); });
} }
_onCredentialManagerAuthenticated(credentialManager, _token) { _oVirtUserAuthenticated(_token) {
this._preemptingService = credentialManager.service; this._preemptingService = OVIRT_SERVICE_NAME;
this.emit('credential-manager-authenticated'); this.emit('ovirt-user-authenticated');
} }
_checkForSmartcard() { _checkForSmartcard() {
@ -356,11 +339,10 @@ var ShellUserVerifier = class {
this._verificationFailed(false); this._verificationFailed(false);
} }
async _openReauthenticationChannel(userName) { _reauthenticationChannelOpened(client, result) {
try { try {
this._clearUserVerifier(); this._clearUserVerifier();
this._userVerifier = await this._client.open_reauthentication_channel( this._userVerifier = client.open_reauthentication_channel_finish(result);
userName, this._cancellable);
} catch (e) { } catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
@ -369,7 +351,8 @@ var ShellUserVerifier = class {
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there
// is no session to reauthenticate. Fall back to performing // is no session to reauthenticate. Fall back to performing
// verification from this login session // verification from this login session
this._getUserVerifier(); client.get_user_verifier(this._cancellable,
this._userVerifierGot.bind(this));
return; return;
} }
@ -383,11 +366,10 @@ var ShellUserVerifier = class {
this._hold.release(); this._hold.release();
} }
async _getUserVerifier() { _userVerifierGot(client, result) {
try { try {
this._clearUserVerifier(); this._clearUserVerifier();
this._userVerifier = this._userVerifier = client.get_user_verifier_finish(result);
await this._client.get_user_verifier(this._cancellable);
} catch (e) { } catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
@ -439,25 +421,35 @@ var ShellUserVerifier = class {
} }
} }
async _startService(serviceName) { _startService(serviceName) {
this._hold.acquire(); this._hold.acquire();
try {
if (this._userName) { if (this._userName) {
await this._userVerifier.call_begin_verification_for_user( this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => {
serviceName, this._userName, this._cancellable); try {
} else { obj.call_begin_verification_for_user_finish(result);
await this._userVerifier.call_begin_verification(
serviceName, this._cancellable);
}
} catch (e) { } catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
this._reportInitError(this._userName this._reportInitError('Failed to start verification for user', e);
? 'Failed to start verification for user'
: 'Failed to start verification', e);
return; return;
} }
this._hold.release(); this._hold.release();
});
} else {
this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => {
try {
obj.call_begin_verification_finish(result);
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
this._reportInitError('Failed to start verification', e);
return;
}
this._hold.release();
});
}
} }
_beginVerification() { _beginVerification() {
@ -500,12 +492,9 @@ var ShellUserVerifier = class {
if (!this.serviceIsForeground(serviceName)) if (!this.serviceIsForeground(serviceName))
return; return;
let token = null; if (serviceName == OVIRT_SERVICE_NAME) {
if (this._credentialManagers[serviceName]) // The only question asked by this service is "Token?"
token = this._credentialManagers[serviceName].token; this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken());
if (token) {
this.answerQuery(serviceName, token);
return; return;
} }
@ -573,10 +562,8 @@ var ShellUserVerifier = class {
// If the login failed with the preauthenticated oVirt credentials // If the login failed with the preauthenticated oVirt credentials
// then discard the credentials and revert to default authentication // then discard the credentials and revert to default authentication
// mechanism. // mechanism.
let foregroundService = Object.keys(this._credentialManagers).find(service => if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) {
this.serviceIsForeground(service)); this._oVirtCredentialsManager.resetToken();
if (foregroundService) {
this._credentialManagers[foregroundService].token = null;
this._preemptingService = null; this._preemptingService = null;
this._verificationFailed(false); this._verificationFailed(false);
return; return;

View File

@ -1,54 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getVmwareCredentialsManager */
const Gio = imports.gi.Gio;
const Signals = imports.signals;
const Credential = imports.gdm.credentialManager;
const dbusPath = '/org/vmware/viewagent/Credentials';
const dbusInterface = 'org.vmware.viewagent.Credentials';
var SERVICE_NAME = 'gdm-vmwcred';
const VmwareCredentialsIface = '<node> \
<interface name="' + dbusInterface + '"> \
<signal name="UserAuthenticated"> \
<arg type="s" name="token"/> \
</signal> \
</interface> \
</node>';
const VmwareCredentialsInfo = Gio.DBusInterfaceInfo.new_for_xml(VmwareCredentialsIface);
let _vmwareCredentialsManager = null;
function VmwareCredentials() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
g_interface_name: VmwareCredentialsInfo.name,
g_interface_info: VmwareCredentialsInfo,
g_name: dbusInterface,
g_object_path: dbusPath,
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
self.init(null);
return self;
}
var VmwareCredentialsManager = class VmwareCredentialsManager extends Credential.CredentialManager {
constructor() {
super(SERVICE_NAME);
this._credentials = new VmwareCredentials();
this._credentials.connectSignal('UserAuthenticated',
(proxy, sender, [token]) => {
this.token = token;
});
}
};
Signals.addSignalMethods(VmwareCredentialsManager.prototype);
function getVmwareCredentialsManager() {
if (!_vmwareCredentialsManager)
_vmwareCredentialsManager = new VmwareCredentialsManager();
return _vmwareCredentialsManager;
}

View File

@ -6,8 +6,6 @@
<file>gdm/fingerprint.js</file> <file>gdm/fingerprint.js</file>
<file>gdm/loginDialog.js</file> <file>gdm/loginDialog.js</file>
<file>gdm/oVirt.js</file> <file>gdm/oVirt.js</file>
<file>gdm/credentialManager.js</file>
<file>gdm/vmware.js</file>
<file>gdm/realmd.js</file> <file>gdm/realmd.js</file>
<file>gdm/util.js</file> <file>gdm/util.js</file>
@ -25,14 +23,12 @@
<file>misc/modemManager.js</file> <file>misc/modemManager.js</file>
<file>misc/objectManager.js</file> <file>misc/objectManager.js</file>
<file>misc/params.js</file> <file>misc/params.js</file>
<file>misc/parentalControlsManager.js</file>
<file>misc/permissionStore.js</file> <file>misc/permissionStore.js</file>
<file>misc/smartcardManager.js</file> <file>misc/smartcardManager.js</file>
<file>misc/systemActions.js</file> <file>misc/systemActions.js</file>
<file>misc/util.js</file> <file>misc/util.js</file>
<file>misc/weather.js</file> <file>misc/weather.js</file>
<file>perf/basic.js</file>
<file>perf/core.js</file> <file>perf/core.js</file>
<file>perf/hwtest.js</file> <file>perf/hwtest.js</file>
@ -93,6 +89,7 @@
<file>ui/ripples.js</file> <file>ui/ripples.js</file>
<file>ui/runDialog.js</file> <file>ui/runDialog.js</file>
<file>ui/screenShield.js</file> <file>ui/screenShield.js</file>
<file>ui/screencast.js</file>
<file>ui/screenshot.js</file> <file>ui/screenshot.js</file>
<file>ui/scripting.js</file> <file>ui/scripting.js</file>
<file>ui/search.js</file> <file>ui/search.js</file>
@ -104,13 +101,13 @@
<file>ui/swipeTracker.js</file> <file>ui/swipeTracker.js</file>
<file>ui/switcherPopup.js</file> <file>ui/switcherPopup.js</file>
<file>ui/switchMonitor.js</file> <file>ui/switchMonitor.js</file>
<file>ui/tweener.js</file>
<file>ui/unlockDialog.js</file> <file>ui/unlockDialog.js</file>
<file>ui/userWidget.js</file> <file>ui/userWidget.js</file>
<file>ui/viewSelector.js</file> <file>ui/viewSelector.js</file>
<file>ui/windowAttentionHandler.js</file> <file>ui/windowAttentionHandler.js</file>
<file>ui/windowMenu.js</file> <file>ui/windowMenu.js</file>
<file>ui/windowManager.js</file> <file>ui/windowManager.js</file>
<file>ui/windowPreview.js</file>
<file>ui/workspace.js</file> <file>ui/workspace.js</file>
<file>ui/workspaceSwitcherPopup.js</file> <file>ui/workspaceSwitcherPopup.js</file>
<file>ui/workspaceThumbnail.js</file> <file>ui/workspaceThumbnail.js</file>
@ -137,6 +134,7 @@
<file>ui/status/volume.js</file> <file>ui/status/volume.js</file>
<file>ui/status/bluetooth.js</file> <file>ui/status/bluetooth.js</file>
<file>ui/status/remoteAccess.js</file> <file>ui/status/remoteAccess.js</file>
<file>ui/status/screencast.js</file>
<file>ui/status/system.js</file> <file>ui/status/system.js</file>
<file>ui/status/thunderbolt.js</file> <file>ui/status/thunderbolt.js</file>
</gresource> </gresource>

View File

@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported collectFromDatadirs, recursivelyDeleteDir, /* exported collectFromDatadirs, recursivelyDeleteDir,
recursivelyMoveDir, loadInterfaceXML, loadSubInterfaceXML */ recursivelyMoveDir, loadInterfaceXML */
const { Gio, GLib } = imports.gi; const { Gio, GLib } = imports.gi;
const Config = imports.misc.config; const Config = imports.misc.config;
@ -67,19 +67,14 @@ function recursivelyMoveDir(srcDir, destDir) {
} }
let _ifaceResource = null; let _ifaceResource = null;
function ensureIfaceResource() { function loadInterfaceXML(iface) {
if (_ifaceResource) if (!_ifaceResource) {
return;
// don't use global.datadir so the method is usable from tests/tools // don't use global.datadir so the method is usable from tests/tools
let dir = GLib.getenv('GNOME_SHELL_DATADIR') || Config.PKGDATADIR; let dir = GLib.getenv('GNOME_SHELL_DATADIR') || Config.PKGDATADIR;
let path = `${dir}/gnome-shell-dbus-interfaces.gresource`; let path = `${dir}/gnome-shell-dbus-interfaces.gresource`;
_ifaceResource = Gio.Resource.load(path); _ifaceResource = Gio.Resource.load(path);
_ifaceResource._register(); _ifaceResource._register();
} }
function loadInterfaceXML(iface) {
ensureIfaceResource();
let uri = `resource:///org/gnome/shell/dbus-interfaces/${iface}.xml`; let uri = `resource:///org/gnome/shell/dbus-interfaces/${iface}.xml`;
let f = Gio.File.new_for_uri(uri); let f = Gio.File.new_for_uri(uri);
@ -93,25 +88,3 @@ function loadInterfaceXML(iface) {
return null; return null;
} }
function loadSubInterfaceXML(iface, ifaceFile) {
let xml = loadInterfaceXML(ifaceFile);
if (!xml)
return null;
let ifaceStartTag = `<interface name="${iface}">`;
let ifaceStopTag = '</interface>';
let ifaceStartIndex = xml.indexOf(ifaceStartTag);
let ifaceEndIndex = xml.indexOf(ifaceStopTag, ifaceStartIndex + 1) + ifaceStopTag.length;
let xmlHeader = '<!DOCTYPE node PUBLIC\n' +
'\'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\'\n' +
'\'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\'>\n' +
'<node>\n';
let xmlFooter = '</node>';
return (
xmlHeader +
xml.substr(ifaceStartIndex, ifaceEndIndex - ifaceStartIndex) +
xmlFooter);
}

View File

@ -6,15 +6,6 @@ const Signals = imports.signals;
const IBusCandidatePopup = imports.ui.ibusCandidatePopup; const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
Gio._promisify(IBus.Bus.prototype,
'list_engines_async', 'list_engines_async_finish');
Gio._promisify(IBus.Bus.prototype,
'request_name_async', 'request_name_async_finish');
Gio._promisify(IBus.Bus.prototype,
'get_global_engine_async', 'get_global_engine_async_finish');
Gio._promisify(IBus.Bus.prototype,
'set_global_engine_async', 'set_global_engine_async_finish');
// Ensure runtime version matches // Ensure runtime version matches
_checkIBusVersion(1, 5, 2); _checkIBusVersion(1, 5, 2);
@ -111,14 +102,16 @@ var IBusManager = class {
_onConnected() { _onConnected() {
this._cancellable = new Gio.Cancellable(); this._cancellable = new Gio.Cancellable();
this._initEngines(); this._ibus.list_engines_async(-1, this._cancellable,
this._initPanelService(); this._initEngines.bind(this));
this._ibus.request_name_async(IBus.SERVICE_PANEL,
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable,
this._initPanelService.bind(this));
} }
async _initEngines() { _initEngines(ibus, result) {
try { try {
const enginesList = let enginesList = this._ibus.list_engines_async_finish(result);
await this._ibus.list_engines_async(-1, this._cancellable);
for (let i = 0; i < enginesList.length; ++i) { for (let i = 0; i < enginesList.length; ++i) {
let name = enginesList[i].get_name(); let name = enginesList[i].get_name();
this._engines.set(name, enginesList[i]); this._engines.set(name, enginesList[i]);
@ -133,10 +126,9 @@ var IBusManager = class {
} }
} }
async _initPanelService() { _initPanelService(ibus, result) {
try { try {
await this._ibus.request_name_async(IBus.SERVICE_PANEL, this._ibus.request_name_async_finish(result);
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable);
} catch (e) { } catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
logError(e); logError(e);
@ -171,15 +163,19 @@ var IBusManager = class {
this._panelService.connect('set-content-type', this._setContentType.bind(this)); this._panelService.connect('set-content-type', this._setContentType.bind(this));
} catch (e) { } catch (e) {
} }
this._updateReadiness();
try {
// If an engine is already active we need to get its properties // If an engine is already active we need to get its properties
const engine = this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, res) => {
await this._ibus.get_global_engine_async(-1, this._cancellable); let engine;
this._engineChanged(this._ibus, engine.get_name()); try {
engine = this._ibus.get_global_engine_async_finish(res);
if (!engine)
return;
} catch (e) { } catch (e) {
return;
} }
this._engineChanged(this._ibus, engine.get_name());
});
this._updateReadiness();
} }
_updateReadiness() { _updateReadiness() {
@ -227,7 +223,7 @@ var IBusManager = class {
return this._engines.get(id); return this._engines.get(id);
} }
async setEngine(id, callback) { setEngine(id, callback) {
// Send id even if id == this._currentEngineName // Send id even if id == this._currentEngineName
// because 'properties-registered' signal can be emitted // because 'properties-registered' signal can be emitted
// while this._ibusSources == null on a lock screen. // while this._ibusSources == null on a lock screen.
@ -237,16 +233,18 @@ var IBusManager = class {
return; return;
} }
try { this._ibus.set_global_engine_async(id,
await this._ibus.set_global_engine_async(id,
this._MAX_INPUT_SOURCE_ACTIVATION_TIME, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
this._cancellable); this._cancellable, (_bus, res) => {
try {
this._ibus.set_global_engine_async_finish(res);
} catch (e) { } catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
logError(e); logError(e);
} }
if (callback) if (callback)
callback(); callback();
});
} }
preloadEngines(ids) { preloadEngines(ids) {

View File

@ -4,9 +4,6 @@ const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
const Keyboard = imports.ui.status.keyboard; const Keyboard = imports.ui.status.keyboard;
Gio._promisify(IBus.Bus.prototype,
'create_input_context_async', 'create_input_context_async_finish');
var HIDE_PANEL_TIME = 50; var HIDE_PANEL_TIME = 50;
var InputMethod = GObject.registerClass( var InputMethod = GObject.registerClass(
@ -49,11 +46,15 @@ class InputMethod extends Clutter.InputMethod {
this._currentSource = this._inputSourceManager.currentSource; this._currentSource = this._inputSourceManager.currentSource;
} }
async _onConnected() { _onConnected() {
this._cancellable = new Gio.Cancellable(); this._cancellable = new Gio.Cancellable();
this._ibus.create_input_context_async('gnome-shell', -1,
this._cancellable, this._setContext.bind(this));
}
_setContext(bus, res) {
try { try {
this._context = await this._ibus.create_input_context_async( this._context = this._ibus.create_input_context_async_finish(res);
'gnome-shell', -1, this._cancellable);
} catch (e) { } catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
logError(e); logError(e);

View File

@ -3,9 +3,9 @@ const { Gio, GLib, Meta, Shell, St } = imports.gi;
const INTROSPECT_SCHEMA = 'org.gnome.shell'; const INTROSPECT_SCHEMA = 'org.gnome.shell';
const INTROSPECT_KEY = 'introspect'; const INTROSPECT_KEY = 'introspect';
const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk']; const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk'];
const INTROSPECT_DBUS_API_VERSION = 3; const INTROSPECT_DBUS_API_VERSION = 2;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
@ -46,24 +46,19 @@ var IntrospectService = class {
this._syncRunningApplications(); this._syncRunningApplications();
this._allowlistMap = new Map(); this._whitelistMap = new Map();
APP_ALLOWLIST.forEach(appName => { APP_WHITELIST.forEach(appName => {
Gio.DBus.watch_name(Gio.BusType.SESSION, Gio.DBus.watch_name(Gio.BusType.SESSION,
appName, appName,
Gio.BusNameWatcherFlags.NONE, Gio.BusNameWatcherFlags.NONE,
(conn, name, owner) => this._allowlistMap.set(name, owner), (conn, name, owner) => this._whitelistMap.set(name, owner),
(conn, name) => this._allowlistMap.delete(name)); (conn, name) => this._whitelistMap.delete(name));
}); });
this._settings = St.Settings.get(); this._settings = St.Settings.get();
this._settings.connect('notify::enable-animations', this._settings.connect('notify::enable-animations',
this._syncAnimationsEnabled.bind(this)); this._syncAnimationsEnabled.bind(this));
this._syncAnimationsEnabled(); this._syncAnimationsEnabled();
const monitorManager = Meta.MonitorManager.get();
monitorManager.connect('monitors-changed',
this._syncScreenSize.bind(this));
this._syncScreenSize();
} }
_isStandaloneApp(app) { _isStandaloneApp(app) {
@ -74,8 +69,8 @@ var IntrospectService = class {
return this._introspectSettings.get_boolean(INTROSPECT_KEY); return this._introspectSettings.get_boolean(INTROSPECT_KEY);
} }
_isSenderAllowed(sender) { _isSenderWhitelisted(sender) {
return [...this._allowlistMap.values()].includes(sender); return [...this._whitelistMap.values()].includes(sender);
} }
_getSandboxedAppId(app) { _getSandboxedAppId(app) {
@ -138,7 +133,7 @@ var IntrospectService = class {
if (this._isIntrospectEnabled()) if (this._isIntrospectEnabled())
return true; return true;
if (this._isSenderAllowed(invocation.get_sender())) if (this._isSenderWhitelisted(invocation.get_sender()))
return true; return true;
return false; return false;
@ -214,28 +209,10 @@ var IntrospectService = class {
} }
} }
_syncScreenSize() {
const oldScreenWidth = this._screenWidth;
const oldScreenHeight = this._screenHeight;
this._screenWidth = global.screen_width;
this._screenHeight = global.screen_height;
if (oldScreenWidth !== this._screenWidth ||
oldScreenHeight !== this._screenHeight) {
const variant = new GLib.Variant('(ii)',
[this._screenWidth, this._screenHeight]);
this._dbusImpl.emit_property_changed('ScreenSize', variant);
}
}
get AnimationsEnabled() { get AnimationsEnabled() {
return this._animationsEnabled; return this._animationsEnabled;
} }
get ScreenSize() {
return [this._screenWidth, this._screenHeight];
}
get version() { get version() {
return INTROSPECT_DBUS_API_VERSION; return INTROSPECT_DBUS_API_VERSION;
} }

View File

@ -24,7 +24,8 @@ function getCompletions(text, commandHeader, globalCompletionList) {
[expr_, base, attrHead] = matches; [expr_, base, attrHead] = matches;
methods = getPropertyNamesFromExpression(base, commandHeader).filter( methods = getPropertyNamesFromExpression(base, commandHeader).filter(
attr => attr.slice(0, attrHead.length) === attrHead); attr => attr.slice(0, attrHead.length) == attrHead
);
} }
// Look for the empty expression or partially entered words // Look for the empty expression or partially entered words
@ -33,7 +34,8 @@ function getCompletions(text, commandHeader, globalCompletionList) {
if (text == '' || matches) { if (text == '' || matches) {
[expr_, attrHead] = matches; [expr_, attrHead] = matches;
methods = globalCompletionList.filter( methods = globalCompletionList.filter(
attr => attr.slice(0, attrHead.length) === attrHead); attr => attr.slice(0, attrHead.length) == attrHead
);
} }
} }

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */ /* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
const { GLib, GnomeDesktop } = imports.gi; const { GLib, GnomeDesktop, Meta } = imports.gi;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -62,11 +62,11 @@ var KeyboardManager = class {
return; return;
this._currentKeymap = { layouts, variants, options }; this._currentKeymap = { layouts, variants, options };
global.backend.set_keymap(layouts, variants, options); Meta.get_backend().set_keymap(layouts, variants, options);
} }
_applyLayoutGroupIndex(idx) { _applyLayoutGroupIndex(idx) {
global.backend.lock_layout_group(idx); Meta.get_backend().lock_layout_group(idx);
} }
apply(id) { apply(id) {

View File

@ -50,22 +50,25 @@ function canLock() {
} }
async function registerSessionWithGDM() { function registerSessionWithGDM() {
log("Registering session with GDM"); log("Registering session with GDM");
try { Gio.DBus.system.call('org.gnome.DisplayManager',
await Gio.DBus.system.call(
'org.gnome.DisplayManager',
'/org/gnome/DisplayManager/Manager', '/org/gnome/DisplayManager/Manager',
'org.gnome.DisplayManager.Manager', 'org.gnome.DisplayManager.Manager',
'RegisterSession', 'RegisterSession',
GLib.Variant.new('(a{sv})', [{}]), null, GLib.Variant.new('(a{sv})', [{}]), null,
Gio.DBusCallFlags.NONE, -1, null); Gio.DBusCallFlags.NONE, -1, null,
(source, result) => {
try {
source.call_finish(result);
} catch (e) { } catch (e) {
if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD)) if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
log(`Error registering session with GDM: ${e.message}`); log(`Error registering session with GDM: ${e.message}`);
else else
log('Not calling RegisterSession(): method not exported, GDM too old?'); log("Not calling RegisterSession(): method not exported, GDM too old?");
} }
}
);
} }
let _loginManager = null; let _loginManager = null;
@ -158,23 +161,6 @@ var LoginManagerSystemd = class {
}); });
} }
canRebootToBootLoaderMenu(asyncCallback) {
this._proxy.CanRebootToBootLoaderMenuRemote((result, error) => {
if (error) {
asyncCallback(false, false);
} else {
const needsAuth = result[0] === 'challenge';
const canRebootToBootLoaderMenu = needsAuth || result[0] === 'yes';
asyncCallback(canRebootToBootLoaderMenu, needsAuth);
}
});
}
setRebootToBootLoaderMenu() {
/* Parameter is timeout in usec, show to menu for 60 seconds */
this._proxy.SetRebootToBootLoaderMenuRemote(60000000);
}
listSessions(asyncCallback) { listSessions(asyncCallback) {
this._proxy.ListSessionsRemote((result, error) => { this._proxy.ListSessionsRemote((result, error) => {
if (error) if (error)
@ -188,19 +174,24 @@ var LoginManagerSystemd = class {
this._proxy.SuspendRemote(true); this._proxy.SuspendRemote(true);
} }
async inhibit(reason, callback) { inhibit(reason, callback) {
let inVariant = GLib.Variant.new('(ssss)',
['sleep',
'GNOME Shell',
reason,
'delay']);
this._proxy.call_with_unix_fd_list('Inhibit', inVariant, 0, -1, null, null,
(proxy, result) => {
let fd = -1;
try { try {
const inVariant = new GLib.Variant('(ssss)', let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result);
['sleep', 'GNOME Shell', reason, 'delay']); fd = fdList.steal_fds()[0];
const [outVariant_, fdList] =
await this._proxy.call_with_unix_fd_list('Inhibit',
inVariant, 0, -1, null, null);
const [fd] = fdList.steal_fds();
callback(new Gio.UnixInputStream({ fd })); callback(new Gio.UnixInputStream({ fd }));
} catch (e) { } catch (e) {
logError(e, 'Error getting systemd inhibitor'); logError(e, "Error getting systemd inhibitor");
callback(null); callback(null);
} }
});
} }
_prepareForSleep(proxy, sender, [aboutToSuspend]) { _prepareForSleep(proxy, sender, [aboutToSuspend]) {
@ -220,13 +211,6 @@ var LoginManagerDummy = class {
asyncCallback(false, false); asyncCallback(false, false);
} }
canRebootToBootLoaderMenu(asyncCallback) {
asyncCallback(false, false);
}
setRebootToBootLoaderMenu() {
}
listSessions(asyncCallback) { listSessions(asyncCallback) {
asyncCallback([]); asyncCallback([]);
} }

View File

@ -57,7 +57,9 @@ var ObjectManager = class {
// Start out inhibiting load until at least the proxy // Start out inhibiting load until at least the proxy
// manager is loaded and the remote objects are fetched // manager is loaded and the remote objects are fetched
this._numLoadInhibitors = 1; this._numLoadInhibitors = 1;
this._initManagerProxy(); this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
this._cancellable,
this._onManagerProxyLoaded.bind(this));
} }
_tryToCompleteLoad() { _tryToCompleteLoad() {
@ -71,7 +73,7 @@ var ObjectManager = class {
} }
} }
async _addInterface(objectPath, interfaceName, onFinished) { _addInterface(objectPath, interfaceName, onFinished) {
let info = this._interfaceInfos[interfaceName]; let info = this._interfaceInfos[interfaceName];
if (!info) { if (!info) {
@ -87,8 +89,9 @@ var ObjectManager = class {
g_interface_info: info, g_interface_info: info,
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START }); g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => {
try { try {
await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable); initable.init_finish(result);
} catch (e) { } catch (e) {
logError(e, `could not initialize proxy for interface ${interfaceName}`); logError(e, `could not initialize proxy for interface ${interfaceName}`);
@ -119,6 +122,7 @@ var ObjectManager = class {
if (onFinished) if (onFinished)
onFinished(); onFinished();
});
} }
_removeInterface(objectPath, interfaceName) { _removeInterface(objectPath, interfaceName) {
@ -147,10 +151,9 @@ var ObjectManager = class {
} }
} }
async _initManagerProxy() { _onManagerProxyLoaded(initable, result) {
try { try {
await this._managerProxy.init_async( initable.init_finish(result);
GLib.PRIORITY_DEFAULT, this._cancellable);
} catch (e) { } catch (e) {
logError(e, `could not initialize object manager for object ${this._serviceName}`); logError(e, `could not initialize object manager for object ${this._serviceName}`);

View File

@ -1,146 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
//
// Copyright (C) 2018, 2019, 2020 Endless Mobile, Inc.
//
// This is a GNOME Shell component to wrap the interactions over
// D-Bus with the malcontent library.
//
// Licensed under the GNU General Public License Version 2
//
// 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
// of the License, 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/* exported getDefault */
const { Gio, GObject, Shell } = imports.gi;
// We require libmalcontent ≥ 0.6.0
const HAVE_MALCONTENT = imports.package.checkSymbol(
'Malcontent', '0', 'ManagerGetValueFlags');
var Malcontent = null;
if (HAVE_MALCONTENT) {
Malcontent = imports.gi.Malcontent;
Gio._promisify(Malcontent.Manager.prototype, 'get_app_filter_async', 'get_app_filter_finish');
}
let _singleton = null;
function getDefault() {
if (_singleton === null)
_singleton = new ParentalControlsManager();
return _singleton;
}
// A manager class which provides cached access to the constructing users
// parental controls settings. Its possible for the users parental controls
// to change at runtime if the Parental Controls application is used by an
// administrator from within the users session.
var ParentalControlsManager = GObject.registerClass({
Signals: {
'app-filter-changed': {},
},
}, class ParentalControlsManager extends GObject.Object {
_init() {
super._init();
this._initialized = false;
this._disabled = false;
this._appFilter = null;
this._initializeManager();
}
async _initializeManager() {
if (!HAVE_MALCONTENT) {
log('Skipping parental controls support as its disabled');
this._initialized = true;
this.emit('app-filter-changed');
return;
}
log(`Getting parental controls for user ${Shell.util_get_uid()}`);
try {
const connection = await Gio.DBus.get(Gio.BusType.SYSTEM, null);
this._manager = new Malcontent.Manager({ connection });
this._appFilter = await this._manager.get_app_filter_async(
Shell.util_get_uid(),
Malcontent.ManagerGetValueFlags.NONE,
null);
} catch (e) {
if (e.matches(Malcontent.ManagerError, Malcontent.ManagerError.DISABLED)) {
log('Parental controls globally disabled');
this._disabled = true;
} else {
logError(e, 'Failed to get parental controls settings');
return;
}
}
this._manager.connect('app-filter-changed', this._onAppFilterChanged.bind(this));
// Signal initialisation is complete.
this._initialized = true;
this.emit('app-filter-changed');
}
async _onAppFilterChanged(manager, uid) {
// Emit 'changed' signal only if app-filter is changed for currently logged-in user.
let currentUid = Shell.util_get_uid();
if (currentUid !== uid)
return;
try {
this._appFilter = await this._manager.get_app_filter_async(
currentUid,
Malcontent.ManagerGetValueFlags.NONE,
null);
this.emit('app-filter-changed');
} catch (e) {
// Log an error and keep the old app filter.
logError(e, `Failed to get new MctAppFilter for uid ${Shell.util_get_uid()} on app-filter-changed`);
}
}
get initialized() {
return this._initialized;
}
// Calculate whether the given app (a Gio.DesktopAppInfo) should be shown
// on the desktop, in search results, etc. The app should be shown if:
// - The .desktop file doesnt say it should be hidden.
// - The executable from the .desktop files Exec line isnt denied in
// the users parental controls.
// - None of the flatpak app IDs from the X-Flatpak and the
// X-Flatpak-RenamedFrom lines are denied in the users parental
// controls.
shouldShowApp(appInfo) {
// Quick decision?
if (!appInfo.should_show())
return false;
// Are parental controls enabled (at configure time or runtime)?
if (!HAVE_MALCONTENT || this._disabled)
return true;
// Have we finished initialising yet?
if (!this.initialized) {
log(`Warning: Hiding app because parental controls not yet initialised: ${appInfo.get_id()}`);
return false;
}
return this._appFilter.is_appinfo_allowed(appInfo);
}
});

View File

@ -21,7 +21,6 @@ const SENSOR_OBJECT_PATH = '/net/hadess/SensorProxy';
const SensorProxyInterface = loadInterfaceXML('net.hadess.SensorProxy'); const SensorProxyInterface = loadInterfaceXML('net.hadess.SensorProxy');
const POWER_OFF_ACTION_ID = 'power-off'; const POWER_OFF_ACTION_ID = 'power-off';
const RESTART_ACTION_ID = 'restart';
const LOCK_SCREEN_ACTION_ID = 'lock-screen'; const LOCK_SCREEN_ACTION_ID = 'lock-screen';
const LOGOUT_ACTION_ID = 'logout'; const LOGOUT_ACTION_ID = 'logout';
const SUSPEND_ACTION_ID = 'suspend'; const SUSPEND_ACTION_ID = 'suspend';
@ -41,36 +40,39 @@ function getDefault() {
const SystemActions = GObject.registerClass({ const SystemActions = GObject.registerClass({
Properties: { Properties: {
'can-power-off': GObject.ParamSpec.boolean( 'can-power-off': GObject.ParamSpec.boolean('can-power-off',
'can-power-off', 'can-power-off', 'can-power-off', 'can-power-off',
'can-power-off',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-restart': GObject.ParamSpec.boolean( 'can-suspend': GObject.ParamSpec.boolean('can-suspend',
'can-restart', 'can-restart', 'can-restart', 'can-suspend',
'can-suspend',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-suspend': GObject.ParamSpec.boolean( 'can-lock-screen': GObject.ParamSpec.boolean('can-lock-screen',
'can-suspend', 'can-suspend', 'can-suspend', 'can-lock-screen',
'can-lock-screen',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-lock-screen': GObject.ParamSpec.boolean( 'can-switch-user': GObject.ParamSpec.boolean('can-switch-user',
'can-lock-screen', 'can-lock-screen', 'can-lock-screen', 'can-switch-user',
'can-switch-user',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-switch-user': GObject.ParamSpec.boolean( 'can-logout': GObject.ParamSpec.boolean('can-logout',
'can-switch-user', 'can-switch-user', 'can-switch-user', 'can-logout',
'can-logout',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-logout': GObject.ParamSpec.boolean( 'can-lock-orientation': GObject.ParamSpec.boolean('can-lock-orientation',
'can-logout', 'can-logout', 'can-logout', 'can-lock-orientation',
'can-lock-orientation',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-lock-orientation': GObject.ParamSpec.boolean( 'orientation-lock-icon': GObject.ParamSpec.string('orientation-lock-icon',
'can-lock-orientation', 'can-lock-orientation', 'can-lock-orientation', 'orientation-lock-icon',
GObject.ParamFlags.READABLE, 'orientation-lock-icon',
false),
'orientation-lock-icon': GObject.ParamSpec.string(
'orientation-lock-icon', 'orientation-lock-icon', 'orientation-lock-icon',
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
null), null),
}, },
@ -81,25 +83,13 @@ const SystemActions = GObject.registerClass({
this._canHavePowerOff = true; this._canHavePowerOff = true;
this._canHaveSuspend = true; this._canHaveSuspend = true;
function tokenizeKeywords(keywords) {
return keywords.split(';').map(keyword => GLib.str_tokenize_and_fold(keyword, null)).flat(2);
}
this._actions = new Map(); this._actions = new Map();
this._actions.set(POWER_OFF_ACTION_ID, { this._actions.set(POWER_OFF_ACTION_ID, {
// Translators: The name of the power-off action in search // Translators: The name of the power-off action in search
name: C_("search-result", "Power Off"), name: C_("search-result", "Power Off"),
iconName: 'system-shutdown-symbolic', iconName: 'system-shutdown-symbolic',
// Translators: A list of keywords that match the power-off action, separated by semicolons // Translators: A list of keywords that match the power-off action, separated by semicolons
keywords: tokenizeKeywords(_('power off;shutdown;halt;stop')), keywords: _('power off;shutdown;reboot;restart;halt;stop').split(/[; ]/),
available: false,
});
this._actions.set(RESTART_ACTION_ID, {
// Translators: The name of the restart action in search
name: C_('search-result', 'Restart'),
iconName: 'system-reboot-symbolic',
// Translators: A list of keywords that match the restart action, separated by semicolons
keywords: tokenizeKeywords(_('reboot;restart;')),
available: false, available: false,
}); });
this._actions.set(LOCK_SCREEN_ACTION_ID, { this._actions.set(LOCK_SCREEN_ACTION_ID, {
@ -107,15 +97,15 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Lock Screen"), name: C_("search-result", "Lock Screen"),
iconName: 'system-lock-screen-symbolic', iconName: 'system-lock-screen-symbolic',
// Translators: A list of keywords that match the lock screen action, separated by semicolons // Translators: A list of keywords that match the lock screen action, separated by semicolons
keywords: tokenizeKeywords(_('lock screen')), keywords: _("lock screen").split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(LOGOUT_ACTION_ID, { this._actions.set(LOGOUT_ACTION_ID, {
// Translators: The name of the logout action in search // Translators: The name of the logout action in search
name: C_("search-result", "Log Out"), name: C_("search-result", "Log Out"),
iconName: 'system-log-out-symbolic', iconName: 'application-exit-symbolic',
// Translators: A list of keywords that match the logout action, separated by semicolons // Translators: A list of keywords that match the logout action, separated by semicolons
keywords: tokenizeKeywords(_('logout;log out;sign off')), keywords: _("logout;log out;sign off").split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(SUSPEND_ACTION_ID, { this._actions.set(SUSPEND_ACTION_ID, {
@ -123,7 +113,7 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Suspend"), name: C_("search-result", "Suspend"),
iconName: 'media-playback-pause-symbolic', iconName: 'media-playback-pause-symbolic',
// Translators: A list of keywords that match the suspend action, separated by semicolons // Translators: A list of keywords that match the suspend action, separated by semicolons
keywords: tokenizeKeywords(_('suspend;sleep')), keywords: _("suspend;sleep").split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(SWITCH_USER_ACTION_ID, { this._actions.set(SWITCH_USER_ACTION_ID, {
@ -131,14 +121,14 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Switch User"), name: C_("search-result", "Switch User"),
iconName: 'system-switch-user-symbolic', iconName: 'system-switch-user-symbolic',
// Translators: A list of keywords that match the switch user action, separated by semicolons // Translators: A list of keywords that match the switch user action, separated by semicolons
keywords: tokenizeKeywords(_('switch user')), keywords: _("switch user").split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(LOCK_ORIENTATION_ACTION_ID, { this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
name: '', name: '',
iconName: '', iconName: '',
// Translators: A list of keywords that match the lock orientation action, separated by semicolons // Translators: A list of keywords that match the lock orientation action, separated by semicolons
keywords: tokenizeKeywords(_('lock orientation;unlock orientation;screen;rotation')), keywords: _("lock orientation;unlock orientation;screen;rotation").split(/[; ]/),
available: false, available: false,
}); });
@ -209,11 +199,6 @@ const SystemActions = GObject.registerClass({
return this._actions.get(POWER_OFF_ACTION_ID).available; return this._actions.get(POWER_OFF_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_restart() {
return this._actions.get(RESTART_ACTION_ID).available;
}
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
get can_suspend() { get can_suspend() {
return this._actions.get(SUSPEND_ACTION_ID).available; return this._actions.get(SUSPEND_ACTION_ID).available;
@ -292,7 +277,7 @@ const SystemActions = GObject.registerClass({
getMatchingActions(terms) { getMatchingActions(terms) {
// terms is a list of strings // terms is a list of strings
terms = terms.map(term => GLib.str_tokenize_and_fold(term, null)[0]); terms = terms.map(term => term.toLowerCase());
let results = []; let results = [];
@ -317,9 +302,6 @@ const SystemActions = GObject.registerClass({
case POWER_OFF_ACTION_ID: case POWER_OFF_ACTION_ID:
this.activatePowerOff(); this.activatePowerOff();
break; break;
case RESTART_ACTION_ID:
this.activateRestart();
break;
case LOCK_SCREEN_ACTION_ID: case LOCK_SCREEN_ACTION_ID:
this.activateLockScreen(); this.activateLockScreen();
break; break;
@ -361,9 +343,6 @@ const SystemActions = GObject.registerClass({
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY)); this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
this._actions.get(POWER_OFF_ACTION_ID).available = this._canHavePowerOff && !disabled; this._actions.get(POWER_OFF_ACTION_ID).available = this._canHavePowerOff && !disabled;
this.notify('can-power-off'); this.notify('can-power-off');
this._actions.get(RESTART_ACTION_ID).available = this._canHavePowerOff && !disabled;
this.notify('can-restart');
} }
_updateHaveSuspend() { _updateHaveSuspend() {
@ -462,13 +441,6 @@ const SystemActions = GObject.registerClass({
this._session.ShutdownRemote(0); this._session.ShutdownRemote(0);
} }
activateRestart() {
if (!this._actions.get(RESTART_ACTION_ID).available)
throw new Error('The restart action is not available!');
this._session.RebootRemote();
}
activateSuspend() { activateSuspend() {
if (!this._actions.get(SUSPEND_ACTION_ID).available) if (!this._actions.get(SUSPEND_ACTION_ID).available)
throw new Error('The suspend action is not available!'); throw new Error('The suspend action is not available!');

View File

@ -1,9 +1,9 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine, /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
formatTime, formatTimeSpan, createTimeLabel, insertSorted, formatTime, formatTimeSpan, createTimeLabel, insertSorted,
ensureActorVisibleInScrollView, wiggle */ makeCloseButton, ensureActorVisibleInScrollView, wiggle */
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; const { Clutter, Gio, GLib, GObject, Shell, St, GnomeDesktop } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -363,6 +363,51 @@ function insertSorted(array, val, cmp) {
return pos; return pos;
} }
var CloseButton = GObject.registerClass(
class CloseButton extends St.Button {
_init(boxpointer) {
super._init({
style_class: 'notification-close',
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START,
});
this._boxPointer = boxpointer;
if (boxpointer)
this._boxPointer.connect('arrow-side-changed', this._sync.bind(this));
}
_computeBoxPointerOffset() {
if (!this._boxPointer || !this._boxPointer.get_stage())
return 0;
let side = this._boxPointer.arrowSide;
if (side == St.Side.TOP)
return this._boxPointer.getArrowHeight();
else
return 0;
}
_sync() {
let themeNode = this.get_theme_node();
let offY = this._computeBoxPointerOffset();
this.translation_x = themeNode.get_length('-shell-close-overlap-x');
this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
}
vfunc_style_changed() {
this._sync();
super.vfunc_style_changed();
}
});
function makeCloseButton(boxpointer) {
return new CloseButton(boxpointer);
}
function ensureActorVisibleInScrollView(scrollView, actor) { function ensureActorVisibleInScrollView(scrollView, actor) {
let adjustment = scrollView.vscroll.adjustment; let adjustment = scrollView.vscroll.adjustment;
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values(); let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();

View File

@ -7,8 +7,6 @@ const PermissionStore = imports.misc.permissionStore;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
Gio._promisify(Geoclue.Simple, 'new', 'new_finish');
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration'); const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
const WEATHER_BUS_NAME = 'org.gnome.Weather'; const WEATHER_BUS_NAME = 'org.gnome.Weather';
@ -81,7 +79,16 @@ var WeatherClient = class {
this._weatherApp = null; this._weatherApp = null;
this._weatherProxy = null; this._weatherProxy = null;
this._createWeatherProxy(); let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
Gio.DBusProxy.new(
Gio.DBus.session,
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
WEATHER_BUS_NAME,
WEATHER_OBJECT_PATH,
WEATHER_INTEGRATION_IFACE,
null,
this._onWeatherProxyReady.bind(this));
this._settings = new Gio.Settings({ this._settings = new Gio.Settings({
schema_id: 'org.gnome.shell.weather', schema_id: 'org.gnome.shell.weather',
@ -139,17 +146,9 @@ var WeatherClient = class {
(!this._needsAuth || this._weatherAuthorized); (!this._needsAuth || this._weatherAuthorized);
} }
async _createWeatherProxy() { _onWeatherProxyReady(o, res) {
const nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
try { try {
this._weatherProxy = await Gio.DBusProxy.new( this._weatherProxy = Gio.DBusProxy.new_finish(res);
Gio.DBus.session,
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
WEATHER_BUS_NAME,
WEATHER_OBJECT_PATH,
WEATHER_INTEGRATION_IFACE,
null);
} catch (e) { } catch (e) {
log(`Failed to create GNOME Weather proxy: ${e}`); log(`Failed to create GNOME Weather proxy: ${e}`);
return; return;
@ -240,15 +239,16 @@ var WeatherClient = class {
} }
} }
async _startGClueService() { _startGClueService() {
if (this._gclueStarting) if (this._gclueStarting)
return; return;
this._gclueStarting = true; this._gclueStarting = true;
Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
(o, res) => {
try { try {
this._gclueService = await Geoclue.Simple.new( this._gclueService = Geoclue.Simple.new_finish(res);
'org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null);
} catch (e) { } catch (e) {
log(`Failed to connect to Geoclue2 service: ${e.message}`); log(`Failed to connect to Geoclue2 service: ${e.message}`);
this._setLocation(this._mostRecentLocation); this._setLocation(this._mostRecentLocation);
@ -257,6 +257,7 @@ var WeatherClient = class {
this._gclueStarted = true; this._gclueStarted = true;
this._gclueService.get_client().distance_threshold = 100; this._gclueService.get_client().distance_threshold = 100;
this._updateLocationMonitoring(); this._updateLocationMonitoring();
});
} }
_onGClueLocationChanged() { _onGClueLocationChanged() {

View File

@ -1,146 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported run, finish, script_topBarNavDone, script_notificationShowDone,
script_notificationCloseDone, script_overviewShowDone,
script_applicationsShowStart, script_applicationsShowDone, METRICS,
*/
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
const { St } = imports.gi;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Scripting = imports.ui.scripting;
// This script tests the most important (basic) functionality of the shell.
var METRICS = {};
async function run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent('topBarNavStart', 'Starting to navigate the top bar');
Scripting.defineScriptEvent('topBarNavDone', 'Done navigating the top bar');
Scripting.defineScriptEvent('notificationShowStart', 'Showing a notification');
Scripting.defineScriptEvent('notificationShowDone', 'Done showing a notification');
Scripting.defineScriptEvent('notificationCloseStart', 'Closing a notification');
Scripting.defineScriptEvent('notificationCloseDone', 'Done closing a notification');
Scripting.defineScriptEvent('overviewShowStart', 'Starting to show the overview');
Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
Scripting.defineScriptEvent('applicationsShowStart', 'Starting to switch to applications view');
Scripting.defineScriptEvent('applicationsShowDone', 'Done switching to applications view');
Main.overview.connect('shown',
() => Scripting.scriptEvent('overviewShowDone'));
await Scripting.sleep(1000);
// navigate through top bar
Scripting.scriptEvent('topBarNavStart');
Main.panel.statusArea.aggregateMenu.menu.open();
await Scripting.sleep(400);
const { menuManager } = Main.panel;
while (menuManager.activeMenu &&
Main.panel.navigate_focus(menuManager.activeMenu.sourceActor,
St.DirectionType.TAB_BACKWARD, false))
await Scripting.sleep(400);
Scripting.scriptEvent('topBarNavDone');
await Scripting.sleep(1000);
// notification
const source = new MessageTray.SystemNotificationSource();
Main.messageTray.add(source);
Scripting.scriptEvent('notificationShowStart');
source.connect('notification-show',
() => Scripting.scriptEvent('notificationShowDone'));
const notification = new MessageTray.Notification(source,
'A test notification');
source.showNotification(notification);
await Scripting.sleep(400);
Main.panel.statusArea.dateMenu.menu.open();
await Scripting.sleep(400);
Scripting.scriptEvent('notificationCloseStart');
notification.connect('destroy',
() => Scripting.scriptEvent('notificationCloseDone'));
notification.destroy();
await Scripting.sleep(400);
Main.panel.statusArea.dateMenu.menu.close();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
// overview (window picker)
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
await Scripting.waitLeisure();
Main.overview.hide();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
// overview (app picker)
Main.overview.show();
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false;
await Scripting.waitLeisure();
Main.overview.hide();
await Scripting.waitLeisure();
/* eslint-enable no-await-in-loop */
}
let topBarNav = false;
let notificationShown = false;
let notificationClosed = false;
let windowPickerShown = false;
let appPickerShown = false;
function script_topBarNavDone() {
topBarNav = true;
}
function script_notificationShowDone() {
notificationShown = true;
}
function script_notificationCloseDone() {
notificationClosed = true;
}
function script_overviewShowDone() {
windowPickerShown = true;
}
function script_applicationsShowDone() {
appPickerShown = true;
}
function finish() {
if (!topBarNav)
throw new Error('Failed to navigate top bar');
if (!notificationShown)
throw new Error('Failed to show notification');
if (!notificationClosed)
throw new Error('Failed to close notification');
if (!windowPickerShown)
throw new Error('Failed to show window picker');
if (!appPickerShown)
throw new Error('Failed to show app picker');
}

View File

@ -70,8 +70,7 @@ let WINDOW_CONFIGS = [
{ width: 640, height: 480, alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha' }, { width: 640, height: 480, alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha' },
]; ];
async function run() { function *run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview"); Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
@ -85,7 +84,7 @@ async function run() {
Scripting.scriptEvent('overviewShowDone'); Scripting.scriptEvent('overviewShowDone');
}); });
await Scripting.sleep(1000); yield Scripting.sleep(1000);
for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) { for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
// We go to the overview twice for each configuration; the first time // We go to the overview twice for each configuration; the first time
@ -93,50 +92,49 @@ async function run() {
// a clean set of numbers. // a clean set of numbers.
if ((i % 2) == 0) { if ((i % 2) == 0) {
let config = WINDOW_CONFIGS[i / 2]; let config = WINDOW_CONFIGS[i / 2];
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
for (let k = 0; k < config.count; k++) { for (let k = 0; k < config.count; k++) {
await Scripting.createTestWindow({ width: config.width, yield Scripting.createTestWindow({ width: config.width,
height: config.height, height: config.height,
alpha: config.alpha, alpha: config.alpha,
maximized: config.maximized }); maximized: config.maximized });
} }
await Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
} }
Scripting.scriptEvent('overviewShowStart'); Scripting.scriptEvent('overviewShowStart');
Main.overview.show(); Main.overview.show();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Main.overview.hide(); Main.overview.hide();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
System.gc(); System.gc();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.collectStatistics(); Scripting.collectStatistics();
Scripting.scriptEvent('afterShowHide'); Scripting.scriptEvent('afterShowHide');
} }
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Main.overview.show(); Main.overview.show();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true; Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false; Main.overview.dash.showAppsButton.checked = false;
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
} }
/* eslint-enable no-await-in-loop */
} }
let showingOverview = false; let showingOverview = false;

View File

@ -94,8 +94,7 @@ function extractBootTimestamp() {
return result; return result;
} }
async function run() { function *run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("desktopShown", "Finished initial animation"); Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
@ -111,7 +110,7 @@ async function run() {
Scripting.defineScriptEvent("geditLaunch", "gedit application launch"); Scripting.defineScriptEvent("geditLaunch", "gedit application launch");
Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn"); Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn");
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('desktopShown'); Scripting.scriptEvent('desktopShown');
let interfaceSettings = new Gio.Settings({ let interfaceSettings = new Gio.Settings({
@ -121,22 +120,22 @@ async function run() {
Scripting.scriptEvent('overviewShowStart'); Scripting.scriptEvent('overviewShowStart');
Main.overview.show(); Main.overview.show();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('overviewShowDone'); Scripting.scriptEvent('overviewShowDone');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true; Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Main.overview.hide(); Main.overview.hide();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
// --------------------- // // --------------------- //
// Tests of redraw speed // // Tests of redraw speed //
@ -146,46 +145,46 @@ async function run() {
global.frame_finish_timestamp = true; global.frame_finish_timestamp = true;
for (let k = 0; k < 5; k++) for (let k = 0; k < 5; k++)
await Scripting.createTestWindow({ maximized: true }); yield Scripting.createTestWindow({ maximized: true });
await Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('mainViewDrawStart'); Scripting.scriptEvent('mainViewDrawStart');
await waitAndDraw(1000); yield waitAndDraw(1000);
Scripting.scriptEvent('mainViewDrawDone'); Scripting.scriptEvent('mainViewDrawDone');
Main.overview.show(); Main.overview.show();
Scripting.waitLeisure(); Scripting.waitLeisure();
await Scripting.sleep(1500); yield Scripting.sleep(1500);
Scripting.scriptEvent('overviewDrawStart'); Scripting.scriptEvent('overviewDrawStart');
await waitAndDraw(1000); yield waitAndDraw(1000);
Scripting.scriptEvent('overviewDrawDone'); Scripting.scriptEvent('overviewDrawDone');
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
Main.overview.hide(); Main.overview.hide();
await Scripting.createTestWindow({ maximized: true, yield Scripting.createTestWindow({ maximized: true,
redraws: true }); redraws: true });
await Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestStart'); Scripting.scriptEvent('redrawTestStart');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestDone'); Scripting.scriptEvent('redrawTestDone');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('collectTimings'); Scripting.scriptEvent('collectTimings');
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
global.frame_timestamps = false; global.frame_timestamps = false;
global.frame_finish_timestamp = false; global.frame_finish_timestamp = false;
await Scripting.sleep(1000); yield Scripting.sleep(1000);
let appSys = Shell.AppSystem.get_default(); let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop'); let app = appSys.lookup_app('org.gnome.gedit.desktop');
@ -198,22 +197,21 @@ async function run() {
throw new Error('gedit was already running'); throw new Error('gedit was already running');
while (windows.length == 0) { while (windows.length == 0) {
await waitSignal(global.display, 'window-created'); yield waitSignal(global.display, 'window-created');
windows = app.get_windows(); windows = app.get_windows();
} }
let actor = windows[0].get_compositor_private(); let actor = windows[0].get_compositor_private();
await waitSignal(actor, 'first-frame'); yield waitSignal(actor, 'first-frame');
Scripting.scriptEvent('geditFirstFrame'); Scripting.scriptEvent('geditFirstFrame');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
windows[0].delete(global.get_current_time()); windows[0].delete(global.get_current_time());
await Scripting.sleep(1000); yield Scripting.sleep(1000);
interfaceSettings.set_boolean('enable-animations', true); interfaceSettings.set_boolean('enable-animations', true);
/* eslint-enable no-await-in-loop */
} }
let overviewShowStart; let overviewShowStart;

View File

@ -68,8 +68,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._items = this._switcherList.icons; this._items = this._switcherList.icons;
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
super.vfunc_allocate(box); super.vfunc_allocate(box, flags);
// Allocate the thumbnails // Allocate the thumbnails
// We try to avoid overflowing the screen so we base the resulting size on // We try to avoid overflowing the screen so we base the resulting size on
@ -102,7 +102,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1); this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1); let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
childBox.y2 = childBox.y1 + childNaturalHeight; childBox.y2 = childBox.y1 + childNaturalHeight;
this._thumbnails.allocate(childBox); this._thumbnails.allocate(childBox, flags);
} }
} }
@ -681,7 +681,8 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
// Cache the window list now; we don't handle dynamic changes here, // Cache the window list now; we don't handle dynamic changes here,
// and we don't want to be continually retrieving it // and we don't want to be continually retrieving it
appIcon.cachedWindows = allWindows.filter( appIcon.cachedWindows = allWindows.filter(
w => windowTracker.get_window_app(w) === appIcon.app); w => windowTracker.get_window_app(w) == appIcon.app
);
if (appIcon.cachedWindows.length > 0) if (appIcon.cachedWindows.length > 0)
this._addIcon(appIcon); this._addIcon(appIcon);
} }
@ -749,9 +750,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
return super.vfunc_get_preferred_height(forWidth); return super.vfunc_get_preferred_height(forWidth);
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
// Allocate the main list items // Allocate the main list items
super.vfunc_allocate(box); super.vfunc_allocate(box, flags);
let contentBox = this.get_theme_node().get_content_box(box); let contentBox = this.get_theme_node().get_content_box(box);
@ -766,7 +767,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
childBox.x2 = childBox.x1 + arrowWidth; childBox.x2 = childBox.x1 + arrowWidth;
childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight; childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
childBox.y2 = childBox.y1 + arrowHeight; childBox.y2 = childBox.y1 + arrowHeight;
this._arrows[i].allocate(childBox); this._arrows[i].allocate(childBox, flags);
} }
} }
@ -852,9 +853,6 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
if (index === -1) if (index === -1)
return; return;
this._arrows[index].destroy();
this._arrows.splice(index, 1);
this.icons.splice(index, 1); this.icons.splice(index, 1);
this.removeItem(index); this.removeItem(index);
} }
@ -1059,28 +1057,28 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
return [minHeight, natHeight]; return [minHeight, natHeight];
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
let contentBox = themeNode.get_content_box(box); let contentBox = themeNode.get_content_box(box);
const labelHeight = this._label.height;
const totalLabelHeight =
labelHeight + themeNode.get_padding(St.Side.BOTTOM);
box.y2 -= totalLabelHeight; let childBox = new Clutter.ActorBox();
super.vfunc_allocate(box); childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2;
childBox.y1 = childBox.y2 - this._label.height;
this._label.allocate(childBox, flags);
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM);
childBox.x1 = box.x1;
childBox.x2 = box.x2;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - totalLabelHeight;
super.vfunc_allocate(childBox, flags);
// Hooking up the parent vfunc will call this.set_allocation() with // Hooking up the parent vfunc will call this.set_allocation() with
// the height without the label height, so call it again with the // the height without the label height, so call it again with the
// correct size here. // correct size here.
box.y2 += totalLabelHeight; this.set_allocation(box, flags);
this.set_allocation(box);
const childBox = new Clutter.ActorBox();
childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2;
childBox.y1 = childBox.y2 - labelHeight;
this._label.allocate(childBox);
} }
highlight(index, justOutline) { highlight(index, justOutline) {

View File

@ -60,7 +60,7 @@ class Animation extends St.Bin {
} }
_loadFile(file, width, height) { _loadFile(file, width, height) {
const resourceScale = this.get_resource_scale(); let [validResourceScale, resourceScale] = this.get_resource_scale();
let wasPlaying = this._isPlaying; let wasPlaying = this._isPlaying;
if (this._isPlaying) if (this._isPlaying)
@ -69,6 +69,12 @@ class Animation extends St.Bin {
this._isLoaded = false; this._isLoaded = false;
this.destroy_all_children(); this.destroy_all_children();
if (!validResourceScale) {
if (wasPlaying)
this.play();
return;
}
let textureCache = St.TextureCache.get_default(); let textureCache = St.TextureCache.get_default();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = textureCache.load_sliced_image(file, width, height, this._animations = textureCache.load_sliced_image(file, width, height,

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
/* exported getAppFavorites */ /* exported getAppFavorites */
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const ParentalControlsManager = imports.misc.parentalControlsManager;
const Signals = imports.signals; const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -13,7 +12,6 @@ const RENAMED_DESKTOP_IDS = {
'cheese.desktop': 'org.gnome.Cheese.desktop', 'cheese.desktop': 'org.gnome.Cheese.desktop',
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop', 'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
'empathy.desktop': 'org.gnome.Empathy.desktop', 'empathy.desktop': 'org.gnome.Empathy.desktop',
'eog.desktop': 'org.gnome.eog.desktop',
'epiphany.desktop': 'org.gnome.Epiphany.desktop', 'epiphany.desktop': 'org.gnome.Epiphany.desktop',
'evolution.desktop': 'org.gnome.Evolution.desktop', 'evolution.desktop': 'org.gnome.Evolution.desktop',
'file-roller.desktop': 'org.gnome.FileRoller.desktop', 'file-roller.desktop': 'org.gnome.FileRoller.desktop',
@ -66,13 +64,6 @@ const RENAMED_DESKTOP_IDS = {
class AppFavorites { class AppFavorites {
constructor() { constructor() {
// Filter the apps through the users parental controls.
this._parentalControlsManager = ParentalControlsManager.getDefault();
this._parentalControlsManager.connect('app-filter-changed', () => {
this.reload();
this.emit('changed');
});
this.FAVORITE_APPS_KEY = 'favorite-apps'; this.FAVORITE_APPS_KEY = 'favorite-apps';
this._favorites = {}; this._favorites = {};
global.settings.connect('changed::%s'.format(this.FAVORITE_APPS_KEY), this._onFavsChanged.bind(this)); global.settings.connect('changed::%s'.format(this.FAVORITE_APPS_KEY), this._onFavsChanged.bind(this));
@ -104,7 +95,7 @@ class AppFavorites {
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids); global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
let apps = ids.map(id => appSys.lookup_app(id)) let apps = ids.map(id => appSys.lookup_app(id))
.filter(app => app !== null && this._parentalControlsManager.shouldShowApp(app.app_info)); .filter(app => app != null);
this._favorites = {}; this._favorites = {};
for (let i = 0; i < apps.length; i++) { for (let i = 0; i < apps.length; i++) {
let app = apps[i]; let app = apps[i];
@ -143,9 +134,6 @@ class AppFavorites {
if (!app) if (!app)
return false; return false;
if (!this._parentalControlsManager.shouldShowApp(app.app_info))
return false;
let ids = this._getIds(); let ids = this._getIds();
if (pos == -1) if (pos == -1)
ids.push(appId); ids.push(appId);

View File

@ -147,8 +147,9 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
_onDeviceSelected(dialog, device) { _onDeviceSelected(dialog, device) {
let connection = this._dbusImpl.get_connection(); let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info(); let info = this._dbusImpl.get_info();
const deviceName = Object.keys(AudioDevice) let deviceName = Object.keys(AudioDevice).filter(
.filter(dev => AudioDevice[dev] === device)[0].toLowerCase(); dev => AudioDevice[dev] == device
)[0].toLowerCase();
connection.emit_signal(this._audioSelectionDialog._sender, connection.emit_signal(this._audioSelectionDialog._sender,
this._dbusImpl.get_object_path(), this._dbusImpl.get_object_path(),
info ? info.name : null, info ? info.name : null,

View File

@ -347,8 +347,6 @@ var Background = GObject.registerClass({
this.set_color(color); this.set_color(color);
else else
this.set_gradient(shadingType, color, secondColor); this.set_gradient(shadingType, color, secondColor);
this._setLoaded();
} }
_watchFile(file) { _watchFile(file) {
@ -514,8 +512,8 @@ var SystemBackground = GObject.registerClass({
super._init({ super._init({
meta_display: global.display, meta_display: global.display,
monitor: 0, monitor: 0,
background: _systemBackground,
}); });
this.content.background = _systemBackground;
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.emit('loaded'); this.emit('loaded');
@ -714,18 +712,13 @@ var BackgroundManager = class BackgroundManager {
} }
let newBackgroundActor = this._createBackgroundActor(); let newBackgroundActor = this._createBackgroundActor();
newBackgroundActor.vignette_sharpness = this.backgroundActor.vignette_sharpness;
const oldContent = this.backgroundActor.content; newBackgroundActor.brightness = this.backgroundActor.brightness;
const newContent = newBackgroundActor.content;
newContent.vignette_sharpness = oldContent.vignette_sharpness;
newContent.brightness = oldContent.brightness;
newBackgroundActor.visible = this.backgroundActor.visible; newBackgroundActor.visible = this.backgroundActor.visible;
this._newBackgroundActor = newBackgroundActor; this._newBackgroundActor = newBackgroundActor;
const { background } = newBackgroundActor.content; let background = newBackgroundActor.background;
if (background.isLoaded) { if (background.isLoaded) {
this._swapBackgroundActor(); this._swapBackgroundActor();
@ -745,8 +738,6 @@ var BackgroundManager = class BackgroundManager {
let backgroundActor = new Meta.BackgroundActor({ let backgroundActor = new Meta.BackgroundActor({
meta_display: global.display, meta_display: global.display,
monitor: this._monitorIndex, monitor: this._monitorIndex,
});
backgroundActor.content.set({
background, background,
vignette: this._vignette, vignette: this._vignette,
vignette_sharpness: 0.5, vignette_sharpness: 0.5,
@ -767,27 +758,10 @@ var BackgroundManager = class BackgroundManager {
this._updateBackgroundActor(); this._updateBackgroundActor();
}); });
let loadedSignalId;
if (background.isLoaded) {
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.emit('loaded');
return GLib.SOURCE_REMOVE;
});
} else {
loadedSignalId = background.connect('loaded', () => {
background.disconnect(loadedSignalId);
loadedSignalId = null;
this.emit('loaded');
});
}
backgroundActor.connect('destroy', () => { backgroundActor.connect('destroy', () => {
if (changeSignalId) if (changeSignalId)
background.disconnect(changeSignalId); background.disconnect(changeSignalId);
if (loadedSignalId)
background.disconnect(loadedSignalId);
if (backgroundActor.loadedSignalId) if (backgroundActor.loadedSignalId)
background.disconnect(backgroundActor.loadedSignalId); background.disconnect(backgroundActor.loadedSignalId);
}); });

View File

@ -30,8 +30,8 @@ var BarLevel = GObject.registerClass({
accessible_role: Atk.Role.LEVEL_BAR, accessible_role: Atk.Role.LEVEL_BAR,
}; };
super._init(Object.assign(defaultParams, params)); super._init(Object.assign(defaultParams, params));
this.connect('notify::allocation', () => { this.connect('allocation-changed', (actor, box) => {
this._barLevelWidth = this.allocation.get_width(); this._barLevelWidth = box.get_width();
}); });
this._customAccessible = St.GenericAccessible.new_for_actor(this); this._customAccessible = St.GenericAccessible.new_for_actor(this);

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported BoxPointer */ /* exported BoxPointer */
const { Clutter, GObject, St } = imports.gi; const { Clutter, GObject, Shell, St } = imports.gi;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -196,13 +196,8 @@ var BoxPointer = GObject.registerClass({
return themeNode.adjust_preferred_height(...height); return themeNode.adjust_preferred_height(...height);
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
if (this._sourceActor && this._sourceActor.mapped) { this.set_allocation(box, flags);
this._reposition(box);
this._updateFlip(box);
}
this.set_allocation(box);
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width'); let borderWidth = themeNode.get_length('-arrow-border-width');
@ -214,7 +209,7 @@ var BoxPointer = GObject.registerClass({
childBox.y1 = 0; childBox.y1 = 0;
childBox.x2 = availWidth; childBox.x2 = availWidth;
childBox.y2 = availHeight; childBox.y2 = availHeight;
this._border.allocate(childBox); this._border.allocate(childBox, flags);
childBox.x1 = borderWidth; childBox.x1 = borderWidth;
childBox.y1 = borderWidth; childBox.y1 = borderWidth;
@ -234,7 +229,13 @@ var BoxPointer = GObject.registerClass({
childBox.x2 -= rise; childBox.x2 -= rise;
break; break;
} }
this.bin.allocate(childBox); this.bin.allocate(childBox, flags);
if (this._sourceActor && this._sourceActor.mapped) {
this._reposition(box);
this._updateFlip(box);
this.set_allocation(box, flags);
}
} }
_drawBorder(area) { _drawBorder(area) {
@ -453,16 +454,15 @@ var BoxPointer = GObject.registerClass({
let alignment = this._arrowAlignment; let alignment = this._arrowAlignment;
let monitorIndex = Main.layoutManager.findIndexForActor(sourceActor); let monitorIndex = Main.layoutManager.findIndexForActor(sourceActor);
this._sourceExtents = sourceActor.get_transformed_extents(); this._sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
this._workArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); this._workArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex);
// Position correctly relative to the sourceActor // Position correctly relative to the sourceActor
let sourceNode = sourceActor.get_theme_node(); let sourceNode = sourceActor.get_theme_node();
let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box()); let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
let sourceTopLeft = this._sourceExtents.get_top_left(); let sourceAllocation = this._sourceAllocation;
let sourceBottomRight = this._sourceExtents.get_bottom_right(); let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
let sourceCenterX = sourceTopLeft.x + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment; let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
let sourceCenterY = sourceTopLeft.y + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
let [, , natWidth, natHeight] = this.get_preferred_size(); let [, , natWidth, natHeight] = this.get_preferred_size();
// We also want to keep it onscreen, and separated from the // We also want to keep it onscreen, and separated from the
@ -482,16 +482,16 @@ var BoxPointer = GObject.registerClass({
switch (this._arrowSide) { switch (this._arrowSide) {
case St.Side.TOP: case St.Side.TOP:
resY = sourceBottomRight.y + gap; resY = sourceAllocation.y2 + gap;
break; break;
case St.Side.BOTTOM: case St.Side.BOTTOM:
resY = sourceTopLeft.y - natHeight - gap; resY = sourceAllocation.y1 - natHeight - gap;
break; break;
case St.Side.LEFT: case St.Side.LEFT:
resX = sourceBottomRight.x + gap; resX = sourceAllocation.x2 + gap;
break; break;
case St.Side.RIGHT: case St.Side.RIGHT:
resX = sourceTopLeft.x - natWidth - gap; resX = sourceAllocation.x1 - natWidth - gap;
break; break;
} }
@ -587,30 +587,29 @@ var BoxPointer = GObject.registerClass({
} }
_calculateArrowSide(arrowSide) { _calculateArrowSide(arrowSide) {
let sourceTopLeft = this._sourceExtents.get_top_left(); let sourceAllocation = this._sourceAllocation;
let sourceBottomRight = this._sourceExtents.get_bottom_right();
let [, , boxWidth, boxHeight] = this.get_preferred_size(); let [, , boxWidth, boxHeight] = this.get_preferred_size();
let workarea = this._workArea; let workarea = this._workArea;
switch (arrowSide) { switch (arrowSide) {
case St.Side.TOP: case St.Side.TOP:
if (sourceBottomRight.y + boxHeight > workarea.y + workarea.height && if (sourceAllocation.y2 + boxHeight > workarea.y + workarea.height &&
boxHeight < sourceTopLeft.y - workarea.y) boxHeight < sourceAllocation.y1 - workarea.y)
return St.Side.BOTTOM; return St.Side.BOTTOM;
break; break;
case St.Side.BOTTOM: case St.Side.BOTTOM:
if (sourceTopLeft.y - boxHeight < workarea.y && if (sourceAllocation.y1 - boxHeight < workarea.y &&
boxHeight < workarea.y + workarea.height - sourceBottomRight.y) boxHeight < workarea.y + workarea.height - sourceAllocation.y2)
return St.Side.TOP; return St.Side.TOP;
break; break;
case St.Side.LEFT: case St.Side.LEFT:
if (sourceBottomRight.x + boxWidth > workarea.x + workarea.width && if (sourceAllocation.x2 + boxWidth > workarea.x + workarea.width &&
boxWidth < sourceTopLeft.x - workarea.x) boxWidth < sourceAllocation.x1 - workarea.x)
return St.Side.RIGHT; return St.Side.RIGHT;
break; break;
case St.Side.RIGHT: case St.Side.RIGHT:
if (sourceTopLeft.x - boxWidth < workarea.x && if (sourceAllocation.x1 - boxWidth < workarea.x &&
boxWidth < workarea.x + workarea.width - sourceBottomRight.x) boxWidth < workarea.x + workarea.width - sourceAllocation.x2)
return St.Side.LEFT; return St.Side.LEFT;
break; break;
} }

View File

@ -14,6 +14,7 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
var MSECS_IN_DAY = 24 * 60 * 60 * 1000; var MSECS_IN_DAY = 24 * 60 * 60 * 1000;
var SHOW_WEEKDATE_KEY = 'show-weekdate'; var SHOW_WEEKDATE_KEY = 'show-weekdate';
var ELLIPSIS_CHAR = '\u2026';
var MESSAGE_ICON_SIZE = -1; // pick up from CSS var MESSAGE_ICON_SIZE = -1; // pick up from CSS
@ -31,6 +32,10 @@ function sameDay(dateA, dateB) {
return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate()); return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
} }
function isToday(date) {
return sameDay(new Date(), date);
}
function _isWorkDay(date) { function _isWorkDay(date) {
/* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */ /* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
let days = C_('calendar-no-work', "06"); let days = C_('calendar-no-work', "06");
@ -194,16 +199,14 @@ class DBusEventSource extends EventSourceBase {
this._initialized = false; this._initialized = false;
this._dbusProxy = new CalendarServer(); this._dbusProxy = new CalendarServer();
this._initProxy(); this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, (object, result) => {
}
async _initProxy() {
let loaded = false; let loaded = false;
try { try {
await this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null); this._dbusProxy.init_finish(result);
loaded = true; loaded = true;
} catch (e) { } catch (e) {
if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
// Ignore timeouts and install signals as normal, because with high // Ignore timeouts and install signals as normal, because with high
// probability the service will appear later on, and we will get a // probability the service will appear later on, and we will get a
// NameOwnerChanged which will finish loading // NameOwnerChanged which will finish loading
@ -211,18 +214,13 @@ class DBusEventSource extends EventSourceBase {
// (But still _initialized to false, because the proxy does not know // (But still _initialized to false, because the proxy does not know
// about the HasCalendars property and would cause an exception trying // about the HasCalendars property and would cause an exception trying
// to read it) // to read it)
if (!e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) { } else {
log('Error loading calendars: %s'.format(e.message)); log('Error loading calendars: %s'.format(e.message));
return; return;
} }
} }
this._dbusProxy.connectSignal('EventsAddedOrUpdated', this._dbusProxy.connectSignal('Changed', this._onChanged.bind(this));
this._onEventsAddedOrUpdated.bind(this));
this._dbusProxy.connectSignal('EventsRemoved',
this._onEventsRemoved.bind(this));
this._dbusProxy.connectSignal('ClientDisappeared',
this._onClientDisappeared.bind(this));
this._dbusProxy.connect('notify::g-name-owner', () => { this._dbusProxy.connect('notify::g-name-owner', () => {
if (this._dbusProxy.g_name_owner) if (this._dbusProxy.g_name_owner)
@ -240,6 +238,7 @@ class DBusEventSource extends EventSourceBase {
this.notify('has-calendars'); this.notify('has-calendars');
this._onNameAppeared(); this._onNameAppeared();
} }
});
} }
destroy() { destroy() {
@ -258,7 +257,7 @@ class DBusEventSource extends EventSourceBase {
} }
_resetCache() { _resetCache() {
this._events = new Map(); this._events = [];
this._lastRequestBegin = null; this._lastRequestBegin = null;
this._lastRequestEnd = null; this._lastRequestEnd = null;
} }
@ -274,46 +273,27 @@ class DBusEventSource extends EventSourceBase {
this.emit('changed'); this.emit('changed');
} }
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) { _onChanged() {
const [appointments = []] = argArray; this._loadEvents(false);
let changed = false; }
_onEventsReceived(results, _error) {
let newEvents = [];
let appointments = results[0] || [];
for (let n = 0; n < appointments.length; n++) { for (let n = 0; n < appointments.length; n++) {
const [id, summary, allDay, startTime, endTime] = appointments[n]; let a = appointments[n];
const date = new Date(startTime * 1000); let date = new Date(a[4] * 1000);
const end = new Date(endTime * 1000); let end = new Date(a[5] * 1000);
let id = a[0];
let summary = a[1];
let allDay = a[3];
let event = new CalendarEvent(id, date, end, summary, allDay); let event = new CalendarEvent(id, date, end, summary, allDay);
this._events.set(event.id, event); newEvents.push(event);
changed = true;
} }
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
if (changed) this._events = newEvents;
this.emit('changed'); this._isLoading = false;
}
_onEventsRemoved(dbusProxy, nameOwner, argArray) {
const [ids = []] = argArray;
let changed = false;
for (const id of ids)
changed |= this._events.delete(id);
if (changed)
this.emit('changed');
}
_onClientDisappeared(dbusProxy, nameOwner, argArray) {
let [sourceUid = ''] = argArray;
sourceUid += '\n';
let changed = false;
for (const id of this._events.keys()) {
if (id.startsWith(sourceUid))
changed |= this._events.delete(id);
}
if (changed)
this.emit('changed'); this.emit('changed');
} }
@ -323,38 +303,33 @@ class DBusEventSource extends EventSourceBase {
return; return;
if (this._curRequestBegin && this._curRequestEnd) { if (this._curRequestBegin && this._curRequestEnd) {
if (forceReload) { this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._events.clear();
this.emit('changed');
}
this._dbusProxy.SetTimeRangeRemote(
this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000, this._curRequestEnd.getTime() / 1000,
forceReload, forceReload,
this._onEventsReceived.bind(this),
Gio.DBusCallFlags.NONE); Gio.DBusCallFlags.NONE);
} }
} }
requestRange(begin, end) { requestRange(begin, end) {
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) { if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
this._isLoading = true;
this._lastRequestBegin = begin; this._lastRequestBegin = begin;
this._lastRequestEnd = end; this._lastRequestEnd = end;
this._curRequestBegin = begin; this._curRequestBegin = begin;
this._curRequestEnd = end; this._curRequestEnd = end;
this._loadEvents(true); this._loadEvents(false);
}
}
*_getFilteredEvents(begin, end) {
for (const event of this._events.values()) {
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
yield event;
} }
} }
getEvents(begin, end) { getEvents(begin, end) {
let result = [...this._getFilteredEvents(begin, end)]; let result = [];
for (let n = 0; n < this._events.length; n++) {
let event = this._events[n];
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
result.push(event);
}
result.sort((event1, event2) => { result.sort((event1, event2) => {
// sort events by end time on ending day // sort events by end time on ending day
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date; let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
@ -368,8 +343,12 @@ class DBusEventSource extends EventSourceBase {
let dayBegin = _getBeginningOfDay(day); let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day); let dayEnd = _getEndOfDay(day);
const { done } = this._getFilteredEvents(dayBegin, dayEnd).next(); let events = this.getEvents(dayBegin, dayEnd);
return !done;
if (events.length == 0)
return false;
return true;
} }
}); });
@ -718,6 +697,61 @@ var Calendar = GObject.registerClass({
} }
}); });
var EventMessage = GObject.registerClass(
class EventMessage extends MessageList.Message {
_init(event, date) {
super._init('', event.summary);
this._event = event;
this._date = date;
this.setTitle(this._formatEventTime());
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
this.setIcon(this._icon);
}
vfunc_style_changed() {
let iconVisible = this.get_parent().has_style_pseudo_class('first-child');
this._icon.opacity = iconVisible ? 255 : 0;
super.vfunc_style_changed();
}
_formatEventTime() {
let periodBegin = _getBeginningOfDay(this._date);
let periodEnd = _getEndOfDay(this._date);
let allDay = this._event.allDay || (this._event.date <= periodBegin &&
this._event.end >= periodEnd);
let title;
if (allDay) {
/* Translators: Shown in calendar event list for all day events
* Keep it short, best if you can use less then 10 characters
*/
title = C_("event list time", "All Day");
} else {
let date = this._event.date >= periodBegin
? this._event.date
: this._event.end;
title = Util.formatTime(date, { timeOnly: true });
}
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
if (this._event.date < periodBegin && !this._event.allDay) {
if (rtl)
title = '%s%s'.format(title, ELLIPSIS_CHAR);
else
title = '%s%s'.format(ELLIPSIS_CHAR, title);
}
if (this._event.end > periodEnd && !this._event.allDay) {
if (rtl)
title = '%s%s'.format(ELLIPSIS_CHAR, title);
else
title = '%s%s'.format(title, ELLIPSIS_CHAR);
}
return title;
}
});
var NotificationMessage = GObject.registerClass( var NotificationMessage = GObject.registerClass(
class NotificationMessage extends MessageList.Message { class NotificationMessage extends MessageList.Message {
_init(notification) { _init(notification) {
@ -783,6 +817,148 @@ class NotificationMessage extends MessageList.Message {
} }
}); });
var EventsSection = GObject.registerClass(
class EventsSection extends MessageList.MessageListSection {
_init() {
super._init();
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
this._eventSource = new EmptyEventSource();
this._messageById = new Map();
this._title = new St.Button({ style_class: 'events-section-title',
label: '',
can_focus: true });
this._title.child.x_align = Clutter.ActorAlign.START;
this.insert_child_below(this._title, null);
this._title.connect('clicked', this._onTitleClicked.bind(this));
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
this._appSys = Shell.AppSystem.get_default();
this._appSys.connect('installed-changed',
this._appInstalledChanged.bind(this));
this._appInstalledChanged();
}
setEventSource(eventSource) {
if (!(eventSource instanceof EventSourceBase))
throw new Error('Event source is not valid type');
this._eventSource = eventSource;
this._eventSource.connect('changed', this._reloadEvents.bind(this));
}
get allowed() {
return Main.sessionMode.showCalendarEvents;
}
_updateTitle() {
this._title.visible = !isToday(this._date);
if (!this._title.visible)
return;
let dayFormat;
let now = new Date();
if (sameYear(this._date, now)) {
/* Translators: Shown on calendar heading when selected day occurs on current year */
dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d"));
} else {
/* Translators: Shown on calendar heading when selected day occurs on different year */
dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d, %Y"));
}
this._title.label = this._date.toLocaleFormat(dayFormat);
}
_reloadEvents() {
if (this._eventSource.isLoading)
return;
this._reloading = true;
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 = this._messageById.get(event.id);
if (!message) {
message = new EventMessage(event, this._date);
this._messageById.set(event.id, message);
this.addMessage(message, false);
} else {
this.moveMessage(message, i, false);
}
}
this._reloading = false;
this._sync();
}
_appInstalledChanged() {
this._calendarApp = undefined;
this._title.reactive = this._getCalendarApp() != null;
}
_getCalendarApp() {
if (this._calendarApp !== undefined)
return this._calendarApp;
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
if (apps && (apps.length > 0)) {
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
let defaultInRecommended = apps.some(a => a.equal(app));
this._calendarApp = defaultInRecommended ? app : apps[0];
} else {
this._calendarApp = null;
}
return this._calendarApp;
}
_onTitleClicked() {
Main.overview.hide();
Main.panel.closeCalendar();
let appInfo = this._getCalendarApp();
if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
let app = this._appSys.lookup_app('evolution-calendar.desktop');
if (app)
appInfo = app.app_info;
}
appInfo.launch([], global.create_app_launch_context(0, -1));
}
setDate(date) {
super.setDate(date);
this._updateTitle();
this._reloadEvents();
}
_shouldShow() {
return !this.empty || !isToday(this._date);
}
_sync() {
if (this._reloading)
return;
super._sync();
}
});
var TimeLabel = GObject.registerClass( var TimeLabel = GObject.registerClass(
class NotificationTimeLabel extends St.Label { class NotificationTimeLabel extends St.Label {
_init(datetime) { _init(datetime) {
@ -879,6 +1055,10 @@ class NotificationSection extends MessageList.MessageListSection {
}); });
super.vfunc_map(); super.vfunc_map();
} }
_shouldShow() {
return !this.empty && isToday(this._date);
}
}); });
var Placeholder = GObject.registerClass( var Placeholder = GObject.registerClass(
@ -887,13 +1067,41 @@ class Placeholder extends St.BoxLayout {
super._init({ style_class: 'message-list-placeholder', vertical: true }); super._init({ style_class: 'message-list-placeholder', vertical: true });
this._date = new Date(); this._date = new Date();
const file = Gio.File.new_for_uri( let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
'resource:///org/gnome/shell/theme/no-notifications.svg'); let otherFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-events.svg');
this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file }) }); this._todayIcon = new Gio.FileIcon({ file: todayFile });
this._otherIcon = new Gio.FileIcon({ file: otherFile });
this._icon = new St.Icon();
this.add_actor(this._icon); this.add_actor(this._icon);
this._label = new St.Label({ text: _('No Notifications') }); this._label = new St.Label();
this.add_actor(this._label); this.add_actor(this._label);
this._sync();
}
setDate(date) {
if (sameDay(this._date, date))
return;
this._date = date;
this._sync();
}
_sync() {
let today = isToday(this._date);
if (today && this._icon.gicon == this._todayIcon)
return;
if (!today && this._icon.gicon == this._otherIcon)
return;
if (today) {
this._icon.gicon = this._todayIcon;
this._label.text = _("No Notifications");
} else {
this._icon.gicon = this._otherIcon;
this._label.text = _("No Events");
}
} }
}); });
@ -958,8 +1166,8 @@ class CalendarMessageList extends St.Widget {
child: this._dndSwitch, child: this._dndSwitch,
label_actor: dndLabel, label_actor: dndLabel,
}); });
this._dndSwitch.bind_property('state', this._dndButton.bind_property('checked',
this._dndButton, 'checked', this._dndSwitch, 'state',
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE); GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE);
hbox.add_child(this._dndButton); hbox.add_child(this._dndButton);
@ -994,6 +1202,9 @@ class CalendarMessageList extends St.Widget {
this._notificationSection = new NotificationSection(); this._notificationSection = new NotificationSection();
this._addSection(this._notificationSection); this._addSection(this._notificationSection);
this._eventsSection = new EventsSection();
this._addSection(this._eventsSection);
Main.sessionMode.connect('updated', this._sync.bind(this)); Main.sessionMode.connect('updated', this._sync.bind(this));
} }
@ -1029,4 +1240,13 @@ class CalendarMessageList extends St.Widget {
let canClear = sections.some(s => s.canClear && s.visible); let canClear = sections.some(s => s.canClear && s.visible);
this._clearButton.reactive = canClear; this._clearButton.reactive = canClear;
} }
setEventSource(eventSource) {
this._eventsSection.setEventSource(eventSource);
}
setDate(date) {
this._sectionList.get_children().forEach(s => s.setDate(date));
this._placeholder.setDate(date);
}
}); });

View File

@ -13,13 +13,17 @@ var ComponentManager = class {
_sessionUpdated() { _sessionUpdated() {
let newEnabledComponents = Main.sessionMode.components; let newEnabledComponents = Main.sessionMode.components;
newEnabledComponents newEnabledComponents.filter(
.filter(name => !this._enabledComponents.includes(name)) name => !this._enabledComponents.includes(name)
.forEach(name => this._enableComponent(name)); ).forEach(name => {
this._enableComponent(name);
});
this._enabledComponents this._enabledComponents.filter(
.filter(name => !newEnabledComponents.includes(name)) name => !newEnabledComponents.includes(name)
.forEach(name => this._disableComponent(name)); ).forEach(name => {
this._disableComponent(name);
});
this._enabledComponents = newEnabledComponents; this._enabledComponents = newEnabledComponents;
} }

View File

@ -125,7 +125,8 @@ var ContentTypeDiscoverer = class {
_emitCallback(mount, contentTypes = []) { _emitCallback(mount, contentTypes = []) {
// we're not interested in win32 software content types here // we're not interested in win32 software content types here
contentTypes = contentTypes.filter( contentTypes = contentTypes.filter(
type => type !== 'x-content/win32-software'); type => type != 'x-content/win32-software'
);
let apps = []; let apps = [];
contentTypes.forEach(type => { contentTypes.forEach(type => {

View File

@ -10,7 +10,6 @@ const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry; const ShellEntry = imports.ui.shellEntry;
Gio._promisify(Shell.NetworkAgent.prototype, 'init_async', 'init_finish');
Gio._promisify(Shell.NetworkAgent.prototype, Gio._promisify(Shell.NetworkAgent.prototype,
'search_vpn_plugin', 'search_vpn_plugin_finish'); 'search_vpn_plugin', 'search_vpn_plugin_finish');
@ -483,11 +482,11 @@ var VPNRequestHandler = class {
} }
} }
async _readStdoutOldStyle() { _readStdoutOldStyle() {
const [line, len_] = this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => {
await this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null); let [line, len_] = this._dataStdout.read_line_finish_utf8(result);
if (line === null) { if (line == null) {
// end of file // end of file
this._stdout.close(null); this._stdout.close(null);
return; return;
@ -497,13 +496,14 @@ var VPNRequestHandler = class {
// try to read more! // try to read more!
this._readStdoutOldStyle(); this._readStdoutOldStyle();
});
} }
async _readStdoutNewStyle() { _readStdoutNewStyle() {
const cnt = this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, (stream, result) => {
await this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null); let cnt = this._dataStdout.fill_finish(result);
if (cnt === 0) { if (cnt == 0) {
// end of file // end of file
this._showNewStyleDialog(); this._showNewStyleDialog();
@ -514,6 +514,7 @@ var VPNRequestHandler = class {
// Try to read more // Try to read more
this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size()); this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
this._readStdoutNewStyle(); this._readStdoutNewStyle();
});
} }
_showNewStyleDialog() { _showNewStyleDialog() {
@ -620,17 +621,15 @@ var NetworkAgent = class {
this._native.connect('cancel-request', this._cancelRequest.bind(this)); this._native.connect('cancel-request', this._cancelRequest.bind(this));
this._initialized = false; this._initialized = false;
this._initNative(); this._native.init_async(GLib.PRIORITY_DEFAULT, null, (o, res) => {
}
async _initNative() {
try { try {
await this._native.init_async(GLib.PRIORITY_DEFAULT, null); this._native.init_finish(res);
this._initialized = true; this._initialized = true;
} catch (e) { } catch (e) {
this._native = null; this._native = null;
logError(e, 'error initializing the NetworkManager Agent'); logError(e, 'error initializing the NetworkManager Agent');
} }
});
} }
enable() { enable() {

View File

@ -327,16 +327,12 @@ var AuthenticationDialog = GObject.registerClass({
} }
let resetDialog = () => { let resetDialog = () => {
this._sessionRequestTimeoutId = 0;
if (this.state != ModalDialog.State.OPENED) if (this.state != ModalDialog.State.OPENED)
return GLib.SOURCE_REMOVE; return;
this._passwordEntry.hide(); this._passwordEntry.hide();
this._cancelButton.grab_key_focus(); this._cancelButton.grab_key_focus();
this._okButton.reactive = false; this._okButton.reactive = false;
return GLib.SOURCE_REMOVE;
}; };
if (delay) { if (delay) {

View File

@ -7,14 +7,6 @@ var Tpl = null;
var Tp = null; var Tp = null;
try { try {
({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi); ({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
Gio._promisify(Tp.Channel.prototype, 'close_async', 'close_finish');
Gio._promisify(Tp.Channel.prototype,
'send_message_async', 'send_message_finish');
Gio._promisify(Tp.ChannelDispatchOperation.prototype,
'claim_with_async', 'claim_with_finish');
Gio._promisify(Tpl.LogManager.prototype,
'get_filtered_events_async', 'get_filtered_events_finish');
} catch (e) { } catch (e) {
log('Telepathy is not available, chat integration will be disabled.'); log('Telepathy is not available, chat integration will be disabled.');
} }
@ -223,7 +215,7 @@ class TelepathyClient extends Tp.BaseClient {
// We can only handle text channel, so close any other channel // We can only handle text channel, so close any other channel
if (!(channel instanceof Tp.TextChannel)) { if (!(channel instanceof Tp.TextChannel)) {
channel.close_async(); channel.close_async(null);
continue; continue;
} }
@ -269,7 +261,7 @@ class TelepathyClient extends Tp.BaseClient {
} }
} }
async _approveTextChannel(account, conn, channel, dispatchOp, context) { _approveTextChannel(account, conn, channel, dispatchOp, context) {
let [targetHandle_, targetHandleType] = channel.get_handle(); let [targetHandle_, targetHandleType] = channel.get_handle();
if (targetHandleType != Tp.HandleType.CONTACT) { if (targetHandleType != Tp.HandleType.CONTACT) {
@ -278,15 +270,17 @@ class TelepathyClient extends Tp.BaseClient {
return; return;
} }
context.accept();
// Approve private text channels right away as we are going to handle it // Approve private text channels right away as we are going to handle it
dispatchOp.claim_with_async(this, (o, result) => {
try { try {
await dispatchOp.claim_with_async(this); dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel], false); this._handlingChannels(account, conn, [channel], false);
} catch (err) { } catch (err) {
log('Failed to Claim channel: %s'.format(err.toString())); log('Failed to Claim channel: %s'.format(err.toString()));
} }
});
context.accept();
} }
_delegatedChannelsCb(_client, _channels) { _delegatedChannelsCb(_client, _channels) {
@ -447,14 +441,17 @@ class ChatSource extends MessageTray.Source {
} }
} }
async _getLogMessages() { _getLogMessages() {
let logManager = Tpl.LogManager.dup_singleton(); let logManager = Tpl.LogManager.dup_singleton();
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT); let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
const [events] = await logManager.get_filtered_events_async( logManager.get_filtered_events_async(this._account, entity,
this._account, entity,
Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES, Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
null); null, this._displayPendingMessages.bind(this));
}
_displayPendingMessages(logManager, result) {
let [success_, events] = logManager.get_filtered_events_finish(result);
let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e)); let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e));
this._ensureNotification(); this._ensureNotification();
@ -512,7 +509,9 @@ class ChatSource extends MessageTray.Source {
this._ackMessages(); this._ackMessages();
// The chat box has been destroyed so it can't // The chat box has been destroyed so it can't
// handle the channel any more. // handle the channel any more.
this._channel.close_async(); this._channel.close_async((channel, result) => {
channel.close_finish(result);
});
} else { } else {
// Don't indicate any unread messages when the notification // Don't indicate any unread messages when the notification
// that represents them has been destroyed. // that represents them has been destroyed.
@ -610,7 +609,9 @@ class ChatSource extends MessageTray.Source {
} }
let msg = Tp.ClientMessage.new_text(type, text); let msg = Tp.ClientMessage.new_text(type, text);
this._channel.send_message_async(msg, 0); this._channel.send_message_async(msg, 0, (src, result) => {
this._channel.send_message_finish(result);
});
} }
setChatState(state) { setChatState(state) {

View File

@ -292,11 +292,11 @@ class DashActor extends St.Widget {
}); });
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
let contentBox = this.get_theme_node().get_content_box(box); let contentBox = this.get_theme_node().get_content_box(box);
let availWidth = contentBox.x2 - contentBox.x1; let availWidth = contentBox.x2 - contentBox.x1;
this.set_allocation(box); this.set_allocation(box, flags);
let [appIcons, showAppsButton] = this.get_children(); let [appIcons, showAppsButton] = this.get_children();
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth); let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
@ -306,11 +306,11 @@ class DashActor extends St.Widget {
childBox.y1 = contentBox.y1; childBox.y1 = contentBox.y1;
childBox.x2 = contentBox.x2; childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2 - showAppsNatHeight; childBox.y2 = contentBox.y2 - showAppsNatHeight;
appIcons.allocate(childBox); appIcons.allocate(childBox, flags);
childBox.y1 = contentBox.y2 - showAppsNatHeight; childBox.y1 = contentBox.y2 - showAppsNatHeight;
childBox.y2 = contentBox.y2; childBox.y2 = contentBox.y2;
showAppsButton.allocate(childBox); showAppsButton.allocate(childBox, flags);
} }
vfunc_get_preferred_height(forWidth) { vfunc_get_preferred_height(forWidth) {
@ -815,12 +815,7 @@ var Dash = GObject.registerClass({
else else
pos = 0; // always insert at the top when dash is empty pos = 0; // always insert at the top when dash is empty
// Put the placeholder after the last favorite if we are not if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
// in the favorites zone
if (pos > numFavorites)
pos = numFavorites;
if (pos !== this._dragPlaceholderPos && this._animatingPlaceholdersCount === 0) {
this._dragPlaceholderPos = pos; this._dragPlaceholderPos = pos;
// Don't allow positioning before or after self // Don't allow positioning before or after self
@ -848,6 +843,11 @@ var Dash = GObject.registerClass({
this._dragPlaceholder.show(fadeIn); this._dragPlaceholder.show(fadeIn);
} }
// Remove the drag placeholder if we are not in the
// "favorites zone"
if (pos > numFavorites)
this._clearDragPlaceholder();
if (!this._dragPlaceholder) if (!this._dragPlaceholder)
return DND.DragMotionResult.NO_DROP; return DND.DragMotionResult.NO_DROP;

View File

@ -13,11 +13,7 @@ const System = imports.system;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
const NC_ = (context, str) => '%s\u0004%s'.format(context, str);
const T_ = Shell.util_translate_time_string;
const MAX_FORECASTS = 5; const MAX_FORECASTS = 5;
const ELLIPSIS_CHAR = '\u2026';
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration'); const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface); const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
@ -88,188 +84,6 @@ class TodayButton extends St.Button {
} }
}); });
var EventsSection = GObject.registerClass(
class EventsSection extends St.Button {
_init() {
super._init({
style_class: 'events-button',
can_focus: true,
x_expand: true,
child: new St.BoxLayout({
style_class: 'events-box',
vertical: true,
x_expand: true,
}),
});
this._startDate = null;
this._endDate = null;
this._eventSource = null;
this._calendarApp = null;
this._title = new St.Label({
style_class: 'events-title',
});
this.child.add_child(this._title);
this._eventsList = new St.BoxLayout({
style_class: 'events-list',
vertical: true,
x_expand: true,
});
this.child.add_child(this._eventsList);
this._appSys = Shell.AppSystem.get_default();
this._appSys.connect('installed-changed',
this._appInstalledChanged.bind(this));
this._appInstalledChanged();
}
setDate(date) {
const day = [date.getFullYear(), date.getMonth(), date.getDate()];
this._startDate = new Date(...day);
this._endDate = new Date(...day, 23, 59, 59, 999);
this._updateTitle();
this._reloadEvents();
}
setEventSource(eventSource) {
if (!(eventSource instanceof Calendar.EventSourceBase))
throw new Error('Event source is not valid type');
this._eventSource = eventSource;
this._eventSource.connect('changed', this._reloadEvents.bind(this));
this._eventSource.connect('notify::has-calendars',
this._sync.bind(this));
this._sync();
}
_updateTitle() {
/* Translators: Shown on calendar heading when selected day occurs on current year */
const sameYearFormat = T_(NC_('calendar heading', '%B %-d'));
/* Translators: Shown on calendar heading when selected day occurs on different year */
const otherYearFormat = T_(NC_('calendar heading', '%B %-d %Y'));
const timeSpanDay = GLib.TIME_SPAN_DAY / 1000;
const now = new Date();
if (this._startDate <= now && now <= this._endDate)
this._title.text = _('Today');
else if (this._endDate < now && now - this._endDate < timeSpanDay)
this._title.text = _('Yesterday');
else if (this._startDate > now && this._startDate - now < timeSpanDay)
this._title.text = _('Tomorrow');
else if (this._startDate.getFullYear() === now.getFullYear())
this._title.text = this._startDate.toLocaleFormat(sameYearFormat);
else
this._title.text = this._startDate.toLocaleFormat(otherYearFormat);
}
_formatEventTime(event) {
const allDay = event.allDay ||
(event.date <= this._startDate && event.end >= this._endDate);
let title;
if (allDay) {
/* Translators: Shown in calendar event list for all day events
* Keep it short, best if you can use less then 10 characters
*/
title = C_('event list time', 'All Day');
} else {
let date = event.date >= this._startDate ? event.date : event.end;
title = Util.formatTime(date, { timeOnly: true });
}
const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
if (event.date < this._startDate && !event.allDay) {
if (rtl)
title = '%s%s'.format(title, ELLIPSIS_CHAR);
else
title = '%s%s'.format(ELLIPSIS_CHAR, title);
}
if (event.end > this._endDate && !event.allDay) {
if (rtl)
title = '%s%s'.format(ELLIPSIS_CHAR, title);
else
title = '%s%s'.format(title, ELLIPSIS_CHAR);
}
return title;
}
_reloadEvents() {
if (this._eventSource.isLoading || this._reloading)
return;
this._reloading = true;
[...this._eventsList].forEach(c => c.destroy());
const events =
this._eventSource.getEvents(this._startDate, this._endDate);
for (let event of events) {
const box = new St.BoxLayout({
style_class: 'event-box',
vertical: true,
});
box.add(new St.Label({
text: event.summary,
style_class: 'event-summary',
}));
box.add(new St.Label({
text: this._formatEventTime(event),
style_class: 'event-time',
}));
this._eventsList.add_child(box);
}
if (this._eventsList.get_n_children() === 0) {
const placeholder = new St.Label({
text: _('No Events'),
style_class: 'event-placeholder',
});
this._eventsList.add_child(placeholder);
}
this._reloading = false;
this._sync();
}
vfunc_clicked() {
Main.overview.hide();
Main.panel.closeCalendar();
let appInfo = this._calendarApp;
if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
const app = this._appSys.lookup_app('evolution-calendar.desktop');
if (app)
appInfo = app.app_info;
}
appInfo.launch([], global.create_app_launch_context(0, -1));
}
_appInstalledChanged() {
const apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
if (apps && (apps.length > 0)) {
const app = Gio.AppInfo.get_default_for_type('text/calendar', false);
const defaultInRecommended = apps.some(a => a.equal(app));
this._calendarApp = defaultInRecommended ? app : apps[0];
} else {
this._calendarApp = null;
}
return this._sync();
}
_sync() {
this.visible = this._eventSource && this._eventSource.hasCalendars;
this.reactive = this._calendarApp !== null;
}
});
var WorldClocksSection = GObject.registerClass( var WorldClocksSection = GObject.registerClass(
class WorldClocksSection extends St.Button { class WorldClocksSection extends St.Button {
_init() { _init() {
@ -280,7 +94,6 @@ class WorldClocksSection extends St.Button {
}); });
this._clock = new GnomeDesktop.WallClock(); this._clock = new GnomeDesktop.WallClock();
this._clockNotifyId = 0; this._clockNotifyId = 0;
this._tzNotifyId = 0;
this._locations = []; this._locations = [];
@ -353,6 +166,8 @@ class WorldClocksSection extends St.Button {
layout.attach(header, 0, 0, 2, 1); layout.attach(header, 0, 0, 2, 1);
this.label_actor = header; this.label_actor = header;
let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
for (let i = 0; i < this._locations.length; i++) { for (let i = 0; i < this._locations.length; i++) {
let l = this._locations[i].location; let l = this._locations[i].location;
@ -365,8 +180,21 @@ class WorldClocksSection extends St.Button {
let time = new St.Label({ style_class: 'world-clocks-time' }); let time = new St.Label({ style_class: 'world-clocks-time' });
const utcOffset = this._getTimeAtLocation(l).get_utc_offset();
const offsetCurrentTz = utcOffset - localOffset;
const offsetHours = Math.abs(offsetCurrentTz) / GLib.TIME_SPAN_HOUR;
const offsetMinutes =
(Math.abs(offsetCurrentTz) % GLib.TIME_SPAN_HOUR) /
GLib.TIME_SPAN_MINUTE;
const prefix = offsetCurrentTz >= 0 ? '+' : '-';
const text = offsetMinutes === 0
? '%s%d'.format(prefix, offsetHours)
: '%s%d\u2236%d'.format(prefix, offsetHours, offsetMinutes);
const tz = new St.Label({ const tz = new St.Label({
style_class: 'world-clocks-timezone', style_class: 'world-clocks-timezone',
text,
x_align: Clutter.ActorAlign.END, x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER,
}); });
@ -384,65 +212,32 @@ class WorldClocksSection extends St.Button {
layout.attach(tz, 2, i + 1, 1, 1); layout.attach(tz, 2, i + 1, 1, 1);
} }
this._locations[i].timeLabel = time; this._locations[i].actor = time;
this._locations[i].tzLabel = tz;
} }
if (this._grid.get_n_children() > 1) { if (this._grid.get_n_children() > 1) {
if (!this._clockNotifyId) { if (!this._clockNotifyId) {
this._clockNotifyId = this._clockNotifyId =
this._clock.connect('notify::clock', this._updateTimeLabels.bind(this)); this._clock.connect('notify::clock', this._updateLabels.bind(this));
} }
if (!this._tzNotifyId) { this._updateLabels();
this._tzNotifyId =
this._clock.connect('notify::timezone', this._updateTimezoneLabels.bind(this));
}
this._updateTimeLabels();
this._updateTimezoneLabels();
} else { } else {
if (this._clockNotifyId) if (this._clockNotifyId)
this._clock.disconnect(this._clockNotifyId); this._clock.disconnect(this._clockNotifyId);
this._clockNotifyId = 0; this._clockNotifyId = 0;
if (this._tzNotifyId)
this._clock.disconnect(this._tzNotifyId);
this._tzNotifyId = 0;
} }
} }
_getTimezoneOffsetAtLocation(location) {
const localOffset = GLib.DateTime.new_now_local().get_utc_offset();
const utcOffset = this._getTimeAtLocation(location).get_utc_offset();
const offsetCurrentTz = utcOffset - localOffset;
const offsetHours = Math.abs(offsetCurrentTz) / GLib.TIME_SPAN_HOUR;
const offsetMinutes =
(Math.abs(offsetCurrentTz) % GLib.TIME_SPAN_HOUR) /
GLib.TIME_SPAN_MINUTE;
const prefix = offsetCurrentTz >= 0 ? '+' : '-';
const text = offsetMinutes === 0
? '%s%d'.format(prefix, offsetHours)
: '%s%d\u2236%d'.format(prefix, offsetHours, offsetMinutes);
return text;
}
_getTimeAtLocation(location) { _getTimeAtLocation(location) {
let tz = GLib.TimeZone.new(location.get_timezone().get_tzid()); let tz = GLib.TimeZone.new(location.get_timezone().get_tzid());
return GLib.DateTime.new_now(tz); return GLib.DateTime.new_now(tz);
} }
_updateTimeLabels() { _updateLabels() {
for (let i = 0; i < this._locations.length; i++) { for (let i = 0; i < this._locations.length; i++) {
let l = this._locations[i]; let l = this._locations[i];
let now = this._getTimeAtLocation(l.location); let now = this._getTimeAtLocation(l.location);
l.timeLabel.text = Util.formatTime(now, { timeOnly: true }); l.actor.text = Util.formatTime(now, { timeOnly: true });
}
}
_updateTimezoneLabels() {
for (let i = 0; i < this._locations.length; i++) {
let l = this._locations[i];
l.tzLabel.text = this._getTimezoneOffsetAtLocation(l.location);
} }
} }
@ -486,13 +281,13 @@ class WeatherSection extends St.Button {
this.child = box; this.child = box;
let titleBox = new St.BoxLayout({ style_class: 'weather-header-box' }); let titleBox = new St.BoxLayout({ style_class: 'weather-header-box' });
this._titleLabel = new St.Label({ titleBox.add_child(new St.Label({
style_class: 'weather-header', style_class: 'weather-header',
x_align: Clutter.ActorAlign.START, x_align: Clutter.ActorAlign.START,
x_expand: true, x_expand: true,
y_align: Clutter.ActorAlign.END, y_align: Clutter.ActorAlign.END,
}); text: _('Weather'),
titleBox.add_child(this._titleLabel); }));
box.add_child(titleBox); box.add_child(titleBox);
this._titleLocation = new St.Label({ this._titleLocation = new St.Label({
@ -619,8 +414,10 @@ class WeatherSection extends St.Button {
_updateForecasts() { _updateForecasts() {
this._forecastGrid.destroy_all_children(); this._forecastGrid.destroy_all_children();
if (!this._weatherClient.hasLocation) if (!this._weatherClient.hasLocation) {
this._setStatusLabel(_("Select a location…"));
return; return;
}
const { info } = this._weatherClient; const { info } = this._weatherClient;
this._titleLocation.text = this._findBestLocationName(info.location); this._titleLocation.text = this._findBestLocationName(info.location);
@ -647,12 +444,6 @@ class WeatherSection extends St.Button {
if (!this.visible) if (!this.visible)
return; return;
if (this._weatherClient.hasLocation)
this._titleLabel.text = _('Weather');
else
this._titleLabel.text = _('Select weather location…');
this._forecastGrid.visible = this._weatherClient.hasLocation;
this._titleLocation.visible = this._weatherClient.hasLocation; this._titleLocation.visible = this._weatherClient.hasLocation;
this._updateForecasts(); this._updateForecasts();
@ -671,6 +462,7 @@ class MessagesIndicator extends St.Icon {
this._sources = []; this._sources = [];
this._count = 0; this._count = 0;
this._doNotDisturb = false;
this._settings = new Gio.Settings({ this._settings = new Gio.Settings({
schema_id: 'org.gnome.desktop.notifications', schema_id: 'org.gnome.desktop.notifications',
@ -751,8 +543,8 @@ class FreezableBinLayout extends Clutter.BinLayout {
return this._savedHeight; return this._savedHeight;
} }
vfunc_allocate(container, allocation) { vfunc_allocate(container, allocation, flags) {
super.vfunc_allocate(container, allocation); super.vfunc_allocate(container, allocation, flags);
let [width, height] = allocation.get_size(); let [width, height] = allocation.get_size();
this._savedWidth = [width, width]; this._savedWidth = [width, width];
@ -784,7 +576,6 @@ class DateMenuButton extends PanelMenu.Button {
this._clockDisplay = new St.Label({ style_class: 'clock' }); this._clockDisplay = new St.Label({ style_class: 'clock' });
this._clockDisplay.clutter_text.y_align = Clutter.ActorAlign.CENTER; this._clockDisplay.clutter_text.y_align = Clutter.ActorAlign.CENTER;
this._clockDisplay.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._indicator = new MessagesIndicator(); this._indicator = new MessagesIndicator();
@ -819,7 +610,7 @@ class DateMenuButton extends PanelMenu.Button {
this._calendar.connect('selected-date-changed', (_calendar, datetime) => { this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
let date = _gDateTimeToDate(datetime); let date = _gDateTimeToDate(datetime);
layout.frozen = !_isToday(date); layout.frozen = !_isToday(date);
this._eventsItem.setDate(date); this._messageList.setDate(date);
}); });
this.menu.connect('open-state-changed', (menu, isOpen) => { this.menu.connect('open-state-changed', (menu, isOpen) => {
@ -828,7 +619,7 @@ class DateMenuButton extends PanelMenu.Button {
let now = new Date(); let now = new Date();
this._calendar.setDate(now); this._calendar.setDate(now);
this._date.setDate(now); this._date.setDate(now);
this._eventsItem.setDate(now); this._messageList.setDate(now);
} }
}); });
@ -859,9 +650,6 @@ class DateMenuButton extends PanelMenu.Button {
style_class: 'datemenu-displays-box' }); style_class: 'datemenu-displays-box' });
this._displaysSection.add_actor(displaysBox); this._displaysSection.add_actor(displaysBox);
this._eventsItem = new EventsSection();
displaysBox.add_child(this._eventsItem);
this._clocksItem = new WorldClocksSection(); this._clocksItem = new WorldClocksSection();
displaysBox.add_child(this._clocksItem); displaysBox.add_child(this._clocksItem);
@ -887,7 +675,7 @@ class DateMenuButton extends PanelMenu.Button {
this._eventSource.destroy(); this._eventSource.destroy();
this._calendar.setEventSource(eventSource); this._calendar.setEventSource(eventSource);
this._eventsItem.setEventSource(eventSource); this._messageList.setEventSource(eventSource);
this._eventSource = eventSource; this._eventSource = eventSource;
} }

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Dialog, MessageDialogContent, ListSection, ListSectionItem */ /* exported Dialog, MessageDialogContent, ListSection, ListSectionItem */
const { Clutter, GLib, GObject, Meta, Pango, St } = imports.gi; const { Clutter, GObject, Meta, Pango, St } = imports.gi;
function _setLabel(label, value) { function _setLabel(label, value) {
label.set({ label.set({
@ -221,16 +221,13 @@ var MessageDialogContent = GObject.registerClass({
this._updateTitleStyleLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { this._updateTitleStyleLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._updateTitleStyleLater = 0; this._updateTitleStyleLater = 0;
this._title.add_style_class_name('leightweight'); this._title.add_style_class_name('leightweight');
return GLib.SOURCE_REMOVE; return false;
}); });
} }
} }
set title(title) { set title(title) {
if (this._title.text === title)
return;
_setLabel(this._title, title); _setLabel(this._title, title);
this._title.remove_style_class_name('leightweight'); this._title.remove_style_class_name('leightweight');
@ -240,9 +237,6 @@ var MessageDialogContent = GObject.registerClass({
} }
set description(description) { set description(description) {
if (this._description.text === description)
return;
_setLabel(this._description, description); _setLabel(this._description, description);
this.notify('description'); this.notify('description');
} }

View File

@ -375,29 +375,19 @@ var _Draggable = class _Draggable {
this._dragActorSource = undefined; this._dragActorSource = undefined;
this._dragOrigParent = this.actor.get_parent(); this._dragOrigParent = this.actor.get_parent();
this._dragActorHadFixedPos = this._dragActor.fixed_position_set; this._dragOrigX = this._dragActor.x;
this._dragOrigX = this._dragActor.allocation.x1; this._dragOrigY = this._dragActor.y;
this._dragOrigY = this._dragActor.allocation.y1;
this._dragOrigWidth = this._dragActor.allocation.get_width();
this._dragOrigHeight = this._dragActor.allocation.get_height();
this._dragOrigScale = this._dragActor.scale_x; this._dragOrigScale = this._dragActor.scale_x;
// When the actor gets reparented to the uiGroup, it will be
// allocated its preferred size, so use that size instead of the
// current allocation size.
const [, newAllocatedWidth] = this._dragActor.get_preferred_width(-1);
const [, newAllocatedHeight] = this._dragActor.get_preferred_height(-1);
const transformedExtents = this._dragActor.get_transformed_extents();
// Set the actor's scale such that it will keep the same // Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the uiGroup // transformed size when it's reparented to the uiGroup
this._dragActor.set_scale( let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
transformedExtents.get_width() / newAllocatedWidth, this._dragActor.set_scale(scaledWidth / this.actor.width,
transformedExtents.get_height() / newAllocatedHeight); scaledHeight / this.actor.height);
this._dragOffsetX = transformedExtents.origin.x - this._dragStartX; let [actorStageX, actorStageY] = this.actor.get_transformed_position();
this._dragOffsetY = transformedExtents.origin.y - this._dragStartY; this._dragOffsetX = actorStageX - this._dragStartX;
this._dragOffsetY = actorStageY - this._dragStartY;
this._dragOrigParent.remove_actor(this._dragActor); this._dragOrigParent.remove_actor(this._dragActor);
Main.uiGroup.add_child(this._dragActor); Main.uiGroup.add_child(this._dragActor);
@ -427,10 +417,6 @@ var _Draggable = class _Draggable {
this._dragOffsetX -= transX; this._dragOffsetX -= transX;
this._dragOffsetY -= transY; this._dragOffsetY -= transY;
this._dragActor.set_position(
this._dragX + this._dragOffsetX,
this._dragY + this._dragOffsetY);
if (this._dragActorMaxSize != undefined) { if (this._dragActorMaxSize != undefined) {
let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size(); let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size();
let currentSize = Math.max(scaledWidth, scaledHeight); let currentSize = Math.max(scaledWidth, scaledHeight);
@ -649,15 +635,9 @@ var _Draggable = class _Draggable {
if (parentWidth != 0) if (parentWidth != 0)
parentScale = parentScaledWidth / parentWidth; parentScale = parentScaledWidth / parentWidth;
// Also adjust for the difference in the original actor width
// and the width it is now (children of uiGroup always get
// allocated their preferred size)
const childScaleX =
this._dragOrigWidth / this._dragActor.allocation.get_width();
x = parentX + parentScale * this._dragOrigX; x = parentX + parentScale * this._dragOrigX;
y = parentY + parentScale * this._dragOrigY; y = parentY + parentScale * this._dragOrigY;
scale = this._dragOrigScale * parentScale * childScaleX; scale = this._dragOrigScale * parentScale;
} else { } else {
// Snap back actor to its original stage position // Snap back actor to its original stage position
x = this._snapBackX; x = this._snapBackX;
@ -738,10 +718,7 @@ var _Draggable = class _Draggable {
Main.uiGroup.remove_child(this._dragActor); Main.uiGroup.remove_child(this._dragActor);
this._dragOrigParent.add_actor(this._dragActor); this._dragOrigParent.add_actor(this._dragActor);
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale); dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
if (this._dragActorHadFixedPos)
dragActor.set_position(this._dragOrigX, this._dragOrigY); dragActor.set_position(this._dragOrigX, this._dragOrigY);
else
dragActor.fixed_position_set = false;
} else { } else {
dragActor.destroy(); dragActor.destroy();
} }

View File

@ -18,7 +18,7 @@
*/ */
const { AccountsService, Clutter, Gio, const { AccountsService, Clutter, Gio,
GLib, GObject, Pango, Polkit, Shell, St, UPowerGlib: UPower } = imports.gi; GLib, GObject, Pango, Polkit, Shell, St } = imports.gi;
const CheckBox = imports.ui.checkBox; const CheckBox = imports.ui.checkBox;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
@ -31,30 +31,24 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
const _ITEM_ICON_SIZE = 64; const _ITEM_ICON_SIZE = 64;
const LOW_BATTERY_THRESHOLD = 30;
const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog'); const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog');
const logoutDialogContent = { const logoutDialogContent = {
subjectWithUser: C_("title", "Log Out %s"), subjectWithUser: C_("title", "Log Out %s"),
subject: C_("title", "Log Out"), subject: C_("title", "Log Out"),
descriptionWithUser(user, seconds) { descriptionWithUser(user, seconds) {
return ngettext( return ngettext("%s will be logged out automatically in %d second.",
'%s will be logged out automatically in %d second.', "%s will be logged out automatically in %d seconds.",
'%s will be logged out automatically in %d seconds.',
seconds).format(user, seconds); seconds).format(user, seconds);
}, },
description(seconds) { description(seconds) {
return ngettext( return ngettext("You will be logged out automatically in %d second.",
'You will be logged out automatically in %d second.', "You will be logged out automatically in %d seconds.",
'You will be logged out automatically in %d seconds.',
seconds).format(seconds); seconds).format(seconds);
}, },
showBatteryWarning: false, showBatteryWarning: false,
confirmButtons: [{ confirmButtons: [{ signal: 'ConfirmedLogout',
signal: 'ConfirmedLogout', label: C_("button", "Log Out") }],
label: C_('button', 'Log Out'),
}],
showOtherSessions: false, showOtherSessions: false,
}; };
@ -62,36 +56,30 @@ const shutdownDialogContent = {
subject: C_("title", "Power Off"), subject: C_("title", "Power Off"),
subjectWithUpdates: C_("title", "Install Updates & Power Off"), subjectWithUpdates: C_("title", "Install Updates & Power Off"),
description(seconds) { description(seconds) {
return ngettext( return ngettext("The system will power off automatically in %d second.",
'The system will power off automatically in %d second.', "The system will power off automatically in %d seconds.",
'The system will power off automatically in %d seconds.',
seconds).format(seconds); seconds).format(seconds);
}, },
checkBoxText: C_("checkbox", "Install pending software updates"), checkBoxText: C_("checkbox", "Install pending software updates"),
showBatteryWarning: true, showBatteryWarning: true,
confirmButtons: [{ confirmButtons: [{ signal: 'ConfirmedReboot',
signal: 'ConfirmedShutdown', label: C_("button", "Restart") },
label: C_('button', 'Power Off'), { signal: 'ConfirmedShutdown',
}], label: C_("button", "Power Off") }],
iconName: 'system-shutdown-symbolic', iconName: 'system-shutdown-symbolic',
showOtherSessions: true, showOtherSessions: true,
}; };
const restartDialogContent = { const restartDialogContent = {
subject: C_("title", "Restart"), subject: C_("title", "Restart"),
subjectWithUpdates: C_('title', 'Install Updates & Restart'),
description(seconds) { description(seconds) {
return ngettext( return ngettext("The system will restart automatically in %d second.",
'The system will restart automatically in %d second.', "The system will restart automatically in %d seconds.",
'The system will restart automatically in %d seconds.',
seconds).format(seconds); seconds).format(seconds);
}, },
checkBoxText: C_('checkbox', 'Install pending software updates'), showBatteryWarning: false,
showBatteryWarning: true, confirmButtons: [{ signal: 'ConfirmedReboot',
confirmButtons: [{ label: C_("button", "Restart") }],
signal: 'ConfirmedReboot',
label: C_('button', 'Restart'),
}],
iconName: 'view-refresh-symbolic', iconName: 'view-refresh-symbolic',
showOtherSessions: true, showOtherSessions: true,
}; };
@ -100,16 +88,13 @@ const restartUpdateDialogContent = {
subject: C_("title", "Restart & Install Updates"), subject: C_("title", "Restart & Install Updates"),
description(seconds) { description(seconds) {
return ngettext( return ngettext("The system will automatically restart and install updates in %d second.",
'The system will automatically restart and install updates in %d second.', "The system will automatically restart and install updates in %d seconds.",
'The system will automatically restart and install updates in %d seconds.',
seconds).format(seconds); seconds).format(seconds);
}, },
showBatteryWarning: true, showBatteryWarning: true,
confirmButtons: [{ confirmButtons: [{ signal: 'ConfirmedReboot',
signal: 'ConfirmedReboot', label: C_("button", "Restart &amp; Install") }],
label: C_('button', 'Restart &amp; Install'),
}],
unusedFutureButtonForTranslation: C_("button", "Install &amp; Power Off"), unusedFutureButtonForTranslation: C_("button", "Install &amp; Power Off"),
unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"), unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"),
iconName: 'view-refresh-symbolic', iconName: 'view-refresh-symbolic',
@ -127,10 +112,8 @@ const restartUpgradeDialogContent = {
}, },
disableTimer: true, disableTimer: true,
showBatteryWarning: false, showBatteryWarning: false,
confirmButtons: [{ confirmButtons: [{ signal: 'ConfirmedReboot',
signal: 'ConfirmedReboot', label: C_("button", "Restart &amp; Install") }],
label: C_('button', 'Restart &amp; Install'),
}],
iconName: 'view-refresh-symbolic', iconName: 'view-refresh-symbolic',
showOtherSessions: true, showOtherSessions: true,
}; };
@ -159,7 +142,7 @@ const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
const PkOfflineIface = loadInterfaceXML('org.freedesktop.PackageKit.Offline'); const PkOfflineIface = loadInterfaceXML('org.freedesktop.PackageKit.Offline');
const PkOfflineProxy = Gio.DBusProxy.makeProxyWrapper(PkOfflineIface); const PkOfflineProxy = Gio.DBusProxy.makeProxyWrapper(PkOfflineIface);
const UPowerIface = loadInterfaceXML('org.freedesktop.UPower.Device'); const UPowerIface = loadInterfaceXML('org.freedesktop.UPower');
const UPowerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerIface); const UPowerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerIface);
function findAppFromInhibitor(inhibitor) { function findAppFromInhibitor(inhibitor) {
@ -230,11 +213,6 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
destroyOnClose: false }); destroyOnClose: false });
this._loginManager = LoginManager.getLoginManager(); this._loginManager = LoginManager.getLoginManager();
this._loginManager.canRebootToBootLoaderMenu(
(canRebootToBootLoaderMenu, unusedNeedsAuth) => {
this._canRebootToBootLoaderMenu = canRebootToBootLoaderMenu;
});
this._userManager = AccountsService.UserManager.get_default(); this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name()); this._user = this._userManager.get_user(GLib.get_user_name());
this._updatesPermission = null; this._updatesPermission = null;
@ -246,7 +224,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._powerProxy = new UPowerProxy(Gio.DBus.system, this._powerProxy = new UPowerProxy(Gio.DBus.system,
'org.freedesktop.UPower', 'org.freedesktop.UPower',
'/org/freedesktop/UPower/devices/DisplayDevice', '/org/freedesktop/UPower',
(proxy, error) => { (proxy, error) => {
if (error) { if (error) {
log(error.message); log(error.message);
@ -261,9 +239,6 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._totalSecondsToStayOpen = 0; this._totalSecondsToStayOpen = 0;
this._applications = []; this._applications = [];
this._sessions = []; this._sessions = [];
this._capturedEventId = 0;
this._rebootButton = null;
this._rebootButtonAlt = null;
this.connect('destroy', this.connect('destroy',
this._onDestroy.bind(this)); this._onDestroy.bind(this));
@ -281,7 +256,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._batteryWarning = new St.Label({ this._batteryWarning = new St.Label({
style_class: 'end-session-dialog-battery-warning', style_class: 'end-session-dialog-battery-warning',
text: _('Low battery power: please plug in before installing updates.'), text: _('Running on battery power: Please plug in before installing updates.'),
}); });
this._batteryWarning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._batteryWarning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._batteryWarning.clutter_text.line_wrap = true; this._batteryWarning.clutter_text.line_wrap = true;
@ -303,7 +278,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog'); this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
} }
async _onPkOfflineProxyCreated(proxy, error) { _onPkOfflineProxyCreated(proxy, error) {
if (error) { if (error) {
log(error.message); log(error.message);
return; return;
@ -318,12 +293,15 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
// It only makes sense to check for this permission if PackageKit is available. // It only makes sense to check for this permission if PackageKit is available.
Polkit.Permission.new(
'org.freedesktop.packagekit.trigger-offline-update', null, null,
(source, res) => {
try { try {
this._updatesPermission = await Polkit.Permission.new( this._updatesPermission = Polkit.Permission.new_finish(res);
'org.freedesktop.packagekit.trigger-offline-update', null, null);
} catch (e) { } catch (e) {
log('No permission to trigger offline updates: %s'.format(e.toString())); log('No permission to trigger offline updates: %s'.format(e.toString()));
} }
});
} }
_onDestroy() { _onDestroy() {
@ -331,32 +309,6 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._user.disconnect(this._userChangedId); this._user.disconnect(this._userChangedId);
} }
_isDischargingBattery() {
return this._powerProxy.IsPresent &&
this._powerProxy.State !== UPower.DeviceState.CHARGING &&
this._powerProxy.State !== UPower.DeviceState.FULLY_CHARGED;
}
_isBatteryLow() {
return this._isDischargingBattery() && this._powerProxy.Percentage < LOW_BATTERY_THRESHOLD;
}
_shouldShowLowBatteryWarning(dialogContent) {
if (!dialogContent.showBatteryWarning)
return false;
if (!this._isBatteryLow())
return false;
if (this._checkBox.checked)
return true;
// Show the warning if updates have already been triggered, but
// the user doesn't have enough permissions to cancel them.
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
return this._updateInfo.UpdatePrepared && this._updateInfo.UpdateTriggered && !updatesAllowed;
}
_sync() { _sync() {
let open = this.state == ModalDialog.State.OPENING || this.state == ModalDialog.State.OPENED; let open = this.state == ModalDialog.State.OPENING || this.state == ModalDialog.State.OPENED;
if (!open) if (!open)
@ -370,7 +322,10 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
if (dialogContent.subjectWithUpdates && this._checkBox.checked) if (dialogContent.subjectWithUpdates && this._checkBox.checked)
subject = dialogContent.subjectWithUpdates; subject = dialogContent.subjectWithUpdates;
this._batteryWarning.visible = this._shouldShowLowBatteryWarning(dialogContent); if (dialogContent.showBatteryWarning) {
this._batteryWarning.visible =
this._powerProxy.OnBattery && this._checkBox.checked;
}
let description; let description;
let displayTime = _roundSecondsToInterval(this._totalSecondsToStayOpen, let displayTime = _roundSecondsToInterval(this._totalSecondsToStayOpen,
@ -411,38 +366,16 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._sessionSection.visible = hasSessions; this._sessionSection.visible = hasSessions;
} }
_onCapturedEvent(actor, event) {
let altEnabled = false;
let type = event.type();
if (type !== Clutter.EventType.KEY_PRESS && type !== Clutter.EventType.KEY_RELEASE)
return Clutter.EVENT_PROPAGATE;
let key = event.get_key_symbol();
if (key !== Clutter.KEY_Alt_L && key !== Clutter.KEY_Alt_R)
return Clutter.EVENT_PROPAGATE;
if (type === Clutter.EventType.KEY_PRESS)
altEnabled = true;
this._rebootButton.visible = !altEnabled;
this._rebootButtonAlt.visible = altEnabled;
return Clutter.EVENT_PROPAGATE;
}
_updateButtons() { _updateButtons() {
this.clearButtons();
this.addButton({ action: this.cancel.bind(this),
label: _("Cancel"),
key: Clutter.KEY_Escape });
let dialogContent = DialogContent[this._type]; let dialogContent = DialogContent[this._type];
let buttons = [{ action: this.cancel.bind(this),
label: _("Cancel"),
key: Clutter.KEY_Escape }];
for (let i = 0; i < dialogContent.confirmButtons.length; i++) { for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
let signal = dialogContent.confirmButtons[i].signal; let signal = dialogContent.confirmButtons[i].signal;
let label = dialogContent.confirmButtons[i].label; let label = dialogContent.confirmButtons[i].label;
let button = this.addButton({ buttons.push({
action: () => { action: () => {
this.close(true); this.close(true);
let signalId = this.connect('closed', () => { let signalId = this.connect('closed', () => {
@ -452,34 +385,9 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
}, },
label, label,
}); });
// Add Alt "Boot Options" option to the Reboot button
if (this._canRebootToBootLoaderMenu && signal === 'ConfirmedReboot') {
this._rebootButton = button;
this._rebootButtonAlt = this.addButton({
action: () => {
this.close(true);
let signalId = this.connect('closed', () => {
this.disconnect(signalId);
this._confirmRebootToBootLoaderMenu();
});
},
label: C_('button', 'Boot Options'),
});
this._rebootButtonAlt.visible = false;
this._capturedEventId = global.stage.connect('captured-event',
this._onCapturedEvent.bind(this));
}
}
} }
_stopAltCapture() { this.setButtons(buttons);
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
this._rebootButton = null;
this._rebootButtonAlt = null;
} }
close(skipSignal) { close(skipSignal) {
@ -491,21 +399,14 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
cancel() { cancel() {
this._stopTimer(); this._stopTimer();
this._stopAltCapture();
this._dbusImpl.emit_signal('Canceled', null); this._dbusImpl.emit_signal('Canceled', null);
this.close(); this.close();
} }
_confirmRebootToBootLoaderMenu() {
this._loginManager.setRebootToBootLoaderMenu();
this._confirm('ConfirmedReboot');
}
_confirm(signal) { _confirm(signal) {
let callback = () => { let callback = () => {
this._fadeOutDialog(); this._fadeOutDialog();
this._stopTimer(); this._stopTimer();
this._stopAltCapture();
this._dbusImpl.emit_signal(signal, null); this._dbusImpl.emit_signal(signal, null);
}; };
@ -773,17 +674,19 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
if (dialogContent.showOtherSessions) if (dialogContent.showOtherSessions)
this._loadSessions(); this._loadSessions();
let updateTriggered = this._updateInfo.UpdateTriggered;
let updatePrepared = this._updateInfo.UpdatePrepared;
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed; let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || ''); _setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
this._checkBox.visible = dialogContent.checkBoxText && this._updateInfo.UpdatePrepared && updatesAllowed; this._checkBox.visible = dialogContent.checkBoxText && updatePrepared && updatesAllowed;
this._checkBox.checked = this._checkBox.visible;
if (this._type === DialogType.UPGRADE_RESTART) // We show the warning either together with the checkbox, or when
this._checkBox.checked = this._checkBox.visible && this._updateInfo.UpdateTriggered && !this._isDischargingBattery(); // updates have already been triggered, but the user doesn't have
else // enough permissions to cancel them.
this._checkBox.checked = this._checkBox.visible && !this._isBatteryLow(); this._batteryWarning.visible = dialogContent.showBatteryWarning &&
(this._checkBox.visible || updatePrepared && updateTriggered && !updatesAllowed);
this._batteryWarning.visible = this._shouldShowLowBatteryWarning(dialogContent);
this._updateButtons(); this._updateButtons();

View File

@ -10,20 +10,11 @@ imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12'; imports.gi.versions.TelepathyGLib = '0.12';
imports.gi.versions.TelepathyLogger = '0.2'; imports.gi.versions.TelepathyLogger = '0.2';
const { Clutter, Gio, GLib, GObject, Meta, Polkit, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const System = imports.system; const System = imports.system;
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async', 'fill_finish');
Gio._promisify(Gio.DataInputStream.prototype,
'read_line_async', 'read_line_finish');
Gio._promisify(Gio.DBus, 'get', 'get_finish');
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish'); Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
Gio._promisify(Gio.DBusProxy, 'new', 'new_finish');
Gio._promisify(Gio.DBusProxy.prototype, 'init_async', 'init_finish');
Gio._promisify(Gio.DBusProxy.prototype,
'call_with_unix_fd_list', 'call_with_unix_fd_list_finish');
Gio._promisify(Polkit.Permission, 'new', 'new_finish');
let _localTimeZone = null; let _localTimeZone = null;
@ -134,14 +125,7 @@ function _easeActor(actor, params) {
actor.set_easing_mode(params.mode); actor.set_easing_mode(params.mode);
delete params.mode; delete params.mode;
const prepare = () => { let cleanup = () => Meta.enable_unredirect_for_display(global.display);
Meta.disable_unredirect_for_display(global.display);
global.begin_work();
};
const cleanup = () => {
Meta.enable_unredirect_for_display(global.display);
global.end_work();
};
let callback = _makeEaseCallback(params, cleanup); let callback = _makeEaseCallback(params, cleanup);
// cancel overwritten transitions // cancel overwritten transitions
@ -156,9 +140,9 @@ function _easeActor(actor, params) {
.find(t => t !== null); .find(t => t !== null);
if (transition && transition.delay) if (transition && transition.delay)
transition.connect('started', () => prepare()); transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
else else
prepare(); Meta.disable_unredirect_for_display(global.display);
if (transition) { if (transition) {
transition.set({ repeatCount, autoReverse }); transition.set({ repeatCount, autoReverse });
@ -198,14 +182,7 @@ function _easeActorProperty(actor, propName, target, params) {
if (actor instanceof Clutter.Actor && !actor.mapped) if (actor instanceof Clutter.Actor && !actor.mapped)
duration = 0; duration = 0;
const prepare = () => { let cleanup = () => Meta.enable_unredirect_for_display(global.display);
Meta.disable_unredirect_for_display(global.display);
global.begin_work();
};
const cleanup = () => {
Meta.enable_unredirect_for_display(global.display);
global.end_work();
};
let callback = _makeEaseCallback(params, cleanup); let callback = _makeEaseCallback(params, cleanup);
// cancel overwritten transition // cancel overwritten transition
@ -217,7 +194,7 @@ function _easeActorProperty(actor, propName, target, params) {
if (!isReversed) if (!isReversed)
obj[prop] = target; obj[prop] = target;
prepare(); Meta.disable_unredirect_for_display(global.display);
callback(true); callback(true);
return; return;
@ -236,9 +213,9 @@ function _easeActorProperty(actor, propName, target, params) {
transition.set_to(target); transition.set_to(target);
if (transition.delay) if (transition.delay)
transition.connect('started', () => prepare()); transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
else else
prepare(); Meta.disable_unredirect_for_display(global.display);
transition.connect('stopped', (t, finished) => callback(finished)); transition.connect('stopped', (t, finished) => callback(finished));
} }
@ -259,15 +236,16 @@ function _loggingFunc(...args) {
} }
function init() { function init() {
// Add some bindings to the global JS namespace // Add some bindings to the global JS namespace; (gjs keeps the web
globalThis.global = Shell.Global.get(); // browser convention of having that namespace be called 'window'.)
window.global = Shell.Global.get();
globalThis.log = _loggingFunc; window.log = _loggingFunc;
globalThis._ = Gettext.gettext; window._ = Gettext.gettext;
globalThis.C_ = Gettext.pgettext; window.C_ = Gettext.pgettext;
globalThis.ngettext = Gettext.ngettext; window.ngettext = Gettext.ngettext;
globalThis.N_ = s => s; window.N_ = s => s;
GObject.gtypeNameBasedOnJSPath = true; GObject.gtypeNameBasedOnJSPath = true;
@ -299,11 +277,6 @@ function init() {
_easeActorProperty(this, 'value', target, params); _easeActorProperty(this, 'value', target, params);
}; };
Clutter.Actor.prototype[Symbol.iterator] = function* () {
for (let c = this.get_first_child(); c; c = c.get_next_sibling())
yield c;
};
Clutter.Actor.prototype.toString = function () { Clutter.Actor.prototype.toString = function () {
return St.describe_actor(this); return St.describe_actor(this);
}; };
@ -374,12 +347,10 @@ function init() {
// OK, now things are initialized enough that we can import shell JS // OK, now things are initialized enough that we can import shell JS
const Format = imports.format; const Format = imports.format;
const Tweener = imports.ui.tweener;
Tweener.init();
String.prototype.format = Format.format; String.prototype.format = Format.format;
Math.clamp = function (x, lower, upper) {
return Math.min(Math.max(x, lower), upper);
};
} }
// adjustAnimationTime: // adjustAnimationTime:

View File

@ -139,9 +139,7 @@ function checkForUpdates() {
return; return;
if (extension.hasUpdate) if (extension.hasUpdate)
return; return;
metadatas[uuid] = { metadatas[uuid] = extension.metadata;
version: extension.metadata.version,
};
}); });
if (Object.keys(metadatas).length === 0) if (Object.keys(metadatas).length === 0)
@ -240,7 +238,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
}); });
function init() { function init() {
_httpSession = new Soup.Session({ ssl_use_system_ca_file: true }); _httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context. // See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
// _httpSession.add_feature(new Soup.ProxyResolverDefault()); // _httpSession.add_feature(new Soup.ProxyResolverDefault());

View File

@ -26,7 +26,6 @@ var ExtensionManager = class {
this._updateNotified = false; this._updateNotified = false;
this._extensions = new Map(); this._extensions = new Map();
this._unloadedExtensions = new Map();
this._enabledExtensions = []; this._enabledExtensions = [];
this._extensionOrder = []; this._extensionOrder = [];
@ -103,18 +102,18 @@ var ExtensionManager = class {
} }
} }
try {
extension.stateObj.disable();
} catch (e) {
this.logExtensionError(uuid, e);
}
if (extension.stylesheet) { if (extension.stylesheet) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(extension.stylesheet); theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet; delete extension.stylesheet;
} }
try {
extension.stateObj.disable();
} catch (e) {
this.logExtensionError(uuid, e);
}
for (let i = 0; i < order.length; i++) { for (let i = 0; i < order.length; i++) {
let otherUuid = order[i]; let otherUuid = order[i];
try { try {
@ -230,7 +229,8 @@ var ExtensionManager = class {
null, null,
Gio.DBusCallFlags.NONE, Gio.DBusCallFlags.NONE,
-1, -1,
null); null,
(conn, res) => conn.call_finish(res));
return true; return true;
} }
@ -260,8 +260,7 @@ var ExtensionManager = class {
if (!extension) if (!extension)
return; return;
const message = error instanceof Error let message = error.toString();
? error.message : error.toString();
extension.error = message; extension.error = message;
extension.state = ExtensionState.ERROR; extension.state = ExtensionState.ERROR;
@ -270,7 +269,6 @@ var ExtensionManager = class {
extension.errors.push(message); extension.errors.push(message);
logError(error, 'Extension %s'.format(uuid)); logError(error, 'Extension %s'.format(uuid));
this._updateCanChange(extension);
this.emit('extension-state-changed', extension); this.emit('extension-state-changed', extension);
} }
@ -320,14 +318,6 @@ var ExtensionManager = class {
return extension; return extension;
} }
_canLoad(extension) {
if (!this._unloadedExtensions.has(extension.uuid))
return true;
const version = this._unloadedExtensions.get(extension.uuid);
return extension.metadata.version === version;
}
loadExtension(extension) { loadExtension(extension) {
// Default to error, we set success as the last step // Default to error, we set success as the last step
extension.state = ExtensionState.ERROR; extension.state = ExtensionState.ERROR;
@ -336,9 +326,6 @@ var ExtensionManager = class {
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) { if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE; extension.state = ExtensionState.OUT_OF_DATE;
} else if (!this._canLoad(extension)) {
this.logExtensionError(extension.uuid, new Error(
'A different version was loaded previously. You need to log out for changes to take effect.'));
} else { } else {
let enabled = this._enabledExtensions.includes(extension.uuid); let enabled = this._enabledExtensions.includes(extension.uuid);
if (enabled) { if (enabled) {
@ -349,8 +336,6 @@ var ExtensionManager = class {
} else { } else {
extension.state = ExtensionState.INITIALIZED; extension.state = ExtensionState.INITIALIZED;
} }
this._unloadedExtensions.delete(extension.uuid);
} }
this._updateCanChange(extension); this._updateCanChange(extension);
@ -358,22 +343,15 @@ var ExtensionManager = class {
} }
unloadExtension(extension) { unloadExtension(extension) {
const { uuid, type } = extension;
// Try to disable it -- if it's ERROR'd, we can't guarantee that, // Try to disable it -- if it's ERROR'd, we can't guarantee that,
// but it will be removed on next reboot, and hopefully nothing // but it will be removed on next reboot, and hopefully nothing
// broke too much. // broke too much.
this._callExtensionDisable(uuid); this._callExtensionDisable(extension.uuid);
extension.state = ExtensionState.UNINSTALLED; extension.state = ExtensionState.UNINSTALLED;
this.emit('extension-state-changed', extension); this.emit('extension-state-changed', extension);
// If we did install an importer, it is now cached and it's this._extensions.delete(extension.uuid);
// impossible to load a different version
if (type === ExtensionType.PER_USER && extension.imports)
this._unloadedExtensions.set(uuid, extension.metadata.version);
this._extensions.delete(uuid);
return true; return true;
} }
@ -486,15 +464,19 @@ var ExtensionManager = class {
// Find and enable all the newly enabled extensions: UUIDs found in the // Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one. // new setting, but not in the old one.
newEnabledExtensions newEnabledExtensions.filter(
.filter(uuid => !this._enabledExtensions.includes(uuid)) uuid => !this._enabledExtensions.includes(uuid)
.forEach(uuid => this._callExtensionEnable(uuid)); ).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the // Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one. // old setting, but not in the new one.
this._extensionOrder this._extensionOrder.filter(
.filter(uuid => !newEnabledExtensions.includes(uuid)) uuid => !newEnabledExtensions.includes(uuid)
.reverse().forEach(uuid => this._callExtensionDisable(uuid)); ).reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions; this._enabledExtensions = newEnabledExtensions;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* exported InhibitShortcutsDialog */ /* exported InhibitShortcutsDialog */
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Pango, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
@ -7,7 +7,7 @@ const PermissionStore = imports.misc.permissionStore;
const WAYLAND_KEYBINDINGS_SCHEMA = 'org.gnome.mutter.wayland.keybindings'; const WAYLAND_KEYBINDINGS_SCHEMA = 'org.gnome.mutter.wayland.keybindings';
const APP_ALLOWLIST = ['gnome-control-center.desktop']; const APP_WHITELIST = ['gnome-control-center.desktop'];
const APP_PERMISSIONS_TABLE = 'gnome'; const APP_PERMISSIONS_TABLE = 'gnome';
const APP_PERMISSIONS_ID = 'shortcuts-inhibitor'; const APP_PERMISSIONS_ID = 'shortcuts-inhibitor';
const GRANTED = 'GRANTED'; const GRANTED = 'GRANTED';
@ -90,8 +90,6 @@ var InhibitShortcutsDialog = GObject.registerClass({
text: _('You can restore shortcuts by pressing %s.').format(restoreAccel), text: _('You can restore shortcuts by pressing %s.').format(restoreAccel),
style_class: 'message-dialog-description', style_class: 'message-dialog-description',
}); });
restoreLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
restoreLabel.clutter_text.line_wrap = true;
content.add_child(restoreLabel); content.add_child(restoreLabel);
} }
@ -118,7 +116,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
} }
vfunc_show() { vfunc_show() {
if (this._app && APP_ALLOWLIST.includes(this._app.get_id())) { if (this._app && APP_WHITELIST.includes(this._app.get_id())) {
this._emitResponse(DialogResponse.ALLOW); this._emitResponse(DialogResponse.ALLOW);
return; return;
} }

View File

@ -42,7 +42,7 @@ const defaultKeysPost = [
[[{ width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic' }], [[{ width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic' }],
[{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic' }], [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic' }],
[{ label: '=/<', width: 3, level: 3, right: true }], [{ label: '=/<', width: 3, level: 3, right: true }],
[{ action: 'emoji', icon: 'face-smile-symbolic' }, { action: 'languageMenu', extraClassName: 'layout-key', icon: 'keyboard-layout-filled-symbolic' }, { action: 'hide', extraClassName: 'hide-key', icon: 'go-down-symbolic' }]], [{ action: 'emoji', icon: 'face-smile-symbolic' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }]],
[[{ width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic' }], [[{ width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic' }],
[{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic' }], [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic' }],
[{ label: '?123', width: 3, level: 2, right: true }], [{ label: '?123', width: 3, level: 2, right: true }],
@ -61,25 +61,7 @@ class AspectContainer extends St.Widget {
this.queue_relayout(); this.queue_relayout();
} }
vfunc_get_preferred_width(forHeight) { vfunc_allocate(box, flags) {
let [min, nat] = super.vfunc_get_preferred_width(forHeight);
if (forHeight > 0)
nat = forHeight * this._ratio;
return [min, nat];
}
vfunc_get_preferred_height(forWidth) {
let [min, nat] = super.vfunc_get_preferred_height(forWidth);
if (forWidth > 0)
nat = forWidth / this._ratio;
return [min, nat];
}
vfunc_allocate(box) {
if (box.get_width() > 0 && box.get_height() > 0) { if (box.get_width() > 0 && box.get_height() > 0) {
let sizeRatio = box.get_width() / box.get_height(); let sizeRatio = box.get_width() / box.get_height();
@ -97,7 +79,7 @@ class AspectContainer extends St.Widget {
} }
} }
super.vfunc_allocate(box); super.vfunc_allocate(box, flags);
} }
}); });
@ -740,7 +722,7 @@ var EmojiPager = GObject.registerClass({
_onPan(action) { _onPan(action) {
let [dist_, dx, dy_] = action.get_motion_delta(0); let [dist_, dx, dy_] = action.get_motion_delta(0);
this.delta += dx; this.delta = this.delta + dx;
if (this._currentKey != null) { if (this._currentKey != null) {
this._currentKey.cancel(); this._currentKey.cancel();
@ -953,7 +935,8 @@ var EmojiSelection = GObject.registerClass({
this.add_child(this._emojiPager); this.add_child(this._emojiPager);
this._pageIndicator = new PageIndicators.PageIndicators( this._pageIndicator = new PageIndicators.PageIndicators(
Clutter.Orientation.HORIZONTAL); Clutter.Orientation.HORIZONTAL
);
this.add_child(this._pageIndicator); this.add_child(this._pageIndicator);
this._pageIndicator.setReactive(false); this._pageIndicator.setReactive(false);
@ -1091,8 +1074,8 @@ var Keypad = GObject.registerClass({
{ label: '8', keyval: Clutter.KEY_8, left: 1, top: 2 }, { label: '8', keyval: Clutter.KEY_8, left: 1, top: 2 },
{ label: '9', keyval: Clutter.KEY_9, left: 2, top: 2 }, { label: '9', keyval: Clutter.KEY_9, left: 2, top: 2 },
{ label: '0', keyval: Clutter.KEY_0, left: 1, top: 3 }, { label: '0', keyval: Clutter.KEY_0, left: 1, top: 3 },
{ keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic', left: 3, top: 0 }, { label: '⌫', keyval: Clutter.KEY_BackSpace, left: 3, top: 0 },
{ keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic', left: 3, top: 1, height: 2 }, { keyval: Clutter.KEY_Return, extraClassName: 'enter-key', left: 3, top: 1, height: 2 },
]; ];
super._init({ super._init({
@ -1109,7 +1092,7 @@ var Keypad = GObject.registerClass({
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
let cur = keys[i]; let cur = keys[i];
let key = new Key(cur.label || "", [], cur.icon); let key = new Key(cur.label || "", []);
if (keys[i].extraClassName) if (keys[i].extraClassName)
key.keyButton.add_style_class_name(cur.extraClassName); key.keyButton.add_style_class_name(cur.extraClassName);
@ -1136,7 +1119,7 @@ var KeyboardManager = class KeyBoardManager {
this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this)); this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
this._lastDevice = null; this._lastDevice = null;
global.backend.connect('last-device-changed', (backend, device) => { Meta.get_backend().connect('last-device-changed', (backend, device) => {
if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE) if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE)
return; return;
@ -1274,10 +1257,6 @@ class Keyboard extends St.BoxLayout {
return this._keyboardVisible && super.visible; return this._keyboardVisible && super.visible;
} }
set visible(visible) {
super.visible = visible;
}
_onFocusPositionChanged(focusTracker) { _onFocusPositionChanged(focusTracker) {
let rect = focusTracker.getCurrentRect(); let rect = focusTracker.getCurrentRect();
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height); this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
@ -1626,9 +1605,7 @@ class Keyboard extends St.BoxLayout {
* we allow the OSK being smaller than 1/3rd of the monitor height * we allow the OSK being smaller than 1/3rd of the monitor height
* there. * there.
*/ */
const forWidth = this.get_theme_node().adjust_for_width(monitor.width); this.height = Math.min(maxHeight, this.get_preferred_height(monitor.width));
const [, natHeight] = this.get_preferred_height(forWidth);
this.height = Math.min(maxHeight, natHeight);
} }
} }

View File

@ -6,6 +6,7 @@ const Signals = imports.signals;
const Background = imports.ui.background; const Background = imports.ui.background;
const BackgroundMenu = imports.ui.backgroundMenu; const BackgroundMenu = imports.ui.backgroundMenu;
const LoginManager = imports.misc.loginManager;
const DND = imports.ui.dnd; const DND = imports.ui.dnd;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -245,7 +246,7 @@ var LayoutManager = GObject.registerClass({
vertical: true }); vertical: true });
this.addChrome(this.panelBox, { affectsStruts: true, this.addChrome(this.panelBox, { affectsStruts: true,
trackFullscreen: true }); trackFullscreen: true });
this.panelBox.connect('notify::allocation', this.panelBox.connect('allocation-changed',
this._panelBoxChanged.bind(this)); this._panelBoxChanged.bind(this));
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup', this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
@ -294,6 +295,18 @@ var LayoutManager = GObject.registerClass({
monitorManager.connect('monitors-changed', monitorManager.connect('monitors-changed',
this._monitorsChanged.bind(this)); this._monitorsChanged.bind(this));
this._monitorsChanged(); 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 // This is called by Main after everything else is constructed
@ -457,15 +470,6 @@ var LayoutManager = GObject.registerClass({
} }
} }
_waitLoaded(bgManager) {
return new Promise(resolve => {
const id = bgManager.connect('loaded', () => {
bgManager.disconnect(id);
resolve();
});
});
}
_updateBackgrounds() { _updateBackgrounds() {
for (let i = 0; i < this._bgManagers.length; i++) for (let i = 0; i < this._bgManagers.length; i++)
this._bgManagers[i].destroy(); this._bgManagers[i].destroy();
@ -473,7 +477,7 @@ var LayoutManager = GObject.registerClass({
this._bgManagers = []; this._bgManagers = [];
if (Main.sessionMode.isGreeter) if (Main.sessionMode.isGreeter)
return Promise.resolve(); return;
for (let i = 0; i < this.monitors.length; i++) { for (let i = 0; i < this.monitors.length; i++) {
let bgManager = this._createBackgroundManager(i); let bgManager = this._createBackgroundManager(i);
@ -482,8 +486,6 @@ var LayoutManager = GObject.registerClass({
if (i != this.primaryIndex && this._startingUp) if (i != this.primaryIndex && this._startingUp)
bgManager.backgroundActor.hide(); bgManager.backgroundActor.hide();
} }
return Promise.all(this._bgManagers.map(this._waitLoaded));
} }
_updateKeyboardBox() { _updateKeyboardBox() {
@ -642,7 +644,7 @@ var LayoutManager = GObject.registerClass({
// When starting a normal user session, we want to grow it out of the middle // When starting a normal user session, we want to grow it out of the middle
// of the screen. // of the screen.
async _prepareStartupAnimation() { _prepareStartupAnimation() {
// During the initial transition, add a simple actor to block all events, // During the initial transition, add a simple actor to block all events,
// so they don't get delivered to X11 windows that have been transformed. // so they don't get delivered to X11 windows that have been transformed.
this._coverPane = new Clutter.Actor({ opacity: 0, this._coverPane = new Clutter.Actor({ opacity: 0,
@ -659,6 +661,8 @@ var LayoutManager = GObject.registerClass({
} else if (Main.sessionMode.isGreeter) { } else if (Main.sessionMode.isGreeter) {
this.panelBox.translation_y = -this.panelBox.height; this.panelBox.translation_y = -this.panelBox.height;
} else { } else {
this._updateBackgrounds();
// We need to force an update of the regions now before we scale // We need to force an update of the regions now before we scale
// the UI group to get the correct allocation for the struts. // the UI group to get the correct allocation for the struts.
this._updateRegions(); this._updateRegions();
@ -674,8 +678,6 @@ var LayoutManager = GObject.registerClass({
this.uiGroup.scale_x = this.uiGroup.scale_y = 0.75; this.uiGroup.scale_x = this.uiGroup.scale_y = 0.75;
this.uiGroup.opacity = 0; this.uiGroup.opacity = 0;
global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height); global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
await this._updateBackgrounds();
} }
this.emit('startup-prepared'); this.emit('startup-prepared');
@ -1202,8 +1204,7 @@ class HotCorner extends Clutter.Actor {
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
this._corner.set_position(this.width - this._corner.width, 0); this._corner.set_position(this.width - this._corner.width, 0);
this.set_pivot_point(1.0, 0.0); this.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
this.translation_x = -this.width;
} else { } else {
this._corner.set_position(0, 0); this._corner.set_position(0, 0);
} }
@ -1228,9 +1229,8 @@ class HotCorner extends Clutter.Actor {
return; return;
if (Main.overview.shouldToggleByCornerOrButton()) { if (Main.overview.shouldToggleByCornerOrButton()) {
Main.overview.toggle();
if (Main.overview.animationInProgress)
this._ripples.playAnimation(this._x, this._y); this._ripples.playAnimation(this._x, this._y);
Main.overview.toggle();
} }
} }

View File

@ -27,11 +27,13 @@ var RadialShaderEffect = GObject.registerClass({
'brightness': GObject.ParamSpec.float( 'brightness': GObject.ParamSpec.float(
'brightness', 'brightness', 'brightness', 'brightness', 'brightness', 'brightness',
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
0, 1, 1), 0, 1, 1
),
'sharpness': GObject.ParamSpec.float( 'sharpness': GObject.ParamSpec.float(
'sharpness', 'sharpness', 'sharpness', 'sharpness', 'sharpness', 'sharpness',
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
0, 1, 0), 0, 1, 0
),
}, },
}, class RadialShaderEffect extends Shell.GLSLEffect { }, class RadialShaderEffect extends Shell.GLSLEffect {
_init(params) { _init(params) {

View File

@ -37,9 +37,10 @@ const LG_ANIMATION_TIME = 500;
function _getAutoCompleteGlobalKeywords() { function _getAutoCompleteGlobalKeywords() {
const keywords = ['true', 'false', 'null', 'new']; const keywords = ['true', 'false', 'null', 'new'];
// Don't add the private properties of globalThis (i.e., ones starting with '_') // Don't add the private properties of window (i.e., ones starting with '_')
const windowProperties = Object.getOwnPropertyNames(globalThis).filter( const windowProperties = Object.getOwnPropertyNames(window).filter(
a => a.charAt(0) !== '_'); a => a.charAt(0) != '_'
);
const headerProperties = JsParse.getDeclaredConstants(commandHeader); const headerProperties = JsParse.getDeclaredConstants(commandHeader);
return keywords.concat(windowProperties).concat(headerProperties); return keywords.concat(windowProperties).concat(headerProperties);
@ -554,8 +555,8 @@ var Inspector = GObject.registerClass({
this._lookingGlass = lookingGlass; this._lookingGlass = lookingGlass;
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
this.set_allocation(box); this.set_allocation(box, flags);
if (!this._eventHandler) if (!this._eventHandler)
return; return;
@ -570,7 +571,7 @@ var Inspector = GObject.registerClass({
childBox.x2 = childBox.x1 + natWidth; childBox.x2 = childBox.x1 + natWidth;
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2); childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
childBox.y2 = childBox.y1 + natHeight; childBox.y2 = childBox.y1 + natHeight;
this._eventHandler.allocate(childBox); this._eventHandler.allocate(childBox, flags);
} }
_close() { _close() {
@ -802,191 +803,6 @@ var Extensions = GObject.registerClass({
} }
}); });
var ActorLink = GObject.registerClass({
Signals: {
'inspect-actor': {},
},
}, class ActorLink extends St.Button {
_init(actor) {
this._arrow = new St.Icon({
icon_name: 'pan-end-symbolic',
icon_size: 8,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
const label = new St.Label({
text: actor.toString(),
x_align: Clutter.ActorAlign.START,
});
const inspectButton = new St.Button({
child: new St.Icon({
icon_name: 'insert-object-symbolic',
icon_size: 12,
y_align: Clutter.ActorAlign.CENTER,
}),
reactive: true,
x_expand: true,
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER,
});
inspectButton.connect('clicked', () => this.emit('inspect-actor'));
const box = new St.BoxLayout();
box.add_child(this._arrow);
box.add_child(label);
box.add_child(inspectButton);
super._init({
reactive: true,
track_hover: true,
toggle_mode: true,
style_class: 'actor-link',
child: box,
x_align: Clutter.ActorAlign.START,
});
this._actor = actor;
}
vfunc_clicked() {
this._arrow.ease({
rotation_angle_z: this.checked ? 90 : 0,
duration: 250,
});
}
});
var ActorTreeViewer = GObject.registerClass(
class ActorTreeViewer extends St.BoxLayout {
_init(lookingGlass) {
super._init();
this._lookingGlass = lookingGlass;
this._actorData = new Map();
}
_showActorChildren(actor) {
const data = this._actorData.get(actor);
if (!data || data.visible)
return;
data.visible = true;
data.actorAddedId = actor.connect('actor-added', (container, child) => {
this._addActor(data.children, child);
});
data.actorRemovedId = actor.connect('actor-removed', (container, child) => {
this._removeActor(child);
});
for (let child of actor)
this._addActor(data.children, child);
}
_hideActorChildren(actor) {
const data = this._actorData.get(actor);
if (!data || !data.visible)
return;
for (let child of actor)
this._removeActor(child);
data.visible = false;
if (data.actorAddedId > 0) {
actor.disconnect(data.actorAddedId);
data.actorAddedId = 0;
}
if (data.actorRemovedId > 0) {
actor.disconnect(data.actorRemovedId);
data.actorRemovedId = 0;
}
data.children.remove_all_children();
}
_addActor(container, actor) {
if (this._actorData.has(actor))
return;
if (actor === this._lookingGlass)
return;
const button = new ActorLink(actor);
button.connect('notify::checked', () => {
this._lookingGlass.setBorderPaintTarget(actor);
if (button.checked)
this._showActorChildren(actor);
else
this._hideActorChildren(actor);
});
button.connect('inspect-actor', () => {
this._lookingGlass.inspectObject(actor, button);
});
const mainContainer = new St.BoxLayout({ vertical: true });
const childrenContainer = new St.BoxLayout({
vertical: true,
style: 'padding: 0 0 0 18px',
});
mainContainer.add_child(button);
mainContainer.add_child(childrenContainer);
this._actorData.set(actor, {
button,
container: mainContainer,
children: childrenContainer,
visible: false,
actorAddedId: 0,
actorRemovedId: 0,
actorDestroyedId: actor.connect('destroy', () => this._removeActor(actor)),
});
let belowChild = null;
const nextSibling = actor.get_next_sibling();
if (nextSibling && this._actorData.has(nextSibling))
belowChild = this._actorData.get(nextSibling).container;
container.insert_child_above(mainContainer, belowChild);
}
_removeActor(actor) {
const data = this._actorData.get(actor);
if (!data)
return;
for (let child of actor)
this._removeActor(child);
if (data.actorAddedId > 0) {
actor.disconnect(data.actorAddedId);
data.actorAddedId = 0;
}
if (data.actorRemovedId > 0) {
actor.disconnect(data.actorRemovedId);
data.actorRemovedId = 0;
}
if (data.actorDestroyedId > 0) {
actor.disconnect(data.actorDestroyedId);
data.actorDestroyedId = 0;
}
data.container.destroy();
this._actorData.delete(actor);
}
vfunc_map() {
super.vfunc_map();
this._addActor(this, global.stage);
}
vfunc_unmap() {
super.vfunc_unmap();
this._removeActor(global.stage);
}
});
var LookingGlass = GObject.registerClass( var LookingGlass = GObject.registerClass(
class LookingGlass extends St.BoxLayout { class LookingGlass extends St.BoxLayout {
_init() { _init() {
@ -1018,9 +834,9 @@ class LookingGlass extends St.BoxLayout {
Main.uiGroup.add_actor(this); Main.uiGroup.add_actor(this);
Main.uiGroup.set_child_below_sibling(this, Main.uiGroup.set_child_below_sibling(this,
Main.layoutManager.panelBox); Main.layoutManager.panelBox);
Main.layoutManager.panelBox.connect('notify::allocation', Main.layoutManager.panelBox.connect('allocation-changed',
this._queueResize.bind(this)); this._queueResize.bind(this));
Main.layoutManager.keyboardBox.connect('notify::allocation', Main.layoutManager.keyboardBox.connect('allocation-changed',
this._queueResize.bind(this)); this._queueResize.bind(this));
this._objInspector = new ObjInspector(this); this._objInspector = new ObjInspector(this);
@ -1102,9 +918,6 @@ class LookingGlass extends St.BoxLayout {
this._extensions = new Extensions(this); this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions); notebook.appendPage('Extensions', this._extensions);
this._actorTreeViewer = new ActorTreeViewer(this);
notebook.appendPage('Actors', this._actorTreeViewer);
this._entry.clutter_text.connect('activate', (o, _e) => { this._entry.clutter_text.connect('activate', (o, _e) => {
// Hide any completions we are currently showing // Hide any completions we are currently showing
this._hideCompletions(); this._hideCompletions();

View File

@ -489,10 +489,7 @@ var Magnifier = class Magnifier {
_updateMouseSprite() { _updateMouseSprite() {
this._updateSpriteTexture(); this._updateSpriteTexture();
let [xHot, yHot] = this._cursorTracker.get_hot(); let [xHot, yHot] = this._cursorTracker.get_hot();
this._mouseSprite.set({ this._mouseSprite.set_anchor_point(xHot, yHot);
translation_x: -xHot,
translation_y: -yHot,
});
} }
_updateSpriteTexture() { _updateSpriteTexture() {
@ -646,7 +643,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setClampScrollingAtEdges( this._zoomRegions[0].setClampScrollingAtEdges(
!this._settings.get_boolean(CLAMP_MODE_KEY)); !this._settings.get_boolean(CLAMP_MODE_KEY)
);
} }
} }
@ -654,7 +652,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setMouseTrackingMode( this._zoomRegions[0].setMouseTrackingMode(
this._settings.get_enum(MOUSE_TRACKING_KEY)); this._settings.get_enum(MOUSE_TRACKING_KEY)
);
} }
} }
@ -662,7 +661,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setFocusTrackingMode( this._zoomRegions[0].setFocusTrackingMode(
this._settings.get_enum(FOCUS_TRACKING_KEY)); this._settings.get_enum(FOCUS_TRACKING_KEY)
);
} }
} }
@ -670,7 +670,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setCaretTrackingMode( this._zoomRegions[0].setCaretTrackingMode(
this._settings.get_enum(CARET_TRACKING_KEY)); this._settings.get_enum(CARET_TRACKING_KEY)
);
} }
} }
@ -678,7 +679,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setInvertLightness( this._zoomRegions[0].setInvertLightness(
this._settings.get_boolean(INVERT_LIGHTNESS_KEY)); this._settings.get_boolean(INVERT_LIGHTNESS_KEY)
);
} }
} }
@ -686,7 +688,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setColorSaturation( this._zoomRegions[0].setColorSaturation(
this._settings.get_double(COLOR_SATURATION_KEY)); this._settings.get_double(COLOR_SATURATION_KEY)
);
} }
} }
@ -1938,8 +1941,9 @@ var MagShaderEffects = class MagShaderEffects {
// it modifies the brightness and/or contrast. // it modifies the brightness and/or contrast.
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast(); let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
this._brightnessContrast.set_enabled( this._brightnessContrast.set_enabled(
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE || bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE ||
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE); cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE
);
} }
/** /**
@ -1966,7 +1970,8 @@ var MagShaderEffects = class MagShaderEffects {
// a null first argument. // a null first argument.
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness(); let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
this._brightnessContrast.set_enabled( this._brightnessContrast.set_enabled(
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE || cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE ||
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE); bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE
);
} }
}; };

View File

@ -3,10 +3,10 @@
ctrlAltTabManager, padOsdService, osdWindowManager, ctrlAltTabManager, padOsdService, osdWindowManager,
osdMonitorLabeler, shellMountOpDBusService, shellDBusService, osdMonitorLabeler, shellMountOpDBusService, shellDBusService,
shellAccessDialogDBusService, shellAudioSelectionDBusService, shellAccessDialogDBusService, shellAudioSelectionDBusService,
screenSaverDBus, uiGroup, magnifier, xdndHandler, keyboard, screenSaverDBus, screencastService, uiGroup, magnifier,
kbdA11yDialog, introspectService, start, pushModal, popModal, xdndHandler, keyboard, kbdA11yDialog, introspectService,
activateWindow, createLookingGlass, initializeDeferredWork, start, pushModal, popModal, activateWindow, createLookingGlass,
getThemeStylesheet, setThemeStylesheet */ initializeDeferredWork, getThemeStylesheet, setThemeStylesheet */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
@ -34,6 +34,7 @@ const LoginManager = imports.misc.loginManager;
const LookingGlass = imports.ui.lookingGlass; const LookingGlass = imports.ui.lookingGlass;
const NotificationDaemon = imports.ui.notificationDaemon; const NotificationDaemon = imports.ui.notificationDaemon;
const WindowAttentionHandler = imports.ui.windowAttentionHandler; const WindowAttentionHandler = imports.ui.windowAttentionHandler;
const Screencast = imports.ui.screencast;
const ScreenShield = imports.ui.screenShield; const ScreenShield = imports.ui.screenShield;
const Scripting = imports.ui.scripting; const Scripting = imports.ui.scripting;
const SessionMode = imports.ui.sessionMode; const SessionMode = imports.ui.sessionMode;
@ -45,7 +46,6 @@ const XdndHandler = imports.ui.xdndHandler;
const KbdA11yDialog = imports.ui.kbdA11yDialog; const KbdA11yDialog = imports.ui.kbdA11yDialog;
const LocatePointer = imports.ui.locatePointer; const LocatePointer = imports.ui.locatePointer;
const PointerA11yTimeout = imports.ui.pointerA11yTimeout; const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
const ParentalControlsManager = imports.misc.parentalControlsManager;
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard'; const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const STICKY_KEYS_ENABLE = 'stickykeys-enable'; const STICKY_KEYS_ENABLE = 'stickykeys-enable';
@ -73,6 +73,7 @@ var shellAudioSelectionDBusService = null;
var shellDBusService = null; var shellDBusService = null;
var shellMountOpDBusService = null; var shellMountOpDBusService = null;
var screenSaverDBus = null; var screenSaverDBus = null;
var screencastService = null;
var modalCount = 0; var modalCount = 0;
var actionMode = Shell.ActionMode.NONE; var actionMode = Shell.ActionMode.NONE;
var modalActorFocusStack = []; var modalActorFocusStack = [];
@ -95,8 +96,6 @@ let _oskResource = null;
Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish'); Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish');
Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish'); Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
let _remoteAccessInhibited = false;
function _sessionUpdated() { function _sessionUpdated() {
if (sessionMode.isPrimary) if (sessionMode.isPrimary)
_loadDefaultStylesheet(); _loadDefaultStylesheet();
@ -121,23 +120,12 @@ function _sessionUpdated() {
if (lookingGlass) if (lookingGlass)
lookingGlass.close(); lookingGlass.close();
} }
let remoteAccessController = global.backend.get_remote_access_controller();
if (remoteAccessController) {
if (sessionMode.allowScreencast && _remoteAccessInhibited) {
remoteAccessController.uninhibit_remote_access();
_remoteAccessInhibited = false;
} else if (!sessionMode.allowScreencast && !_remoteAccessInhibited) {
remoteAccessController.inhibit_remote_access();
_remoteAccessInhibited = true;
}
}
} }
function start() { function start() {
// These are here so we don't break compatibility. // These are here so we don't break compatibility.
global.logError = globalThis.log; global.logError = window.log;
global.log = globalThis.log; global.log = window.log;
// Chain up async errors reported from C // Chain up async errors reported from C
global.connect('notify-error', (global, msg, detail) => { global.connect('notify-error', (global, msg, detail) => {
@ -152,10 +140,6 @@ function start() {
sessionMode.connect('updated', _sessionUpdated); sessionMode.connect('updated', _sessionUpdated);
St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet); St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
// Initialize ParentalControlsManager before the UI
ParentalControlsManager.getDefault();
_initializeUI(); _initializeUI();
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus(); shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
@ -198,6 +182,7 @@ function _initializeUI() {
uiGroup = layoutManager.uiGroup; uiGroup = layoutManager.uiGroup;
padOsdService = new PadOsd.PadOsdService(); padOsdService = new PadOsd.PadOsdService();
screencastService = new Screencast.ScreencastService();
xdndHandler = new XdndHandler.XdndHandler(); xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager(); ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
osdWindowManager = new OsdWindow.OsdWindowManager(); osdWindowManager = new OsdWindow.OsdWindowManager();
@ -536,9 +521,7 @@ function pushModal(actor, params) {
let prevFocusDestroyId; let prevFocusDestroyId;
if (prevFocus != null) { if (prevFocus != null) {
prevFocusDestroyId = prevFocus.connect('destroy', () => { prevFocusDestroyId = prevFocus.connect('destroy', () => {
const index = modalActorFocusStack.findIndex( let index = _findModal(actor);
record => record.prevFocus === prevFocus);
if (index >= 0) if (index >= 0)
modalActorFocusStack[index].prevFocus = null; modalActorFocusStack[index].prevFocus = null;
}); });
@ -814,7 +797,7 @@ function showRestartMessage(message) {
var AnimationsSettings = class { var AnimationsSettings = class {
constructor() { constructor() {
let backend = global.backend; let backend = Meta.get_backend();
if (!backend.is_rendering_hardware_accelerated()) { if (!backend.is_rendering_hardware_accelerated()) {
St.Settings.get().inhibit_animations(); St.Settings.get().inhibit_animations();
return; return;

View File

@ -4,6 +4,7 @@ const { Atk, Clutter, Gio, GLib,
const Main = imports.ui.main; const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray; const MessageTray = imports.ui.messageTray;
const Calendar = imports.ui.calendar;
const Util = imports.misc.util; const Util = imports.misc.util;
var MESSAGE_ANIMATION_TIME = 100; var MESSAGE_ANIMATION_TIME = 100;
@ -284,12 +285,12 @@ var LabelExpanderLayout = GObject.registerClass({
return [min, nat]; return [min, nat];
} }
vfunc_allocate(container, box) { vfunc_allocate(container, box, flags) {
for (let i = 0; i < container.get_n_children(); i++) { for (let i = 0; i < container.get_n_children(); i++) {
let child = container.get_child_at_index(i); let child = container.get_child_at_index(i);
if (child.visible) if (child.visible)
child.allocate(box); child.allocate(box, flags);
} }
} }
@ -571,6 +572,7 @@ var MessageListSection = GObject.registerClass({
Main.sessionMode.disconnect(id); Main.sessionMode.disconnect(id);
}); });
this._date = new Date();
this._empty = true; this._empty = true;
this._canClear = false; this._canClear = false;
this._sync(); this._sync();
@ -596,6 +598,13 @@ var MessageListSection = GObject.registerClass({
return true; return true;
} }
setDate(date) {
if (Calendar.sameDay(date, this._date))
return;
this._date = date;
this._sync();
}
addMessage(message, animate) { addMessage(message, animate) {
this.addMessageAtIndex(message, -1, animate); this.addMessageAtIndex(message, -1, animate);
} }

View File

@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NotificationPolicy, NotificationGenericPolicy, /* exported NotificationPolicy, NotificationGenericPolicy,
NotificationApplicationPolicy, Source, SourceActor, NotificationApplicationPolicy, Source, SourceActor, SourceActorWithLabel,
SystemNotificationSource, MessageTray */ SystemNotificationSource, MessageTray */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
@ -136,22 +136,29 @@ var FocusGrabber = class FocusGrabber {
var NotificationPolicy = GObject.registerClass({ var NotificationPolicy = GObject.registerClass({
Properties: { Properties: {
'enable': GObject.ParamSpec.boolean( 'enable': GObject.ParamSpec.boolean(
'enable', 'enable', 'enable', GObject.ParamFlags.READABLE, true), 'enable', 'enable', 'enable',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'enable-sound': GObject.ParamSpec.boolean( 'enable-sound': GObject.ParamSpec.boolean(
'enable-sound', 'enable-sound', 'enable-sound', 'enable-sound', 'enable-sound', 'enable-sound',
GObject.ParamFlags.READABLE, true), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'show-banners': GObject.ParamSpec.boolean( 'show-banners': GObject.ParamSpec.boolean(
'show-banners', 'show-banners', 'show-banners', 'show-banners', 'show-banners', 'show-banners',
GObject.ParamFlags.READABLE, true), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'force-expanded': GObject.ParamSpec.boolean( 'force-expanded': GObject.ParamSpec.boolean(
'force-expanded', 'force-expanded', 'force-expanded', 'force-expanded', 'force-expanded', 'force-expanded',
GObject.ParamFlags.READABLE, false), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'show-in-lock-screen': GObject.ParamSpec.boolean( 'show-in-lock-screen': GObject.ParamSpec.boolean(
'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen',
GObject.ParamFlags.READABLE, false), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'details-in-lock-screen': GObject.ParamSpec.boolean( 'details-in-lock-screen': GObject.ParamSpec.boolean(
'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen',
GObject.ParamFlags.READABLE, false), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
}, },
}, class NotificationPolicy extends GObject.Object { }, class NotificationPolicy extends GObject.Object {
// Do nothing for the default policy. These methods are only useful for the // Do nothing for the default policy. These methods are only useful for the
@ -162,28 +169,24 @@ var NotificationPolicy = GObject.registerClass({
this.run_dispose(); this.run_dispose();
} }
get enable() {
return true;
}
get enableSound() { get enableSound() {
return true; return this.enable_sound;
} }
get showBanners() { get showBanners() {
return true; return this.show_banners;
} }
get forceExpanded() { get forceExpanded() {
return false; return this.force_expanded;
} }
get showInLockScreen() { get showInLockScreen() {
return false; return this.show_in_lock_screen;
} }
get detailsInLockScreen() { get detailsInLockScreen() {
return false; return this.details_in_lock_screen;
} }
}); });
@ -655,6 +658,77 @@ class SourceActor extends St.Widget {
} }
}); });
var SourceActorWithLabel = GObject.registerClass(
class SourceActorWithLabel extends SourceActor {
_init(source, size) {
super._init(source, size);
this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
child: this._counterLabel,
layout_manager: new Clutter.BinLayout() });
this._counterBin.hide();
this._counterBin.connect('style-changed', () => {
let themeNode = this._counterBin.get_theme_node();
this._counterBin.translation_x = themeNode.get_length('-shell-counter-overlap-x');
this._counterBin.translation_y = themeNode.get_length('-shell-counter-overlap-y');
});
this.add_actor(this._counterBin);
this._countUpdatedId = this._source.connect('notify::count', this._updateCount.bind(this));
this._updateCount();
this.connect('destroy', () => {
this._source.disconnect(this._countUpdatedId);
});
}
vfunc_allocate(box, flags) {
super.vfunc_allocate(box, flags);
let childBox = new Clutter.ActorBox();
let [, , naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
let direction = this.get_text_direction();
if (direction == Clutter.TextDirection.LTR) {
// allocate on the right in LTR
childBox.x1 = box.x2 - naturalWidth;
childBox.x2 = box.x2;
} else {
// allocate on the left in RTL
childBox.x1 = 0;
childBox.x2 = naturalWidth;
}
childBox.y1 = box.y2 - naturalHeight;
childBox.y2 = box.y2;
this._counterBin.allocate(childBox, flags);
}
_updateCount() {
if (this._actorDestroyed)
return;
this._counterBin.visible = this._source.countVisible;
let text;
if (this._source.count < 100)
text = this._source.count.toString();
else
text = String.fromCharCode(0x22EF); // midline horizontal ellipsis
this._counterLabel.set_text(text);
}
});
var Source = GObject.registerClass({ var Source = GObject.registerClass({
Properties: { Properties: {
'count': GObject.ParamSpec.int( 'count': GObject.ParamSpec.int(
@ -1093,7 +1167,8 @@ var MessageTray = GObject.registerClass({
this._onNotificationDestroy.bind(this)); this._onNotificationDestroy.bind(this));
this._notificationQueue.push(notification); this._notificationQueue.push(notification);
this._notificationQueue.sort( this._notificationQueue.sort(
(n1, n2) => n2.urgency - n1.urgency); (n1, n2) => n2.urgency - n1.urgency
);
this.emit('queue-changed'); this.emit('queue-changed');
} }
} }

View File

@ -2,6 +2,7 @@
const { Gio, GObject, Shell, St } = imports.gi; const { Gio, GObject, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Calendar = imports.ui.calendar;
const Main = imports.ui.main; const Main = imports.ui.main;
const MessageList = imports.ui.messageList; const MessageList = imports.ui.messageList;
@ -172,11 +173,6 @@ var MprisPlayer = class MprisPlayer {
if (!this._mprisProxy.g_name_owner) if (!this._mprisProxy.g_name_owner)
this._close(); this._close();
}); });
// It is possible for the bus to disappear before the previous signal
// is connected, so we must ensure that the bus still exists at this
// point.
if (!this._mprisProxy.g_name_owner)
this._close();
} }
_onPlayerProxyReady() { _onPlayerProxyReady() {
@ -251,6 +247,10 @@ class MediaSection extends MessageList.MessageListSection {
this._onProxyReady.bind(this)); this._onProxyReady.bind(this));
} }
_shouldShow() {
return !this.empty && Calendar.isToday(this._date);
}
get allowed() { get allowed() {
return !Main.sessionMode.isGreeter; return !Main.sessionMode.isGreeter;
} }

View File

@ -10,6 +10,13 @@ const Params = imports.misc.params;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
// Should really be defined in Gio.js
const BusIface = loadInterfaceXML('org.freedesktop.DBus');
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
function Bus() {
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
}
const FdoNotificationsIface = loadInterfaceXML('org.freedesktop.Notifications'); const FdoNotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
var NotificationClosedReason = { var NotificationClosedReason = {
@ -42,7 +49,9 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications'); this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = []; this._sources = [];
this._senderToPid = {};
this._notifications = {}; this._notifications = {};
this._busProxy = new Bus();
this._nextNotificationId = 1; this._nextNotificationId = 1;
@ -107,9 +116,12 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
// //
// If no existing source is found, a new source is created as long as // If no existing source is found, a new source is created as long as
// pid is provided. // pid is provided.
//
// Either a pid or ndata.notification is needed to retrieve or
// create a source.
_getSource(title, pid, ndata, sender) { _getSource(title, pid, ndata, sender) {
if (!pid && !(ndata && ndata.notification)) if (!pid && !(ndata && ndata.notification))
throw new Error('Either a pid or ndata.notification is needed'); return null;
// We use notification's source for the notifications we still have // We use notification's source for the notifications we still have
// around that are getting replaced because we don't keep sources // around that are getting replaced because we don't keep sources
@ -206,10 +218,42 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
this._notifications[id] = ndata; this._notifications[id] = ndata;
let sender = invocation.get_sender(); let sender = invocation.get_sender();
let pid = hints['sender-pid']; let pid = this._senderToPid[sender];
let source = this._getSource(appName, pid, ndata, sender, null); let source = this._getSource(appName, pid, ndata, sender, null);
if (source) {
this._notifyForSource(source, ndata); this._notifyForSource(source, ndata);
return invocation.return_value(GLib.Variant.new('(u)', [id]));
}
if (replacesId) {
// There's already a pending call to GetConnectionUnixProcessID,
// which will see the new notification data when it finishes,
// so we don't have to do anything.
return invocation.return_value(GLib.Variant.new('(u)', [id]));
}
this._busProxy.GetConnectionUnixProcessIDRemote(sender, (result, excp) => {
// The app may have updated or removed the notification
ndata = this._notifications[id];
if (!ndata)
return;
if (excp) {
logError(excp, 'Call to GetConnectionUnixProcessID failed');
return;
}
[pid] = result;
source = this._getSource(appName, pid, ndata, sender, null);
this._senderToPid[sender] = pid;
source.connect('destroy', () => {
delete this._senderToPid[sender];
});
this._notifyForSource(source, ndata);
});
return invocation.return_value(GLib.Variant.new('(u)', [id])); return invocation.return_value(GLib.Variant.new('(u)', [id]));
} }
@ -373,11 +417,12 @@ var FdoNotificationDaemonSource = GObject.registerClass(
class FdoNotificationDaemonSource extends MessageTray.Source { class FdoNotificationDaemonSource extends MessageTray.Source {
_init(title, pid, sender, appId) { _init(title, pid, sender, appId) {
this.pid = pid; this.pid = pid;
this.initialTitle = title;
this.app = this._getApp(appId); this.app = this._getApp(appId);
super._init(title); super._init(title);
this.initialTitle = title;
if (this.app) if (this.app)
this.title = this.app.get_name(); this.title = this.app.get_name();
else else
@ -425,22 +470,21 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
} }
_getApp(appId) { _getApp(appId) {
const appSys = Shell.AppSystem.get_default();
let app; let app;
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid); app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
if (app != null) if (app != null)
return app; return app;
if (appId) if (appId) {
app = appSys.lookup_app('%s.desktop'.format(appId)); app = Shell.AppSystem.get_default().lookup_app('%s.desktop'.format(appId));
if (app != null)
if (!app)
app = appSys.lookup_app('%s.desktop'.format(this.initialTitle));
return app; return app;
} }
return null;
}
setTitle(title) { setTitle(title) {
// Do nothing if .app is set, we don't want to override the // Do nothing if .app is set, we don't want to override the
// app name with whatever is provided through libnotify (usually // app name with whatever is provided through libnotify (usually

View File

@ -4,10 +4,6 @@
const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
// Time for initial animation going into Overview mode;
// this is defined here to make it available in imports.
var ANIMATION_TIME = 250;
const Background = imports.ui.background; const Background = imports.ui.background;
const DND = imports.ui.dnd; const DND = imports.ui.dnd;
const LayoutManager = imports.ui.layout; const LayoutManager = imports.ui.layout;
@ -18,6 +14,9 @@ const OverviewControls = imports.ui.overviewControls;
const Params = imports.misc.params; const Params = imports.misc.params;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail; const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
var ANIMATION_TIME = 250;
// Must be less than ANIMATION_TIME, since we switch to // Must be less than ANIMATION_TIME, since we switch to
// or from the overview completely after ANIMATION_TIME, // or from the overview completely after ANIMATION_TIME,
// and don't want the shading animation to get cut off // and don't want the shading animation to get cut off
@ -245,11 +244,11 @@ var Overview = class {
_unshadeBackgrounds() { _unshadeBackgrounds() {
let backgrounds = this._backgroundGroup.get_children(); let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) { for (let i = 0; i < backgrounds.length; i++) {
backgrounds[i].ease_property('@content.brightness', 1.0, { backgrounds[i].ease_property('brightness', 1.0, {
duration: SHADE_ANIMATION_TIME, duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
}); });
backgrounds[i].ease_property('@content.vignette-sharpness', 0.0, { backgrounds[i].ease_property('vignette-sharpness', 0.0, {
duration: SHADE_ANIMATION_TIME, duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
}); });
@ -259,13 +258,11 @@ var Overview = class {
_shadeBackgrounds() { _shadeBackgrounds() {
let backgrounds = this._backgroundGroup.get_children(); let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) { for (let i = 0; i < backgrounds.length; i++) {
backgrounds[i].ease_property('@content.brightness', backgrounds[i].ease_property('brightness', Lightbox.VIGNETTE_BRIGHTNESS, {
Lightbox.VIGNETTE_BRIGHTNESS, {
duration: SHADE_ANIMATION_TIME, duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
}); });
backgrounds[i].ease_property('@content.vignette-sharpness', backgrounds[i].ease_property('vignette-sharpness', Lightbox.VIGNETTE_SHARPNESS, {
Lightbox.VIGNETTE_SHARPNESS, {
duration: SHADE_ANIMATION_TIME, duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
}); });
@ -403,7 +400,8 @@ var Overview = class {
_getDesktopClone() { _getDesktopClone() {
let windows = global.get_window_actors().filter( let windows = global.get_window_actors().filter(
w => w.meta_window.get_window_type() === Meta.WindowType.DESKTOP); w => w.meta_window.get_window_type() == Meta.WindowType.DESKTOP
);
if (windows.length == 0) if (windows.length == 0)
return null; return null;
@ -440,19 +438,19 @@ var Overview = class {
this.emit('windows-restacked', stackIndices); this.emit('windows-restacked', stackIndices);
} }
beginItemDrag(source) { beginItemDrag(_source) {
this.emit('item-drag-begin', source); this.emit('item-drag-begin');
this._inItemDrag = true; this._inItemDrag = true;
} }
cancelledItemDrag(source) { cancelledItemDrag(_source) {
this.emit('item-drag-cancelled', source); this.emit('item-drag-cancelled');
} }
endItemDrag(source) { endItemDrag(_source) {
if (!this._inItemDrag) if (!this._inItemDrag)
return; return;
this.emit('item-drag-end', source); this.emit('item-drag-end');
this._inItemDrag = false; this._inItemDrag = false;
} }
@ -578,7 +576,7 @@ var Overview = class {
this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC; this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
Meta.disable_unredirect_for_display(global.display); Meta.disable_unredirect_for_display(global.display);
this.viewSelector.animateToOverview(); this.viewSelector.show();
this._overview.opacity = 0; this._overview.opacity = 0;
this._overview.ease({ this._overview.ease({

View File

@ -8,9 +8,8 @@ const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const ViewSelector = imports.ui.viewSelector; const ViewSelector = imports.ui.viewSelector;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail; const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
const Overview = imports.ui.overview;
var SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME; var SIDE_CONTROLS_ANIMATION_TIME = 160;
function getRtlSlideDirection(direction, actor) { function getRtlSlideDirection(direction, actor) {
let rtl = actor.text_direction == Clutter.TextDirection.RTL; let rtl = actor.text_direction == Clutter.TextDirection.RTL;
@ -52,7 +51,7 @@ var SlideLayout = GObject.registerClass({
return [minWidth, natWidth]; return [minWidth, natWidth];
} }
vfunc_allocate(container, box) { vfunc_allocate(container, box, flags) {
let child = container.get_first_child(); let child = container.get_first_child();
let availWidth = Math.round(box.x2 - box.x1); let availWidth = Math.round(box.x2 - box.x1);
@ -73,7 +72,7 @@ var SlideLayout = GObject.registerClass({
actorBox.y1 = box.y1; actorBox.y1 = box.y1;
actorBox.y2 = actorBox.y1 + availHeight; actorBox.y2 = actorBox.y1 + availHeight;
child.allocate(actorBox); child.allocate(actorBox, flags);
} }
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
@ -395,10 +394,10 @@ class DashSpacer extends St.Widget {
}); });
var ControlsLayout = GObject.registerClass({ var ControlsLayout = GObject.registerClass({
Signals: { 'allocation-changed': {} }, Signals: { 'allocation-changed': { flags: GObject.SignalFlags.RUN_LAST } },
}, class ControlsLayout extends Clutter.BinLayout { }, class ControlsLayout extends Clutter.BinLayout {
vfunc_allocate(container, box) { vfunc_allocate(container, box, flags) {
super.vfunc_allocate(container, box); super.vfunc_allocate(container, box, flags);
this.emit('allocation-changed'); this.emit('allocation-changed');
} }
}); });
@ -423,7 +422,6 @@ class ControlsManager extends St.Widget {
let activeWorkspaceIndex = workspaceManager.get_active_workspace_index(); let activeWorkspaceIndex = workspaceManager.get_active_workspace_index();
this._workspaceAdjustment = new St.Adjustment({ this._workspaceAdjustment = new St.Adjustment({
actor: this,
value: activeWorkspaceIndex, value: activeWorkspaceIndex,
lower: 0, lower: 0,
page_increment: 1, page_increment: 1,
@ -455,6 +453,8 @@ class ControlsManager extends St.Widget {
this._group.add_child(this.viewSelector); this._group.add_child(this.viewSelector);
this._group.add_actor(this._thumbnailsSlider); this._group.add_actor(this._thumbnailsSlider);
layout.connect('allocation-changed', this._updateWorkspacesGeometry.bind(this));
Main.overview.connect('showing', this._updateSpacerVisibility.bind(this)); Main.overview.connect('showing', this._updateSpacerVisibility.bind(this));
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
@ -473,10 +473,29 @@ class ControlsManager extends St.Widget {
// A workspace might have been inserted or removed before the active // A workspace might have been inserted or removed before the active
// one, causing the adjustment to go out of sync, so update the value // one, causing the adjustment to go out of sync, so update the value
this._workspaceAdjustment.remove_transition('value');
this._workspaceAdjustment.value = activeIndex; this._workspaceAdjustment.value = activeIndex;
} }
_updateWorkspacesGeometry() {
let [x, y] = this.get_transformed_position();
let [width, height] = this.get_transformed_size();
let geometry = { x, y, width, height };
let spacing = this.get_theme_node().get_length('spacing');
let dashWidth = this._dashSlider.getVisibleWidth() + spacing;
let thumbnailsWidth = this._thumbnailsSlider.getNonExpandedWidth() + spacing;
geometry.width -= dashWidth;
geometry.width -= thumbnailsWidth;
if (this.get_text_direction() == Clutter.TextDirection.LTR)
geometry.x += dashWidth;
else
geometry.x += thumbnailsWidth;
this.viewSelector.setWorkspacesFullGeometry(geometry);
}
_setVisibility() { _setVisibility() {
// Ignore the case when we're leaving the overview, since // Ignore the case when we're leaving the overview, since
// actors will be made visible again when entering the overview // actors will be made visible again when entering the overview

View File

@ -2,7 +2,7 @@
/* exported PadOsd, PadOsdService */ /* exported PadOsd, PadOsdService */
const { Atk, Clutter, GDesktopEnums, Gio, const { Atk, Clutter, GDesktopEnums, Gio,
GLib, GObject, Gtk, Meta, Pango, Rsvg, St } = imports.gi; GLib, GObject, Gtk, Meta, Rsvg, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -329,7 +329,6 @@ var PadDiagram = GObject.registerClass({
this._imagePath = imagePath; this._imagePath = imagePath;
this._handle = this._composeStyledDiagram(); this._handle = this._composeStyledDiagram();
this._initLabels();
} }
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
@ -344,26 +343,6 @@ var PadDiagram = GObject.registerClass({
this.add_actor(actor); this.add_actor(actor);
} }
_initLabels() {
let i = 0;
for (i = 0; ; i++) {
if (!this._addLabel(Meta.PadActionType.BUTTON, i))
break;
}
for (i = 0; ; i++) {
if (!this._addLabel(Meta.PadActionType.RING, i, CW) ||
!this._addLabel(Meta.PadActionType.RING, i, CCW))
break;
}
for (i = 0; ; i++) {
if (!this._addLabel(Meta.PadActionType.STRIP, i, UP) ||
!this._addLabel(Meta.PadActionType.STRIP, i, DOWN))
break;
}
}
_wrappingSvgHeader() { _wrappingSvgHeader() {
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' + return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
@ -383,8 +362,10 @@ var PadDiagram = GObject.registerClass({
for (let i = 0; i < this._activeButtons.length; i++) { for (let i = 0; i < this._activeButtons.length; i++) {
let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]); let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
css += '.%s.Leader { stroke: %s !important; }'.format(ch, ACTIVE_COLOR); css += '.%s {'.format(ch);
css += '.%s.Button { stroke: %s !important; fill: %s !important; }'.format(ch, ACTIVE_COLOR, ACTIVE_COLOR); css += ' stroke: %s !important;'.format(ACTIVE_COLOR);
css += ' fill: %s !important;'.format(ACTIVE_COLOR);
css += '}';
} }
return css; return css;
@ -409,6 +390,9 @@ var PadDiagram = GObject.registerClass({
} }
_updateDiagramScale() { _updateDiagramScale() {
if (this._handle == null)
return;
[this._actorWidth, this._actorHeight] = this.get_size(); [this._actorWidth, this._actorHeight] = this.get_size();
let dimensions = this._handle.get_dimensions(); let dimensions = this._handle.get_dimensions();
let scaleX = this._actorWidth / dimensions.width; let scaleX = this._actorWidth / dimensions.width;
@ -421,11 +405,6 @@ var PadDiagram = GObject.registerClass({
let [, natWidth] = child.get_preferred_width(natHeight); let [, natWidth] = child.get_preferred_width(natHeight);
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
// I miss Cairo.Matrix
let dimensions = this._handle.get_dimensions();
x = x * this._scale + this._actorWidth / 2 - dimensions.width / 2 * this._scale;
y = y * this._scale + this._actorHeight / 2 - dimensions.height / 2 * this._scale;
if (direction == LTR) { if (direction == LTR) {
childBox.x1 = x; childBox.x1 = x;
childBox.x2 = x + natWidth; childBox.x2 = x + natWidth;
@ -436,23 +415,22 @@ var PadDiagram = GObject.registerClass({
childBox.y1 = y - natHeight / 2; childBox.y1 = y - natHeight / 2;
childBox.y2 = y + natHeight / 2; childBox.y2 = y + natHeight / 2;
child.allocate(childBox); child.allocate(childBox, 0);
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
super.vfunc_allocate(box); super.vfunc_allocate(box, flags);
if (this._handle === null)
return;
this._updateDiagramScale(); this._updateDiagramScale();
for (let i = 0; i < this._labels.length; i++) { for (let i = 0; i < this._labels.length; i++) {
const { label, x, y, arrangement } = this._labels[i]; let [label, action, idx, dir] = this._labels[i];
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
this._allocateChild(label, x, y, arrangement); this._allocateChild(label, x, y, arrangement);
} }
if (this._editorActor && this._curEdited) { if (this._editorActor && this._curEdited) {
const { x, y, arrangement } = this._curEdited; let [label_, action, idx, dir] = this._curEdited;
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
this._allocateChild(this._editorActor, x, y, arrangement); this._allocateChild(this._editorActor, x, y, arrangement);
} }
} }
@ -479,6 +457,17 @@ var PadDiagram = GObject.registerClass({
cr.$dispose(); cr.$dispose();
} }
_transformPoint(x, y) {
if (this._handle == null || this._scale == null)
return [x, y];
// I miss Cairo.Matrix
let dimensions = this._handle.get_dimensions();
x = x * this._scale + this._actorWidth / 2 - dimensions.width / 2 * this._scale;
y = y * this._scale + this._actorHeight / 2 - dimensions.height / 2 * this._scale;
return [Math.round(x), Math.round(y)];
}
_getItemLabelCoords(labelName, leaderName) { _getItemLabelCoords(labelName, leaderName) {
if (this._handle == null) if (this._handle == null)
return [false]; return [false];
@ -506,39 +495,44 @@ var PadDiagram = GObject.registerClass({
pos.y = this._imageHeight - pos.y; pos.y = this._imageHeight - pos.y;
} }
return [true, pos.x, pos.y, direction]; let [x, y] = this._transformPoint(pos.x, pos.y);
return [true, x, y, direction];
} }
_getButtonLabels(button) { getButtonLabelCoords(button) {
let ch = String.fromCharCode('A'.charCodeAt() + button); let ch = String.fromCharCode('A'.charCodeAt() + button);
let labelName = 'Label%s'.format(ch); let labelName = 'Label%s'.format(ch);
let leaderName = 'Leader%s'.format(ch); let leaderName = 'Leader%s'.format(ch);
return [labelName, leaderName];
return this._getItemLabelCoords(labelName, leaderName);
} }
_getRingLabels(number, dir) { getRingLabelCoords(number, dir) {
let numStr = number > 0 ? (number + 1).toString() : ''; let numStr = number > 0 ? (number + 1).toString() : '';
let dirStr = dir == CW ? 'CW' : 'CCW'; let dirStr = dir == CW ? 'CW' : 'CCW';
let labelName = 'LabelRing%s%s'.format(numStr, dirStr); let labelName = 'LabelRing%s%s'.format(numStr, dirStr);
let leaderName = 'LeaderRing%s%s'.format(numStr, dirStr); let leaderName = 'LeaderRing%s%s'.format(numStr, dirStr);
return [labelName, leaderName];
return this._getItemLabelCoords(labelName, leaderName);
} }
_getStripLabels(number, dir) { getStripLabelCoords(number, dir) {
let numStr = number > 0 ? (number + 1).toString() : ''; let numStr = number > 0 ? (number + 1).toString() : '';
let dirStr = dir == UP ? 'Up' : 'Down'; let dirStr = dir == UP ? 'Up' : 'Down';
let labelName = 'LabelStrip%s%s'.format(numStr, dirStr); let labelName = 'LabelStrip%s%s'.format(numStr, dirStr);
let leaderName = 'LeaderStrip%s%s'.format(numStr, dirStr); let leaderName = 'LeaderStrip%s%s'.format(numStr, dirStr);
return [labelName, leaderName];
return this._getItemLabelCoords(labelName, leaderName);
} }
_getLabelCoords(action, idx, dir) { getLabelCoords(action, idx, dir) {
if (action == Meta.PadActionType.BUTTON) if (action == Meta.PadActionType.BUTTON)
return this._getItemLabelCoords(...this._getButtonLabels(idx)); return this.getButtonLabelCoords(idx);
else if (action == Meta.PadActionType.RING) else if (action == Meta.PadActionType.RING)
return this._getItemLabelCoords(...this._getRingLabels(idx, dir)); return this.getRingLabelCoords(idx, dir);
else if (action == Meta.PadActionType.STRIP) else if (action == Meta.PadActionType.STRIP)
return this._getItemLabelCoords(...this._getStripLabels(idx, dir)); return this.getStripLabelCoords(idx, dir);
return [false]; return [false];
} }
@ -563,30 +557,26 @@ var PadDiagram = GObject.registerClass({
this._invalidateSvg(); this._invalidateSvg();
} }
_addLabel(action, idx, dir) { addLabel(label, type, idx, dir) {
let [found, x, y, arrangement] = this._getLabelCoords(action, idx, dir); this._labels.push([label, type, idx, dir]);
if (!found)
return false;
let label = new St.Label();
this._labels.push({ label, action, idx, dir, x, y, arrangement });
this.add_actor(label); this.add_actor(label);
return true;
} }
updateLabels(getText) { updateLabels(getText) {
for (let i = 0; i < this._labels.length; i++) { for (let i = 0; i < this._labels.length; i++) {
const { label, action, idx, dir } = this._labels[i]; let [label, action, idx, dir] = this._labels[i];
let str = getText(action, idx, dir); let str = getText(action, idx, dir);
label.set_text(str); label.set_text(str);
} }
this.queue_relayout();
} }
_applyLabel(label, action, idx, dir, str) { _applyLabel(label, action, idx, dir, str) {
if (str !== null) if (str != null) {
label.set_text(str); label.set_text(str);
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
this._allocateChild(label, x, y, arrangement);
}
label.show(); label.show();
} }
@ -594,20 +584,18 @@ var PadDiagram = GObject.registerClass({
this._editorActor.hide(); this._editorActor.hide();
if (this._prevEdited) { if (this._prevEdited) {
const { label, action, idx, dir } = this._prevEdited; let [label, action, idx, dir] = this._prevEdited;
this._applyLabel(label, action, idx, dir, str); this._applyLabel(label, action, idx, dir, str);
this._prevEdited = null; this._prevEdited = null;
} }
if (this._curEdited) { if (this._curEdited) {
const { label, action, idx, dir } = this._curEdited; let [label, action, idx, dir] = this._curEdited;
this._applyLabel(label, action, idx, dir, str); this._applyLabel(label, action, idx, dir, str);
if (continues) if (continues)
this._prevEdited = this._curEdited; this._prevEdited = this._curEdited;
this._curEdited = null; this._curEdited = null;
} }
this.queue_relayout();
} }
startEdition(action, idx, dir) { startEdition(action, idx, dir) {
@ -617,19 +605,21 @@ var PadDiagram = GObject.registerClass({
return; return;
for (let i = 0; i < this._labels.length; i++) { for (let i = 0; i < this._labels.length; i++) {
if (action == this._labels[i].action && let [label, itemAction, itemIdx, itemDir] = this._labels[i];
idx == this._labels[i].idx && dir == this._labels[i].dir) { if (action == itemAction && idx == itemIdx && dir == itemDir) {
this._curEdited = this._labels[i]; this._curEdited = this._labels[i];
editedLabel = this._curEdited.label; editedLabel = label;
break; break;
} }
} }
if (this._curEdited == null) if (this._curEdited == null)
return; return;
let [found] = this.getLabelCoords(action, idx, dir);
if (!found)
return;
this._editorActor.show(); this._editorActor.show();
editedLabel.hide(); editedLabel.hide();
this.queue_relayout();
} }
}); });
@ -703,7 +693,6 @@ var PadOsd = GObject.registerClass({
this._titleLabel = new St.Label({ style: 'font-side: larger; font-weight: bold;', this._titleLabel = new St.Label({ style: 'font-side: larger; font-weight: bold;',
x_align: Clutter.ActorAlign.CENTER }); x_align: Clutter.ActorAlign.CENTER });
this._titleLabel.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
this._titleLabel.clutter_text.set_text(padDevice.get_device_name()); this._titleLabel.clutter_text.set_text(padDevice.get_device_name());
labelBox.add_actor(this._titleLabel); labelBox.add_actor(this._titleLabel);
@ -721,7 +710,31 @@ var PadOsd = GObject.registerClass({
x_expand: true, x_expand: true,
y_expand: true }); y_expand: true });
this.add_actor(this._padDiagram); this.add_actor(this._padDiagram);
this._updateActionLabels();
// FIXME: Fix num buttons.
let i = 0;
for (i = 0; i < 50; i++) {
let [found] = this._padDiagram.getButtonLabelCoords(i);
if (!found)
break;
this._createLabel(Meta.PadActionType.BUTTON, i);
}
for (i = 0; i < padDevice.get_n_rings(); i++) {
let [found] = this._padDiagram.getRingLabelCoords(i, CW);
if (!found)
break;
this._createLabel(Meta.PadActionType.RING, i, CW);
this._createLabel(Meta.PadActionType.RING, i, CCW);
}
for (i = 0; i < padDevice.get_n_strips(); i++) {
let [found] = this._padDiagram.getStripLabelCoords(i, UP);
if (!found)
break;
this._createLabel(Meta.PadActionType.STRIP, i, UP);
this._createLabel(Meta.PadActionType.STRIP, i, DOWN);
}
let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(), let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
x_expand: true, x_expand: true,
@ -774,6 +787,11 @@ var PadOsd = GObject.registerClass({
return str ? str : _("None"); return str ? str : _("None");
} }
_createLabel(type, number, dir) {
let label = new St.Label({ text: this._getActionText(type, number) });
this._padDiagram.addLabel(label, type, number, dir);
}
_updateActionLabels() { _updateActionLabels() {
this._padDiagram.updateLabels(this._getActionText.bind(this)); this._padDiagram.updateLabels(this._getActionText.bind(this));
} }
@ -849,7 +867,8 @@ var PadOsd = GObject.registerClass({
this._tipLabel.set_text(_("Press any key to exit")); this._tipLabel.set_text(_("Press any key to exit"));
} }
this._titleLabel.set_text(title); this._titleLabel.clutter_text.set_markup(
'<span size="larger"><b>%s</b></span>'.format(title));
} }
_isEditedAction(type, number, dir) { _isEditedAction(type, number, dir) {

View File

@ -120,10 +120,6 @@ var PageIndicators = GObject.registerClass({
for (let i = 0; i < children.length; i++) for (let i = 0; i < children.length; i++)
this._updateIndicator(children[i], i); this._updateIndicator(children[i], i);
} }
get nPages() {
return this._nPages;
}
}); });
var AnimatedPageIndicators = GObject.registerClass( var AnimatedPageIndicators = GObject.registerClass(

View File

@ -90,17 +90,19 @@ class AppMenu extends PopupMenu.PopupMenu {
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._detailsItem = this.addAction(_('Show Details'), async () => { this._detailsItem = this.addAction(_("Show Details"), () => {
let id = this._app.get_id(); let id = this._app.get_id();
let args = GLib.Variant.new('(ss)', [id, '']); let args = GLib.Variant.new('(ss)', [id, '']);
const bus = await Gio.DBus.get(Gio.BusType.SESSION, null); Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => {
bus.call( let bus = Gio.DBus.get_finish(res);
'org.gnome.Software', bus.call('org.gnome.Software',
'/org/gnome/Software', '/org/gnome/Software',
'org.gtk.Actions', 'Activate', 'org.gtk.Actions', 'Activate',
new GLib.Variant('(sava{sv})', ['details', [args], null]), GLib.Variant.new('(sava{sv})',
['details', [args], null]),
null, 0, -1, null); null, 0, -1, null);
}); });
});
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
@ -214,10 +216,7 @@ var AppMenuButton = GObject.registerClass({
this._onIconThemeChanged.bind(this)); this._onIconThemeChanged.bind(this));
let iconEffect = new Clutter.DesaturateEffect(); let iconEffect = new Clutter.DesaturateEffect();
this._iconBox = new St.Bin({ this._iconBox = new St.Bin({ style_class: 'app-menu-icon' });
style_class: 'app-menu-icon',
y_align: Clutter.ActorAlign.CENTER,
});
this._iconBox.add_effect(iconEffect); this._iconBox.add_effect(iconEffect);
this._container.add_actor(this._iconBox); this._container.add_actor(this._iconBox);
@ -284,7 +283,7 @@ var AppMenuButton = GObject.registerClass({
this.remove_all_transitions(); this.remove_all_transitions();
this.ease({ this.ease({
opacity: 0, opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.Animation.EASE_OUT_QUAD,
duration: Overview.ANIMATION_TIME, duration: Overview.ANIMATION_TIME,
onComplete: () => this.hide(), onComplete: () => this.hide(),
}); });
@ -675,7 +674,7 @@ class PanelCorner extends St.DrawingArea {
let borderWidth = node.get_length('-panel-corner-border-width'); let borderWidth = node.get_length('-panel-corner-border-width');
this.set_size(cornerRadius, borderWidth + cornerRadius); this.set_size(cornerRadius, borderWidth + cornerRadius);
this.translation_y = -borderWidth; this.set_anchor_point(0, borderWidth);
} }
}); });
@ -736,11 +735,13 @@ class AggregateMenu extends PanelMenu.Button {
this._volume = new imports.ui.status.volume.Indicator(); this._volume = new imports.ui.status.volume.Indicator();
this._brightness = new imports.ui.status.brightness.Indicator(); this._brightness = new imports.ui.status.brightness.Indicator();
this._system = new imports.ui.status.system.Indicator(); this._system = new imports.ui.status.system.Indicator();
this._screencast = new imports.ui.status.screencast.Indicator();
this._location = new imports.ui.status.location.Indicator(); this._location = new imports.ui.status.location.Indicator();
this._nightLight = new imports.ui.status.nightLight.Indicator(); this._nightLight = new imports.ui.status.nightLight.Indicator();
this._thunderbolt = new imports.ui.status.thunderbolt.Indicator(); this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
this._indicators.add_child(this._thunderbolt); this._indicators.add_child(this._thunderbolt);
this._indicators.add_child(this._screencast);
this._indicators.add_child(this._location); this._indicators.add_child(this._location);
this._indicators.add_child(this._nightLight); this._indicators.add_child(this._nightLight);
if (this._network) if (this._network)
@ -840,8 +841,8 @@ class Panel extends St.Widget {
return [0, 0]; return [0, 0];
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
this.set_allocation(box); this.set_allocation(box, flags);
let allocWidth = box.x2 - box.x1; let allocWidth = box.x2 - box.x1;
let allocHeight = box.y2 - box.y1; let allocHeight = box.y2 - box.y1;
@ -877,13 +878,13 @@ class Panel extends St.Widget {
childBox.x2 = Math.min(Math.floor(sideWidth), childBox.x2 = Math.min(Math.floor(sideWidth),
leftNaturalWidth); leftNaturalWidth);
} }
this._leftBox.allocate(childBox); this._leftBox.allocate(childBox, flags);
childBox.x1 = Math.ceil(sideWidth); childBox.x1 = Math.ceil(sideWidth);
childBox.y1 = 0; childBox.y1 = 0;
childBox.x2 = childBox.x1 + centerWidth; childBox.x2 = childBox.x1 + centerWidth;
childBox.y2 = allocHeight; childBox.y2 = allocHeight;
this._centerBox.allocate(childBox); this._centerBox.allocate(childBox, flags);
childBox.y1 = 0; childBox.y1 = 0;
childBox.y2 = allocHeight; childBox.y2 = allocHeight;
@ -897,7 +898,7 @@ class Panel extends St.Widget {
0); 0);
childBox.x2 = allocWidth; childBox.x2 = allocWidth;
} }
this._rightBox.allocate(childBox); this._rightBox.allocate(childBox, flags);
let cornerWidth, cornerHeight; let cornerWidth, cornerHeight;
@ -907,7 +908,7 @@ class Panel extends St.Widget {
childBox.x2 = cornerWidth; childBox.x2 = cornerWidth;
childBox.y1 = allocHeight; childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight; childBox.y2 = allocHeight + cornerHeight;
this._leftCorner.allocate(childBox); this._leftCorner.allocate(childBox, flags);
[, cornerWidth] = this._rightCorner.get_preferred_width(-1); [, cornerWidth] = this._rightCorner.get_preferred_width(-1);
[, cornerHeight] = this._rightCorner.get_preferred_height(-1); [, cornerHeight] = this._rightCorner.get_preferred_height(-1);
@ -915,7 +916,7 @@ class Panel extends St.Widget {
childBox.x2 = allocWidth; childBox.x2 = allocWidth;
childBox.y1 = allocHeight; childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight; childBox.y2 = allocHeight + cornerHeight;
this._rightCorner.allocate(childBox); this._rightCorner.allocate(childBox, flags);
} }
_tryDragWindow(event) { _tryDragWindow(event) {
@ -1154,9 +1155,10 @@ class Panel extends St.Widget {
_getDraggableWindowForPosition(stageX) { _getDraggableWindowForPosition(stageX) {
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
const windows = workspaceManager.get_active_workspace().list_windows(); let workspace = workspaceManager.get_active_workspace();
const allWindowsByStacking = let allWindowsByStacking = global.display.sort_windows_by_stacking(
global.display.sort_windows_by_stacking(windows).reverse(); workspace.list_windows()
).reverse();
return allWindowsByStacking.find(metaWindow => { return allWindowsByStacking.find(metaWindow => {
let rect = metaWindow.get_frame_rect(); let rect = metaWindow.get_frame_rect();

View File

@ -59,8 +59,8 @@ class ButtonBox extends St.Widget {
return [0, 0]; return [0, 0];
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
this.set_allocation(box); this.set_allocation(box, flags);
let child = this.get_first_child(); let child = this.get_first_child();
if (!child) if (!child)
@ -83,7 +83,7 @@ class ButtonBox extends St.Widget {
childBox.y1 = 0; childBox.y1 = 0;
childBox.y2 = availHeight; childBox.y2 = availHeight;
child.allocate(childBox); child.allocate(childBox, flags);
} }
_onDestroy() { _onDestroy() {
@ -183,9 +183,10 @@ var Button = GObject.registerClass({
} }
_onDestroy() { _onDestroy() {
super._onDestroy();
if (this.menu) if (this.menu)
this.menu.destroy(); this.menu.destroy();
super._onDestroy();
} }
}); });

View File

@ -881,10 +881,9 @@ var PopupMenu = class extends PopupMenuBase {
let state = event.get_state(); let state = event.get_state();
// if user has a modifier down (except capslock and numlock) // if user has a modifier down (except capslock)
// then don't handle the key press here // then don't handle the key press here
state &= ~Clutter.ModifierType.LOCK_MASK; state &= ~Clutter.ModifierType.LOCK_MASK;
state &= ~Clutter.ModifierType.MOD2_MASK;
state &= Clutter.ModifierType.MODIFIER_MASK; state &= Clutter.ModifierType.MODIFIER_MASK;
if (state) if (state)
@ -1325,7 +1324,7 @@ var PopupMenuManager = class {
removeMenu(menu) { removeMenu(menu) {
if (menu == this.activeMenu) if (menu == this.activeMenu)
this._grabHelper.ungrab({ actor: menu.actor }); this._closeMenu(false, menu);
let position = this._findMenu(menu); let position = this._findMenu(menu);
if (position == -1) // not a menu we manage if (position == -1) // not a menu we manage

View File

@ -204,7 +204,7 @@ var RemoteSearchProvider = class {
g_interface_info: proxyInfo, g_interface_info: proxyInfo,
g_interface_name: proxyInfo.name, g_interface_name: proxyInfo.name,
gFlags }); gFlags });
this.proxy.init_async(GLib.PRIORITY_DEFAULT, null); this.proxy.init_async(GLib.PRIORITY_DEFAULT, null, null);
this.appInfo = appInfo; this.appInfo = appInfo;
this.id = appInfo.get_id(); this.id = appInfo.get_id();

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