Compare commits

...

254 Commits

Author SHA1 Message Date
Florian Müllner
f53c8fd4bc Bump version to 47.5
Update NEWS.
2025-05-24 19:13:46 +02:00
Neal Gompa
d7db924424 build: Do not install anything in xsessions when X11 is disabled
Fixes: b05eb4eb6d ("build: Allow disabling the X11 session")
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/400>
(cherry picked from commit 2552c92fe1)
2025-05-23 19:14:44 +02:00
Neal Gompa
71e78265d5 build: Allow disabling the X11 session
This is consistent with gnome-session and the rest of the GNOME
session stack.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/396>
(cherry picked from commit b05eb4eb6d)
2025-05-23 19:14:44 +02:00
Florian Müllner
fa5c4bade1 Bump version to 47.4
Update NEWS.
2025-02-05 00:40:33 +01:00
Florian Müllner
a7d4d8df80 window-list: Use correct params when re-tracking chrome
Since commit 981e8e42, we temporarily untrack the window-list actor
while in the overview.

However as we don't pass pass the chrome parameters when re-tracking
chrome, the window-list no longer contributes to struts or tracks
fullscreen changes, whoops.

Make sure to pass the original parameters when re-tracking chrome
to restore the expected behavior.

Fixes: 981e8e42 ("window-list: Untrack chrome while in overview")
Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/550
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/379>
(cherry picked from commit 01f7df1e8a)
2025-01-16 12:09:05 +01:00
Florian Müllner
791682e836 ci: Switch ci-templates to master
The alternative is to monitor the upstream repository and update
the references when necessary. I don't have the resources to do
that, so trust upstream to not mess up their development branch.

(cherry picked from commit 4e50e9f8dc)

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/376>
2025-01-13 16:29:57 +01:00
Florian Müllner
c815e506dd Bump version to 47.3
Update NEWS.
2025-01-12 21:59:15 +01:00
Florian Müllner
176206a38c places-menu: Remove left-over modeline
This one slipped through commit 253ddb864 ...

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/370>
(cherry picked from commit 83c41bad30)
2025-01-12 20:53:59 +00:00
Bartłomiej Piotrowski
72b2534790 ci: Switch to GNOME GitLab mirror of ci-templates
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/368>
(cherry picked from commit 0f69d7663b)
2025-01-12 20:53:59 +00:00
Florian Müllner
28ac6906c2 ci: Adapt to updated release module template
The release module moved into production now. The process changed
slightly with regard to the testing period, so we will have to
adapt the existing job a bit.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/367>
(cherry picked from commit 5d8d3601b4)
2025-01-12 20:53:59 +00:00
Florian Müllner
e30f634d08 ci: Move LINT_LOG variable out of global section
It is only used by the eslint job, so better define it there.

While at it, make sure the variable is quoted as that's considered
good practice (even when safe to use unquoted as in this case).

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/367>
(cherry picked from commit ea77b557e5)
2025-01-12 20:53:59 +00:00
Florian Müllner
aed90a3f6c ci: Use variable for meson build directory
This ensures that the value is consistent between jobs.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/367>
(cherry picked from commit 9f48149346)
2025-01-12 20:53:59 +00:00
Florian Müllner
7054010520 Revert "ci: Use meson introspect to generate artifact path"
The new release service that now moved into production expects
the tag to match the release version.

Instead of using the $VERSION-real pattern in case of error,
switch to a pre-push hook to hopefully prevent those errors
in the first place:

  https://gitlab.gnome.org/-/snippets/6710

This reverts commit 8c014a6b1d.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/367>
(cherry picked from commit 0d1b279a64)
2025-01-12 20:53:59 +00:00
Florian Müllner
cc3e2842a8 ci: Bump js image
gnome-shell switched to F41 for its JS image, follow suit.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/365>
(cherry picked from commit b30871d105)
2025-01-12 20:53:59 +00:00
Florian Müllner
f6d4e44ee4 workspace-indicator: Do not only exclude DESKTOP windows
There are other window types that should be excluded from workspace
previews, including more common ones like menus. Instead of checking
for a variety of window types, delegate the decision to mutter by
checking for the `skip-taskbar` property.

(The internal `skip-pager` property would be more apt in this case,
but as it only differs from `skip-taskbar` for X11 clients that
explicitly set one and not the other, it shouldn't matter in practice)

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/537
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/363>
(cherry picked from commit 77a11fd9cd)
2025-01-12 20:53:59 +00:00
Florian Müllner
bcf0be86af window-list: Untrack chrome while in overview
The window list is set up to track the monitor's fullscreen state.
Monitors are never considered in fullscreen while showing the overview,
so if shell's layout manager updates the fullscreen visibility after
we hid the bottom bar, it ends up being visible in the overview.

To avoid this, untrack the actor while the overview is visible.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/509
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/364>
(cherry picked from commit 981e8e42e2)
2025-01-12 20:53:59 +00:00
Florian Müllner
fb86b18cf1 window-list: Fix disconnecting window signals in context menu
Menus are not actors themselves, so they are not "destroyables" in
terms of automatic signal disconnection, with the result that we
currently leak window signals.

Fix this by using the menu's actor as tracked object, so the signals
are disconnected automatically when the actor is destroyed.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/474
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/362>
(cherry picked from commit 4a841dfd49)
2025-01-12 20:53:59 +00:00
Florian Müllner
6400be4a6c places-menu: Update fake mount operation source
gnome-shell now checks for an associated drive to automatically
cancel the operation on disconnect, so fake the corresponding
method. While at it, drop the `get_icon()` method that hasn't
been used for quite a while now.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/508
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/361>
(cherry picked from commit 8957f488dc)
2025-01-12 20:53:59 +00:00
Florian Müllner
b1f727fa34 places-menu: Catch errors during async operation
Uncaught errors in async functions don't provide a good stack, because
the unhandled promise rejection masks the error that triggered it.

While we already handle *expected* errors inside the function, make
sure we catch all errors to get useful stack information for unexpected
errors as well.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/361>
(cherry picked from commit e0b68a319e)
2025-01-12 20:53:59 +00:00
Yi-Jyun Pan
97d0a0e514 Update Chinese (Taiwan) translation 2025-01-12 15:59:38 +00:00
Florian Müllner
70e2a02e69 Bump version to 47.2
Update NEWS.
2024-11-25 16:14:41 +01:00
Florian Müllner
079daac9bb screenshot-window-sizer: Mention shortcut in description
Loosely based on the README entry, so users know how to actually use the
extension.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/541
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/358>
2024-11-25 15:43:54 +01:00
Florian Müllner
99d49c1800 places-menu: Inherit from PopupImageMenuItem
PopupImageMenuItems used to position the icon after the label,
so we ended up with our own icon+label items.

However the icon position was changed years ago in the shell, so
inherit from PopupImageMenuItem instead.

This does not only simplify the code a bit, but also pulls in
features we are currently missing, like a11y labelling.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/542
(cherry picked from commit 568826e489)
2024-11-25 14:19:07 +01:00
Florian Müllner
95c4bc5d87 build: Sync check-version script with gnome-shell
The script was updated to not require appstream-util to check for
a corresponding release element in metainfo.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/354>
(cherry picked from commit 1218aee87f)
2024-11-25 14:18:56 +01:00
Florian Müllner
451a12d1fd cleanup: Use consistent line break style in meson.build
Either have all arguments on the same line, or have a separate
line for every argument (that is, don't special-case the first
arg).

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit 265935e14b)
2024-11-25 14:18:35 +01:00
Florian Müllner
48b917ab86 cleanup: Fix indent errors in meson.build
We are supposed to use a 2-space indent, but some inconsistencies
sneaked in over time.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit b903618050)
2024-11-25 14:18:00 +01:00
Florian Müllner
d273dc4e59 cleanup: Always use dangling commas in meson.build
This is meson's default formatting, and matches what we already
do in JS.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit 720933b08e)
2024-11-25 14:17:53 +01:00
Florian Müllner
683080441f cleanup: Use format strings in meson.build
Those are a bit more concise than ''.format(), and have been
in meson for a long time.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit 85ee8829bf)
2024-11-25 14:17:45 +01:00
Florian Müllner
5bbf7f5c6c build: Use SPDX identifier for license
Meson strongly recommends to use SPDX identifiers for the license
string, and there's no reason for us to not do so.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit 6df4905286)
2024-11-25 14:17:35 +01:00
Florian Müllner
f30990535f extensions: Remove modelines
We already include an .editorconfig that is supported by many
editors, including emacs, so no need to repeat an emacs-specific
modeline in every source file.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit 253ddb8642)
2024-11-25 14:17:25 +01:00
Florian Müllner
d14885f96d Add .editorconfig
This should ensure that all editors which support
https://editorconfig.org/ use the correct indentation
with spaces (not tabs) by default.

This is hardly a full specification of our coding style,
but it's a correct subset and better than nothing.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/353>
(cherry picked from commit 0ca156a2b6)
2024-11-25 14:15:52 +01:00
Марко Костић
0a153b78f9 Update Serbian translation 2024-11-04 07:15:02 +00:00
Nathan Follens
598007f994 Update Dutch translation 2024-10-27 22:37:35 +00:00
Fabio Tomat
06caed8c0c Update Friulian translation 2024-10-20 20:01:51 +00:00
Florian Müllner
9991f90804 Bump version to 47.1
Update NEWS.
2024-10-18 21:54:13 +02:00
Florian Müllner
0bc77ef7c9 build: Rename meson_options.txt to meson.options
The name is a bit cleaner, and has been the preferred option(!)
since meson 1.1.

Mutter recently updated the name, so follow suite.

The meson version bump shouldn't be an issue, given that several
hard dependencies like mutter and glib already require higher
versions.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/349>
(cherry picked from commit 1088435120)
2024-10-18 19:15:44 +02:00
Florian Müllner
099b2eeb49 cleanup: Use null for nick/blurb in ParamSpecs
As they are only used by gstreamer for gst-inspect & other tools.
Projects like mutter and gtk have already completely dropped them,
so follow their lead.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/347>
(cherry picked from commit 46a4fa0976)
2024-10-18 19:15:02 +02:00
Florian Müllner
b13984a752 export-zips: Use --destdir instead of custom prefix
meson skips some steps like schema compilation when DESTDIR is
set, so this is slightly more efficient.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/345>
(cherry picked from commit 8f75ccae34)
2024-10-17 20:59:07 +02:00
Florian Müllner
67cdd0bea2 window-list: Remove outdated style
A long time ago, the window list used to embed the bottom message
tray, which caused notifications to inherit the window-list's
font style.

Since that's no longer the case, we have no business in messing
with notification styling, so stop doing that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
(cherry picked from commit f1671bc206)
2024-10-17 20:56:38 +02:00
Florian Müllner
87a849c5af window-list: Switch to Adw.SwitchRow
libadwaita fixed the actionable implementation of Adw.SwitchRow,
so can use the convenience widget instead of composing our own.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/341>
(cherry picked from commit 548d7659e1)
2024-10-17 20:56:26 +02:00
Florian Müllner
f0bff952be window-list: Remove superfluous bindings
The setting is already bound to the switch via the corresponding action,
no need to also set up a binding.

In fact, the second binding is actively harmful, as it keeps the
connection alive until dispose, so the setting is reset on
garbage collection.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/341>
(cherry picked from commit 0162644041)
2024-10-17 20:56:18 +02:00
Florian Müllner
b3ff771a1d window-list: Add missing action
Commit 24ba03fe9 added a new setting, but forgot to create the
corresponding action.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/341>
(cherry picked from commit 062a3d21ab)
2024-10-17 20:56:09 +02:00
Florian Müllner
3ef718d34c window-list: Fix active state
Commit c72b8b21 fixed the styling of the active window's button,
but missed that the `active` property uses the style information
as well.

Adjust it to use the correct actor when checking for the style class.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/342>
(cherry picked from commit a5a92026ac)
2024-10-17 20:55:59 +02:00
Florian Müllner
fb2d87c1da window-list: Fix minimized styling
Commit 039c66e7b7 wrapped the button in a container to
animate transitions, but didn't adjust the `.minimized`
styling to still apply to the button (where it is
expected) rather than the wrapper.

Fix this just like commit c72b8b21 did for the
`.focused` styling.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/342>
(cherry picked from commit 28fd210f28)
2024-10-17 20:55:52 +02:00
Florian Müllner
6d3fbceec9 classic: Add missing top bar indicators
The only intended difference from the regular session is that the
date menu moves to the right. However in the meantime, gnome-shell
added a couple more (usually hidden) indicators, but we never
updated the session mode definition.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/339>
(cherry picked from commit 81aade6659)
2024-10-17 20:55:43 +02:00
Florian Müllner
4da312040b window-list: Don't recreate icons on theme changes
All icons use `StIcon`, which already updates itself correctly
on icon theme changes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
(cherry picked from commit d43abe0869)
2024-10-17 20:55:22 +02:00
Florian Müllner
89276cc184 window-list: Small stylesheet cleanup
The light stylesheet duplicates some declarations, and the
last occurrence matches what we already inherit from the
dark stylesheet.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
(cherry picked from commit 860c56f83e)
2024-10-17 20:55:07 +02:00
Florian Müllner
2716cb0b98 Bump version to 47.0
Update NEWS.
2024-09-14 18:48:33 +02:00
Irénée THIRION
6048971663 Update French translation 2024-09-12 13:06:50 +00:00
Rūdolfs Mazurs
04cab9954b Update Latvian translation 2024-09-10 19:45:49 +00:00
Dušan Kazik
cbb622a099 Update Slovak translation 2024-09-10 10:45:22 +00:00
Aefgh Threenine
f3b505867f Update Thai translation 2024-09-10 09:19:08 +00:00
Ask Hjorth Larsen
7bee509ecd Update Danish translation 2024-09-08 17:01:48 +00:00
Andi Chandler
b6ac158139 Update British English translation 2024-09-08 13:02:41 +00:00
Andika Triwidada
9af1a79434 Update Indonesian translation 2024-09-03 23:36:50 +00:00
Daniel
fa9e2dc71c Updated Spanish translation 2024-09-03 11:26:45 +02:00
Aurimas Černius
e94f10ac16 Update Lithuanian translation 2024-09-02 19:41:25 +00:00
Fran Dieguez
0319c6e8cb Update Galician translation 2024-09-02 18:16:21 +00:00
Alexander Shopov
fe1ae49dbe Update Bulgarian translation 2024-09-02 08:50:17 +00:00
twlvnn kraftwerk
353598e6d8 Update Bulgarian translation
(cherry picked from commit a99515feef)
2024-09-02 08:47:25 +00:00
Florian Müllner
36266e5a5a Bump version to 47.rc
Update NEWS.
2024-09-01 13:55:50 +02:00
Florian Müllner
f7a371c0bf ci: Update ci-fairy include 2024-09-01 13:55:50 +02:00
Sabri Ünal
018815d9e9 Update Turkish translation 2024-09-01 11:09:10 +00:00
Piotr Drąg
82fd82b30c Update Polish translation 2024-08-31 13:42:26 +00:00
Daniel Șerbănescu
26f5e23faa Update Romanian translation 2024-08-30 14:12:48 +00:00
Hugo Carvalho
0989cb3836 Update Portuguese translation 2024-08-30 10:28:12 +00:00
Changwoo Ryu
c55df7c239 Update Korean translation 2024-08-29 23:33:05 +00:00
Jürgen Benvenuti
9a840c437c Update German translation 2024-08-29 18:07:10 +00:00
Anders Jonsson
f33a833f7c Update Swedish translation 2024-08-29 11:18:17 +00:00
Quentin PAGÈS
7c284b6bdc Update Occitan translation 2024-08-27 08:35:49 +00:00
Rafael Fontenelle
6af5cbe4e0 Update Brazilian Portuguese translation 2024-08-26 15:50:33 +00:00
Danial Behzadi
5d6c2a3008 Update Persian translation 2024-08-26 08:50:08 +00:00
Asier Sarasua Garmendia
7ffe7b9aec Update Basque translation 2024-08-25 08:19:43 +00:00
Brage Fuglseth
2e912861f1 Update Norwegian Bokmål translation 2024-08-24 20:22:09 +00:00
Brage Fuglseth
f8ac973802 Update Norwegian Bokmål translation 2024-08-24 20:03:23 +00:00
Luming Zh
5bb15ae1cf Update Chinese (China) translation 2024-08-24 05:32:51 +00:00
Vasil Pupkin
34f379f6c7 Update Belarusian translation 2024-08-23 13:00:34 +00:00
Daniel Rusek
14d6920dd3 Update Czech translation 2024-08-23 12:32:38 +00:00
Jiri Grönroos
3d1c253369 Update Finnish translation 2024-08-23 11:07:46 +00:00
Yuri Chornoivan
b5dd68d6f2 Update Ukrainian translation 2024-08-23 09:33:47 +00:00
Jordi Mas i Hernandez
93c2c408be Update Catalan translation 2024-08-20 05:40:09 +00:00
Ekaterine Papava
c2c57c8e29 Update Georgian translation 2024-08-17 05:19:11 +00:00
Sophie Herold
9432ae260b doap: Remove marge-bot maintainer entry
marge-bot has had GNOME wide Developer access for a while, which should be sufficient.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/333>
2024-08-15 13:22:36 +00:00
Giannis Antypas
69f3132f4c Update Greek translation
(cherry picked from commit 7953cd130d)
2024-08-12 20:30:46 +00:00
Daniel Șerbănescu
4ccffbb27d Update Romanian translation
(cherry picked from commit 75b1ea879b)
2024-08-05 20:05:46 +00:00
Florian Müllner
8a9aa6a818 Bump version to 47.beta
Update NEWS.
2024-08-03 19:51:04 +02:00
Florian Müllner
017c6470b9 workspace-indicator: Re-fittsify workspace previews
For the window-list extension, it is important that the workspace
previews extend to the bottom edge for easier click targets.

That broke while merging the code with the workspace-indicator,
fix it again by moving the padding from the parent box into the
thumbnail children.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/327>
2024-07-31 15:01:08 +00:00
Florian Müllner
1e25fc1b5a status-icons: Add new extension
Based on an original "top-icons" extension by Adel Gadllah that
is no longer maintained.

The code has been heavily simplified and modernised, and adapted
to integrate into the top bar more seemlessly.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/194>
2024-07-31 14:42:55 +00:00
Jakub Steiner
e28215f38f window-list: Update styling
- Contemporary look. Fewer borders, thinner outlines for workspace indicators
- Lacks the designed unfocused window separators.
- Relies on https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/328

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/330>
2024-07-31 14:37:31 +00:00
Florian Müllner
8d06bc8b64 ci: Bump image
node occasionally fails with an "Illegal instruction" error,
which hopefully has been fixed by a package update.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/331>
2024-07-31 15:49:22 +02:00
Chao-Hsiung Liao
9e475cb279 Update Chinese (Taiwan) translation
(cherry picked from commit b89a93a4fc)
2024-07-24 10:26:16 +00:00
Sabri Ünal
cbbb2d2869 Update Turkish translation 2024-07-19 15:12:16 +00:00
Florian Müllner
c72b8b2122 window-list: Fix .focused styling
Commit 039c66e7b7 wrapped the button in a container to
animate transitions, but didn't adjust the `.focused`
styling to still apply to the button (where it is
expected) rather than the wrapper.

Fix that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/328>
2024-07-13 00:11:19 +02:00
Florian Müllner
c302db7545 Bump version to 47.alpha
Update NEWS.
2024-06-29 14:11:12 +02:00
Florian Müllner
0554a8e97d window-list: Replace custom tooltip implementation
DashItemContainer already has support for showing a tooltip-like
label, so now that we use that for animating items, we can use
it for tooltips as well.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/325>
2024-06-29 13:43:55 +02:00
Florian Müllner
039c66e7b7 window-list: Animate buttons in and out
Buttons are currently added and removed from the list without
any transitions, which gives the list a "jumpy" feel. Instead,
do what we do elsewhere and smoothly animate additions and
removals by re-using the dash's ItemContainer class.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/325>
2024-06-29 13:43:55 +02:00
Florian Müllner
7eb00e350e window-list: Don't hide window button while unmanaging
This will allow to animate the transition.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/325>
2024-06-29 13:43:55 +02:00
Florian Müllner
f76f9e8220 window-list: Don't use homogeneous layout
We want all buttons in the window list to have the same size,
but that's already achieved via max/natural-width in the CSS.

Not enforcing the equal size via the layout manager will allow
buttons to temporarily have a different size when we start
animating additions and removals.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/325>
2024-06-29 13:13:12 +02:00
Balázs Úr
17c963b63f Update Hungarian translation 2024-06-28 14:25:44 +00:00
Yosef Or Boczko
5d45a697ce Update Hebrew translation 2024-06-28 07:34:33 +00:00
Милош Поповић
ef729f2d66 Update Serbian translation 2024-06-20 15:00:07 +00:00
Artur S0
1394e82bd0 Update Russian translation 2024-05-27 10:19:22 +00:00
Scrambled 777
9e61aaf08c Update Hindi translation 2024-05-25 17:17:19 +00:00
Florian Müllner
6ac76140a5 ci: Hook up release-module
In the future, the module will automate uploading the release
tarball. We already use the CI pipeline to generate the tarball,
so it's easy to hook up the module and provide some testing
before the module goes into production.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/324>
2024-05-24 15:18:59 +02:00
Florian Müllner
8c014a6b1d ci: Use meson introspect to generate artifact path
We currently assume that the `CI_COMMIT_TAG` variable matches the
version component of the generated dist tarball.

That is usually correct, but sometimes errors happen and a wrong
tag is pushed, and the real release uses something like "46.0-real".

Account for that by building the artifact path from `meson introspect`
and exporting it as environment variable.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/324>
2024-05-24 15:18:59 +02:00
Scrambled 777
2fe844f412 Update Hindi translation 2024-05-12 13:44:51 +00:00
Jose Riha
8185b43d54 Update Slovak translation
(cherry picked from commit 1219dfc144)
2024-05-11 22:19:20 +00:00
Hugo Carvalho
59ab3f834d Update Portuguese translation
(cherry picked from commit dd16556530)
2024-05-04 23:22:30 +00:00
Martin
8b6835c3d6 Update Slovenian translation 2024-05-01 22:12:17 +00:00
Florian Müllner
bb5bb70ac5 Update POTFILES.in
The file is now copied at build time from the workspace-indicator
extension.

Fixes: 0c42f162 ("window-list: Use actual copy of workspace-indicator")
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/321>
2024-04-29 16:49:30 +02:00
Florian Müllner
da90d365ec window-list: Use getter methods for events
The underlying structs were made opaque a while ago, so direct
access to the struct fields is no longer possible.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/320>
2024-04-26 15:22:16 +02:00
Florian Müllner
02ff72b2f0 apps-menu: Set label_actor of Category items
Category items are based on BaseMenuItem rather than MenuItem,
so the accessible relationship isn't set up automatically for us.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/319>
2024-04-25 14:42:53 +00:00
Jordi Mas i Hernandez
9c7a086870 Update Catalan translation 2024-04-25 11:53:01 +00:00
Florian Müllner
24ba03fe96 window-list: Expose workspace preview option
Now that we have the option, the window-list should expose it
in its preference window like the workspace-indicator.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
69d8d1a335 workspace-indicator: Make previews configurable
Now that previews scroll when there are too many workspaces,
there is no longer a reason for the 6-workspace limit.

However some users do prefer the menu, so rather than drop it,
turn it into a proper preference.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
d495a2eed8 workspace-indicator: Also show previews in menu
Since the regular session also switched to horizontal workspaces,
using a vertical menu has been a bit awkward.

Now that our previews have become more flexible, we can use them
in the collapsed state as well as when embedded into the top bar.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
6b3990457e workspace-indicator: Stop handling vertical layouts
Both the regular session and GNOME classic use a horizontal layout
nowadays, so it doesn't seem worth to specifically handle vertical
layouts anymore.

The extension will still work when the layout is changed (by some
other extension), there will simply be a mismatch between horizontal
previews and the actual layout.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
099cff0b95 workspace-indicator: Support labels in previews
The space in the top bar is too limited to include the workspace
names. However we'll soon replace the textual menu with a preview
popover. We can use bigger previews there, so we can include the
names to not lose functionality with regards to the current menu.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
fac7fedfd3 workspace-indicator: Handle preview overflow
We currently avoid previews from overflowing in most setups by
artificially limiting them to a maximum of six workspaces.

Add some proper handling to also cover cases where space is more
limited, and to allow removing the restriction in the future.

For that, wrap the previews in an auto-scrolling scroll view
and add overflow indicators on each side.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
6ed1b56526 workspace-indicator: Split out WorkspacePreviews
The previews will become a bit more complex soon, so spit them out
into a dedicated class.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
a2ffb1238f workspace-indicator: Handle active indication in thumbnail
Meta.Workspace has had an `active` property for a while now, so
we can use a property binding instead of tracking the active
workspace ourselves.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
b55e7a4dc8 workspace-indicator: Simplify scroll handling
gnome-shell already includes a method for switching workspaces
via scroll events. Use that instead of implementing our own.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/316>
2024-04-24 14:23:22 +00:00
Florian Müllner
0c42f162d3 window-list: Use actual copy of workspace-indicator
We are now at a point where the code from the workspace-indicator
extension is usable from the window-list.

However instead of updating the copy, go one step further and
remove it altogether, and copy the required files at build time.

This ensures that future changes are picked up by both extensions
without duplicating any work.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
01a37c8f26 export-zips: Pick up non-default stylesheets
The window-list extension is about to import the workspace-indicator
stylesheet. Explicitly pack css files, so the stylesheet is included
in the bundle.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
5e88c7d891 workspace-indicator: Support light style
The window-list extension already includes light styling for
its copy of the workspace indicator. Just copy that over to
support the light variant here as well.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
af23a8491c workspace-indicator: Tweak preview style
Sync sizes and padding with the window-list previews.

Tone down the colors a bit, but less then the current window-list
style where workspaces blend too much into the background and
the selection is unclear.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
32a454f917 workspace-indicator: Include n-workspaces in status label
The two extensions currently use a slightly different label
in menu mode:
The workspace indicator uses the plain workspace number ("2"),
while the window list includes the number of workspaces ("2 / 4").

The additional information seem useful, as well as the slightly
bigger click/touch target, so copy the window-list behavior.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
63ff5b2ac1 workspace-indicator: Simplify getting status text
Currently the same method is used to get the label text for the
indicator itself and for the menu items.

A method that behaves significantly different depending on whether
a parameter is passed is confusing, so only deal with the indicator
label and directly use the mutter API to get the workspace names
for menu items.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
a9fff9861b workspace-indicator: Small cleanup
The code to update the menu labels is a bit cleaner in the
window-list extension, so use that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
89a3daf9fe workspace-indicator: Only change top bar redirect when in top bar
While this is always the case for the workspace indicator, adding
the check will allow to use the same code in the window list.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
078a5a01ae workspace-indicator: Support showing tooltips above
The indicator is located in the top bar, so tooltips are always
shown below the previews. However supporting showing tooltips
above previews when space permits allows the same code to be
used in the copy that is included with the window-list extension.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
9c8c3495b6 workspace-indicator: Don't use menu section
We never added anything else to the menu, so we can just operate
on the entire menu instead of an intermediate section.

This removes another difference with the window-list copy.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
25e854dde8 workspace-indicator: Use existing property
We already track the current workspace index, use that
instead of getting it from the workspace manager again.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
64060ef4c5 workspace-indicator: Don't use SCHEMA/KEY constants
Each constant is only used once, so all they do is disconnect
the actual value from the code that uses it.

The copy in the window-list extension just uses the strings directly,
do the same here.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
9c97f01bc2 window-list: Handle changes to workspace menu
For now the menu is always set at construction time, however this
will change in the future. Prepare for that by handling the
`menu-set` signal, similar to the top bar.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
8693a8a74c window-list: Externally adjust workspace menu
In order to use a PanelMenu.Button in the bottom bar, we have
to tweak its menu a bit.

We currently handle this inside the indicator, but that means the
code diverges from the original code in the workspace-indicator
extension.

Avoid this by using a small subclass that handles the adjustments.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
47c12c6279 window-list: Override base style class
Apply the changes from the last commit to the workspace-indicator
copy, and override the base style class from the extension.

This will eventually allow us to share the exact same code between
the two extensions, but still use individual styling if necessary.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
e96015b9ea workspace-indicator: Allow overriding base style class
This will allow reusing the code from the window-list extension
without limiting the ability to specify styling that only applies
to one of the extensions.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
d3debab713 window-list: Use consistent style class prefix
This will eventually allow us to re-use the workspace-indicator
extension without changing anything but the used prefix.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
00045b7396 workspace-indicator: Use descendant style selectors
Add a style class to the indicator itself, and only select
descendant elements. This allows using the briefer class names
from the window-list extension without too much risk of conflicts.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
19877302a6 workspace-indicator: Move indicator code into separate file
Shortly after the window-list extension was added, it gained a
workspace switcher based on the workspace indicator extension.

Duplicating the code wasn't a big issue while the switcher was
a simple menu, but since it gained previews with a fair bit of
custom styling, syncing changes between the two extensions has
become tedious, in particular as the two copies have slightly
diverged over time.

In order to allow the two copies to converge again, the indicator
code needs to be separate from the extension boilerplate, so
split out the code into a separate module.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/307>
2024-04-24 14:19:51 +00:00
Florian Müllner
56a74abb8a window-list: Use more appropriate fallback icon
'icon-missing' is not an actual icon name. It somewhat works
because an invalid icon name will fallback to the correct
'image-missing', however for apps the generic app icon is
a better fallback.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/315>
2024-04-24 14:10:41 +00:00
Florian Müllner
78c3957f64 Bump version to 46.1
Update NEWS.
2024-04-21 16:34:14 +02:00
Florian Müllner
38e267ae64 screenshot-window-sizer: Add additional size
1000x700 is the maximum recommended screenshot size on flathub[0]. As
that's a primary use case of the extension, it makes sense to include
the size.

[0] https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/quality-guidelines/#reasonable-window-size

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/317>
2024-04-20 14:33:40 +00:00
Fabio Tomat
59899a211d Update Friulian translation 2024-04-16 19:03:09 +00:00
Matheus Polkorny
d3348761c3 Update Brazilian Portuguese translation 2024-03-29 11:13:45 +00:00
Rachida SACI
79a01c62bc Update Kabyle translation 2024-03-23 09:11:17 +00:00
Florian Müllner
e65c561e6f Bump version to 46.0
Update NEWS.
2024-03-16 01:58:46 +01:00
Florian Müllner
6d36da1ce6 system-monitor: Fix net speed
We use different formats for values above and below 10, to only
include a fraction for the latter.

However we use the same factor to determine the format and to
compute the number to format, with the result that values above
10 are off by a factor of 10.

Address this by adding a separate "unitFactor" value for computing
the value.

Spotted by Yannick Daveluy.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/313>
2024-03-16 00:50:59 +00:00
Ask Hjorth Larsen
cd9341adf1 Update Danish translation 2024-03-13 17:11:10 +00:00
Changwoo Ryu
13842a012b Update Korean translation 2024-03-13 10:15:22 +00:00
Athmane MOKRAOUI
f4f7d2dffb Update Kabyle translation 2024-03-12 11:27:34 +00:00
Quentin PAGÈS
87a5fc42b8 Update Occitan translation 2024-03-12 09:12:03 +00:00
Milo Casagrande
f1456002d4 Update Italian translation 2024-03-08 13:39:43 +00:00
Aral Balkan
30266011bf screenshow-window-sizer: Document keyboard shortcuts
Close https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/492

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/311>
2024-03-06 13:53:50 +01:00
Balázs Úr
5a76dedb50 Update Hungarian translation 2024-03-04 11:35:06 +00:00
Piotr Drąg
dc8ab6cf77 Update Polish translation 2024-03-03 19:05:37 +00:00
Anders Jonsson
b97efdb584 Update Swedish translation 2024-03-03 15:56:53 +00:00
Florian Müllner
a91e6aad87 Bump version to 46.rc
Update NEWS.
2024-03-03 15:39:24 +01:00
Florian Müllner
6f03ca0434 ci: Drop custom image
Since we no longer depend on sassc for classic styling, the
regular JS image from gnome-shell already includes everything
we need for the fedora jobs.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/309>
2024-03-03 15:25:24 +01:00
Florian Müllner
7a01e3e103 ci: Update to F40-based image
gnome-shell switched to F40 for its JS image, follow suit.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/309>
2024-03-03 15:10:50 +01:00
Jiri Grönroos
e539a65709 Update Finnish translation 2024-03-02 15:31:24 +00:00
Daniel Mustieles
2402c1bef5 Updated Spanish translation 2024-02-26 14:10:47 +01:00
Guillaume Bernard
1fd238b31d Update French translation 2024-02-25 12:53:54 +00:00
Rūdolfs Mazurs
21a65c1558 Update Latvian translation 2024-02-25 10:49:23 +00:00
Baurzhan Muftakhidinov
f42d1f7ca9 Update Kazakh translation 2024-02-24 18:03:25 +00:00
Brage Fuglseth
b77ecb2380 Update Norwegian Bokmål translation 2024-02-24 13:42:23 +00:00
Andi Chandler
4fc80e0ef3 Update British English translation 2024-02-23 12:23:32 +00:00
Fran Dieguez
df61f9aadf Update Galician translation 2024-02-23 09:27:53 +00:00
Kukuh Syafaat
7862bfd2aa Update Indonesian translation 2024-02-22 13:20:52 +00:00
Florian Müllner
f6c74e93b7 window-list: Replace Meta.Rectangle
It's deprecated in favor of Mtk.Rectangle, which is a drop-in
replacement.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/306>
2024-02-22 00:02:40 +00:00
Sabri Ünal
81880982b2 Update Turkish translation 2024-02-21 17:24:56 +00:00
Florian Müllner
f53984670c window-list: Fix menu ornament in workspace indicator
The default ornament is now HIDDEN, so in order to align items,
we always have set an initial ornament.

In gnome-shell 46, the expected "counter ornament" to DOT is NO_DOT
rather than NONE, so use that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/305>
2024-02-21 00:07:15 +01:00
Florian Müllner
537530707e workspace-indicator: Fix menu ornament
The default ornament is now HIDDEN, so in order to align items,
we always have set an initial ornament.

In gnome-shell 46, the expected "counter ornament" to DOT is NO_DOT
rather than NONE, so use that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/305>
2024-02-21 00:01:11 +01:00
Boyuan Yang
e069f391c7 Update Chinese (China) translation 2024-02-20 14:06:58 +00:00
Florian Müllner
b00f5c4604 window-list: Fix window previews
St.Bin no longer expands its child automatically. Unless do we do
explicitly, the preview actor will be allocated with a size of 0x0.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/304>
2024-02-19 19:59:54 +01:00
Florian Müllner
a326fa737e workspace-indicator: Fix window previews
St.Bin no longer expands its child automatically. Unless do we do
explicitly, the preview actor will be allocated with a size of 0x0.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/304>
2024-02-19 19:59:54 +01:00
Matej Urbančič
fcd5618321 Update Slovenian translation 2024-02-19 10:08:02 +00:00
Aurimas Černius
55e085894a Update Lithuanian translation 2024-02-18 20:38:56 +00:00
Nathan Follens
801ba69f54 Update Dutch translation 2024-02-18 16:18:10 +00:00
Brage Fuglseth
abdd839073 Update Norwegian Bokmål translation 2024-02-17 21:46:21 +00:00
Yaron Shahrabani
24a5c5fd4e Update Hebrew translation 2024-02-16 22:15:45 +00:00
Asier Sarasua Garmendia
6d49de36a8 Update Basque translation 2024-02-15 18:10:00 +00:00
Vasil Pupkin
ef3c74db8a Update Belarusian translation 2024-02-15 05:28:14 +00:00
Yuri Chornoivan
419b7fad10 Update Ukrainian translation 2024-02-13 17:43:29 +00:00
Artur S0
ad43f16a9a Update Russian translation 2024-02-13 16:33:00 +00:00
Sabri Ünal
db8b779859 Update Turkish translation 2024-02-13 13:34:13 +00:00
Ekaterine Papava
67a91f9a1d Update Georgian translation 2024-02-12 17:39:32 +00:00
Danial Behzadi
ec95dcd330 Update Persian translation 2024-02-12 16:58:42 +00:00
Danial Behzadi
b71ddd1b00 Update Persian translation 2024-02-12 16:48:40 +00:00
Florian Müllner
d6ffd7859e Bump version to 46.beta
Update NEWS.
2024-02-11 17:59:16 +01:00
Gabriel Brand
ded50f8b01 Update German translation 2024-02-08 16:36:27 +00:00
Daniel Rusek
06066be0a8 Update Czech translation 2024-02-07 14:08:50 +00:00
Florian Müllner
fb52f89cc5 system-monitor: Adjust to renamed .desktop file
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/302>
2024-02-06 20:47:44 +01:00
Allan Day
86761952c3 apps-menu: Rename Applications to Apps
Nowadays people call applications apps, and GNOME uses the latter
term rather than the former.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/299>
2024-02-06 19:40:30 +01:00
Sabri Ünal
edc916533a Update Turkish translation 2024-02-06 18:25:32 +00:00
Yosef Or Boczko
6a7e99eb81 Update Hebrew translation 2024-02-05 19:49:02 +00:00
Artur S0
8ca1d5f3ee Update Russian translation 2024-02-05 06:31:00 +00:00
Vasil Pupkin
a3068dc145 Update Belarusian translation 2024-02-03 22:45:30 +00:00
Florian Müllner
3e9d648078 apps-menu: Stop using deprecated vscroll-bar property
The adjustments are now exposed by the view itself.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/301>
2024-02-02 19:37:39 +01:00
Florian Müllner
3e398b9a2f apps-menu: Stop setting scroll policy
The defaults are now "automatic" for vertical scrolling and "never"
for horizontal scrolling, so no need to set that explicitly.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/301>
2024-02-02 19:37:39 +01:00
Florian Müllner
3fb756687b apps-menu: Remove obsolete code
There hasn't been a `passEvents` property on menus since 2011.

Not that it hurts setting it, but it simply doesn't do anything.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/301>
2024-02-02 19:37:39 +01:00
Aefgh Threenine
93fb1a6496 Update Thai translation 2024-02-02 08:50:43 +00:00
Florian Müllner
dfa328a769 ci: Do not create pipelines for branches with open MRs
Pipelines for non-protected branches are set to 'manual', and
thus cheap. However they may still get picked by `@marge-bot`,
meaning that the bot waits for the completion of a pipeline that
never starts.

Avoid that by not creating pipelines for branches with open
merge requests.

Credit to Jordan, who came up with this for gst.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/300>
2024-02-01 16:18:03 +01:00
Fran Dieguez
90b59b6753 Update Galician translation 2024-01-23 21:19:29 +00:00
Daniel Rusek
121c9d891b Update Czech translation 2024-01-22 14:28:45 +00:00
Gabriel Brand
e6a8046d33 Update German translation 2024-01-19 22:38:30 +00:00
Florian Müllner
3cd964e60d system-monitor: Fix POTFILES entry
The gsettings schema is in a subdirectory, whoops.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/297>
2024-01-13 18:45:55 +01:00
Florian Müllner
fa8866d627 ci: Check for missing entries in POTFILES
It is a common mistake to add new translatable strings without
adding the corresponding file to POTFILES. At least for JS sources,
we have a tool we can use to catch these errors during CI.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/296>
2024-01-07 20:12:39 +01:00
Florian Müllner
bf3cb76766 ci: Update default image
We are using a fairly outdated image by now, update to the latest
image that gnome-shell produces.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/296>
2024-01-07 20:12:39 +01:00
Florian Müllner
25d02d17d2 system-monitor: Add missing files to POTFILES
The files contain translatable strings, but were not added to
POTFILES, whoops.

Spotted by Piotr (of course).

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/296>
2024-01-07 20:12:39 +01:00
Florian Müllner
ffcbf03c9c Bump version to 46.alpha
Update NEWS.
2024-01-06 22:16:52 +01:00
Florian Müllner
1d7f37f420 system-monitor: Add new extension
A long time ago, we used to include a system monitor extension,
that added CPU/memory graphs to the (long gone) message tray.

However demand for this type of extensions hasn't died down, to the
point where RHEL includes a revived version of the old extension.

Account for that demand by adding a newly written system-monitor
extension that has been properly designed, and hopefully does not
bring back the CPU/memory issues of the previous one (unlikely
without the graphs) …

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/277>
2023-12-04 13:20:13 +01:00
Florian Müllner
30a15387b5 workspace-indicator: Update visibility on window-type changes
The visibility depends on the type, so we should listen for
changes (even if the property is unlikely to change).

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/292>
2023-12-01 19:14:26 +01:00
Florian Müllner
b5b841dd38 workspace-indicator: Don't hide previews on other monitors
Workspace thumbnails are clipped, so there's no major benefit
of hiding the actors explicitly.

On the other hand, the check is useful on size/position changes
to avoid unnecessary relayouts.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/292>
2023-12-01 19:13:42 +01:00
Florian Müllner
5f2b199627 Revert "workspace-indicator: Only initialize preview visibility on map"
It is not possible to unmap an actor from within the map vfunc,
so the fix broke the initial visibility again.

This reverts commit 25a75e1b0e.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/292>
2023-12-01 19:11:42 +01:00
Florian Müllner
071584621e window-list: Update visibility on window-type changes
The visibility depends on the type, so we should listen for
changes (even if the property is unlikely to change).

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/292>
2023-12-01 19:10:08 +01:00
Florian Müllner
5c57f44838 window-list: Don't hide previews on other monitors
Workspace thumbnails are clipped, so there's no major benefit
of hiding the actors explicitly.

On the other hand, the check is useful on size/position changes
to avoid unnecessary relayouts.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/292>
2023-12-01 19:09:30 +01:00
Florian Müllner
93741e9e1c Revert "window-list: Only initialize preview visibility on map"
It is not possible to unmap an actor from within the map vfunc,
so the fix broke the initial visibility again.

This reverts commit 8b7cfff558.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/292>
2023-12-01 19:09:30 +01:00
Florian Müllner
836f81f2e2 window-list: Move additional padding into buttons
Commit ca1c4b0f9e added additional padding, which means that the
interactive area of buttons no longer extends to the bottom of
the screen.

Address this by moving the new padding into the buttons themselves.
That restores the Fittsability of the bottom bar, without affecting
the cleaner visual appearance.

Close https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/453

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/291>
2023-12-01 12:34:20 +00:00
Florian Müllner
574638328e window-list: Clean up stylesheet indent
Replaces tabs with spaces.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/291>
2023-12-01 12:34:20 +00:00
Jonas Ådahl
e0750db1bd Mark session file as X-GDM-CanRunHeadless=true
This will make it possible to launch the session headlessly for
remote-only access.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/289>
2023-11-30 20:41:58 +00:00
Florian Müllner
5652182fb3 apps-menu: Use customized layout manager to limit height
To avoid continuous height changes while browsing through categories,
we let the list of categories determine the overall height, and rely
on scrolling for the list of apps within a category.

We currently achieve this by assigning a fixed height via the
`style` property. This has been found to trigger a crash when
running headless, as we end up querying an actor's height request
before a valid resource scale is available.

Instead, use a custom layout manager, which seems more elegant anyway.

Close: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/472
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
2023-11-23 21:20:56 +01:00
Florian Müllner
c3cbef19ac apps-menu: Remove vertical separator
Ever since gnome-shell stopped using a stippled separator in the
calendar menu, the styling required by the separator has been
missing.

There haven't been any complaints about the invisible separator,
so we can just as well drop it altogether.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
2023-11-23 21:15:51 +01:00
Florian Müllner
8c8f990a28 apps-menu: Use stylesheet to set width
The `style` property is useful for computed CSS declarations,
but for regular styling the stylesheet is preferable.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
2023-11-23 21:13:30 +01:00
Florian Müllner
f6a6bdda99 apps-menu: Adjust to events API changes
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
2023-11-23 14:25:57 +01:00
Florian Müllner
0d5d06fdd7 apps-menu: Adjust to ClutterContainer removal
The `actor-added` signal got renamed to `child-added` when
moving it to ClutterActor.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/288>
2023-11-14 16:26:06 +00:00
Florian Müllner
d10b98c4fc extensions: Stop using ClutterContainer API
The methods have long been deprecated in favor of the equivalent
ClutterActor methods, so use the latter instead.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/288>
2023-11-14 16:26:06 +00:00
Florian Müllner
8b7cfff558 window-list: Only initialize preview visibility on map
The check whether the window overlaps with the monitor the actor
is on requires the actor to be added to the stage first, so delay
the initial visibility update that was added in commit f576f1b1b6.

Fixes: f576f1b1 ("window-list: Initialize preview visibility")
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/286>
2023-11-08 16:36:59 +00:00
Florian Müllner
25a75e1b0e workspace-indicator: Only initialize preview visibility on map
The check whether the window overlaps with the monitor the actor
is on requires the actor to be added to the stage first, so delay
the initial visibility update that was added in commit b9d2a445b2.

Fixes: b9d2a445 ("workspace-indicator: Initialize preview visibility")
Closes:
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/469

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/286>
2023-11-08 16:36:59 +00:00
Florian Müllner
91a1b8245b window-list: Remove window picker
Now that the overview is available again in the classic session,
the window picker that used to replace it is unused.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/287>
2023-11-07 17:43:18 +01:00
Florian Müllner
4abde90e82 classic: Reenable overview
Since we disabled the overview in the classic session, gnome-shell
switched to a horizontal workspace layout and replaced the activities
button with an indicator.

Those are big enough changes to reevaluate the decision, so remove
the delta with the regular session and turn it back on.

This reverts commit 82d2011061.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/287>
2023-11-07 16:38:37 +01:00
Florian Müllner
dd8ee2931a screenshot-window-sizer: Handle wrapping around backwards
The mod takes care of wrapping at the top, but not when
decrementing 0. Fix this by using Array.prototype.at(),
which handles negative indexes.

Close https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/467

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/284>
2023-10-24 21:15:06 +02:00
Florian Müllner
f530acbf9e screenshot-window-sizer: Use built-in support for reversed bindings
Mutter has had explicit support for reversed bindings for a while now.
Use that, as it's more reliably than examining the modifiers manually.

Close https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/467

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/284>
2023-10-24 21:15:06 +02:00
Brage Fuglseth
7d296d2fd2 Update Norwegian Bokmål translation 2023-10-12 20:28:03 +00:00
Florian Müllner
fb858ed0e4 window-list: Complete move to connectObject()
Commit 3bfaf6f88a removed the explicit disconnect, but forgot
to use connectObject() to connect the handler.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/459
Fixes: 3bfaf6f8 ("js: Use connectObject()")
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/281>
2023-10-09 15:36:39 +02:00
Florian Müllner
f576f1b1b6 window-list: Initialize preview visibility
Otherwise we can end up showing window previews in the workspace
thumbnail that shouldn't be visible, if none of the properties we
track for updates changes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/280>
2023-09-29 21:35:33 +02:00
Florian Müllner
b9d2a445b2 workspace-indicator: Initialize preview visibility
Otherwise we can end up showing windows that shouldn't be visible
if none of the properties we track for updates changes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/280>
2023-09-29 21:33:04 +02:00
Florian Müllner
092b268823 drive-menu: Remove left-over signal connection
The handler itself was removed in commit 3bfaf6f88a, so the
code now fails.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/455
Fixes: 3bfaf6f8 ("js: Use connectObject()")
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/278>
2023-09-29 12:33:13 +00:00
Kristjan SCHMIDT
b64cb0f195 Update Esperanto translation 2023-09-27 20:47:58 +00:00
Florian Müllner
2510bb3625 extensions: Stop using run_dispose()
It is considered bad practice, and mainly a lazy way of disconnecting
signal handlers without tracking individual handler IDs.

We can do better by using connectObject(), which provides the same
level of convenience without the dodginess of getting behind the
garbage collector's back.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/275>
2023-09-26 15:21:41 +00:00
Florian Müllner
4fbd878208 lint: Sync with gnome-shell
gnome-shell itself no longer requires parameter descriptions in
doc comments (just type annotations). The requirement makes even
less sense for extensions, so sync up the configuration.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/276>
2023-09-26 14:30:27 +02:00
Florian Müllner
e8840da00c doap: Actually remove defunct mailing list
Fixes: e405d09c ("DOAP: Remove defunct mailing list; add Discourse")
2023-09-20 13:30:42 +02:00
Florian Müllner
ba5783ff8c Bump version to 45.0
Update NEWS.
2023-09-16 20:29:57 +02:00
Andre Klapper
e405d09c98 DOAP: Remove defunct mailing list; add Discourse 2023-09-15 22:08:36 +02:00
Bruce Cowan
fee98cf385 Update British English translation
(cherry picked from commit 54d6a839f849bbe7c6acbbe03adbcbb909dbd80a)
2023-09-06 11:14:58 +00:00
Florian Müllner
e6b6b0c589 Bump version to 45.rc
Update NEWS.
2023-09-06 11:53:48 +02:00
Florian Müllner
f54b96c327 auto-move: Fix signal name
The functionality is still broken for wayland windows that use
xdg-activation, because the workspace information from the startup
sequence is handled later.

But at least it's a baby step towards a fix.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/272>
2023-09-06 00:00:36 +02:00
A S Alam
5e025ba194 Update Punjabi translation 2023-09-02 15:54:18 +00:00
Florentina Musat
5bf98cbe8f Update Romanian translation 2023-08-17 16:26:01 +00:00
Florian Müllner
3677931bd2 ci: Add reuse job
Now that we are Reuse-compliant, check for it during CI to make
sure we remain compliant.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/224>
2023-08-17 11:51:48 +00:00
Florian Müllner
b7f285d733 Make project compatible with Reuse Software spec
Provide all licenses used in the project in a LICENSES folder and
add SPDX license and copyright information for all files in
accordance with the Reuse Software[0] specification.

The copyright information is based on the file's git history,
using a fairly generous definition of "non-trivial".

As of the spec recommendation, the information is generally added
as comments in the files themselves, except for

 - NEWS, README and similar top-level standard files, so that
   a SPDX code isn't the first thing people encounter
 - files that don't support comments (json) or where they'd
   be a bit awkward (.desktop, .service)
 - anything under po/, to not interfere with translation teams

Those are covered by a .reuse/dep5 files, except for image assets,
where separate .license files are used (It would be possible to
add comments to SVG files, but I don't trust image editors to
preserve them).

[0] https://reuse.software/

Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/224>
2023-08-17 11:51:48 +00:00
Florian Müllner
b966cb6b22 doap: Remove Giovanni from maintainers
He is an emeritus member, which means he is no longer active.

In particular he is no longer in the 'gnomecvs' group, which
is a pre-condition for being listed in the .doap file.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/267>
2023-08-17 11:41:21 +00:00
Sabri Ünal
e238b0f6aa Update Turkish translation 2023-08-16 18:38:33 +00:00
144 changed files with 11879 additions and 6210 deletions

17
.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2024 Florian Müllner <fmuellner@gnome.org>
# SPDX-License-Identifier: CC0-1.0
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
trim_trailing_whitespace = true
[*.js]
indent_size = 4
[meson.build]
indent_size = 2

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2019 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
extends:
- ./lint/eslintrc-gjs.yml
- ./lint/eslintrc-shell.yml

5
.gitignore vendored
View File

@@ -1,3 +1,8 @@
# SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
# SPDX-FileCopyrightText: 2023 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: CC0-1.0
po/gnome-shell-extensions.pot
zip-files/
*~

View File

@@ -1,6 +1,15 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
include:
- remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/bbe5232986c9b98eb1efe62484e07216f7d1a4df/templates/fedora.yml'
- remote: "https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/6f86b8bcb0cd5168c32779c4fea9a893c4a0c046/templates/ci-fairy.yml"
- remote: 'https://gitlab.gnome.org/Infrastructure/freedesktop-ci-templates/-/raw/master/templates/fedora.yml'
- remote: "https://gitlab.gnome.org/Infrastructure/freedesktop-ci-templates/-/raw/master/templates/ci-fairy.yml"
- component: gitlab.gnome.org/GNOME/citemplates/release-service@master
inputs:
job-stage: deploy
dist-job-name: fedora-dist-tarball
tarball-artifact-path: "$TARBALL_ARTIFACT_PATH"
stages:
- pre_review
@@ -10,7 +19,7 @@ stages:
- deploy
default:
image: registry.gitlab.gnome.org/gnome/gnome-shell/fedora/35:2022-02-18.0
image: registry.gitlab.gnome.org/gnome/gnome-shell/fedora/41:2024-10-18.0
# Cancel jobs if newer commits are pushed to the branch
interruptible: true
# Auto-retry jobs in case of infra failures
@@ -24,10 +33,13 @@ default:
variables:
FDO_UPSTREAM_REPO: GNOME/gnome-shell-extensions
LINT_LOG: "eslint-report.xml"
MESON_BUILD_DIR: build
TARBALL_ARTIFACT_PATH: "${MESON_BUILD_DIR}/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz"
workflow:
rules:
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
when: never
- if: '$CI_MERGE_REQUEST_IID'
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH'
@@ -40,13 +52,6 @@ workflow:
- if: '$CI_COMMIT_BRANCH =~ /^gnome-[0-9-]+$/'
- when: 'manual'
.gnome-shell-extensions.fedora:34:
variables:
FDO_DISTRIBUTION_VERSION: 34
FDO_DISTRIBUTION_TAG: '2021-08-31.0'
FDO_DISTRIBUTION_PACKAGES: >
meson git gettext sassc
.prereview_req: &prereview_req
needs:
- check_commit_log
@@ -90,12 +95,13 @@ check-merge-request:
reports:
junit: check-merge-request-report.xml
build-fedora-container:
extends:
- .fdo.container-build@fedora@x86_64
- .gnome-shell-extensions.fedora:34
stage: prepare
<<: *prereview_req
check-reuse:
stage: pre_review
image:
name: fsfe/reuse:latest
entrypoint: [""]
script:
- reuse lint
js_check:
stage: review
@@ -106,14 +112,25 @@ js_check:
eslint:
stage: review
<<: *prereview_req
variables:
LINT_LOG: "eslint-report.xml"
script:
- export NODE_PATH=$(npm root -g)
- ./.gitlab-ci/run-eslint --output-file ${LINT_LOG} --format junit --stdout
- ./.gitlab-ci/run-eslint --output-file "$LINT_LOG" --format junit --stdout
artifacts:
paths:
- ${LINT_LOG}
- "$LINT_LOG"
reports:
junit: ${LINT_LOG}
junit: "$LINT_LOG"
potfile_js_check:
stage: review
<<: *prereview_req
script:
- gjs-check-potfiles
artifacts:
reports:
junit: gjs-check-potfiles.junit.xml
build-bundles:
stage: build
@@ -127,32 +144,25 @@ build-bundles:
- zip-files/
fedora-build:
extends:
- .fdo.distribution-image@fedora
- .gnome-shell-extensions.fedora:34
stage: build
needs:
- build-fedora-container
<<: *prereview_req
script:
- meson setup build --werror -Dextension_set=all -Dclassic_mode=true
- meson compile -C build
- meson test -C build
- meson install -C build
- meson setup "$MESON_BUILD_DIR" --werror -Dextension_set=all -Dclassic_mode=true
- meson compile -C "$MESON_BUILD_DIR"
- meson test -C "$MESON_BUILD_DIR"
- meson install -C "$MESON_BUILD_DIR"
artifacts:
paths:
- build
- "$MESON_BUILD_DIR"
fedora-dist:
extends:
- .fdo.distribution-image@fedora
- .gnome-shell-extensions.fedora:34
stage: deploy
needs:
- fedora-build
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- meson dist -C build
- meson dist -C "$MESON_BUILD_DIR"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
@@ -163,7 +173,9 @@ fedora-dist-tarball:
extends: fedora-dist
artifacts:
expose_as: 'Get tarball here'
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}"
when: always
paths:
- build/meson-dist/$CI_PROJECT_NAME-$CI_COMMIT_TAG.tar.xz
- "$TARBALL_ARTIFACT_PATH"
rules:
- if: '$CI_COMMIT_TAG'

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2021 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
patterns:
deny:
- regex: '^$CI_MERGE_REQUEST_PROJECT_URL/(-/)?merge_requests/$CI_MERGE_REQUEST_IID$'

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env node
// SPDX-FileCopyrightText: 2023 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
const {ESLint} = require('eslint');
console.log(`Running ESLint version ${ESLint.version}...`);

22
.reuse/dep5 Normal file
View File

@@ -0,0 +1,22 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: gnome-shell-extensions
Upstream-Contact: Florian Müllner <fmuellner@gnome.org>
Source: https://gitlab.gnome.org/GNOME/gnome-shell-extensions
Files: NEWS README.md HACKING.md data/HACKING
Copyright: No rights reserved
License: CC0-1.0
Files: *.json.in *.desktop.in *.gschema.override
Copyright: Florian Müllner <fmuellner@gnome.org>
License: GPL-2.0-or-later
# managed by translation teams
Files: po/*.po
Copyright: GNOME Translation Teams <i18n@gnome.org>
License: GPL-2.0-or-later
# managed by translation teams
Files: po/LINGUAS po/POTFILES.in
Copyright: No rights reserved
License: CC0-1.0

View File

@@ -20,9 +20,6 @@ need in gnome-shell.
Generally, we follow [GJS coding style][coding-style], which in short is:
indent 4 spaces, no tabs, space after comma, no space after function call.
The Emacs mode line for this
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
Imports should be at the top, in two groups, one for standard
imports (like imports.lang or imports.dbus) and introspection,
the other for Shell API. Within the same group, put everything

121
LICENSES/CC0-1.0.txt Normal file
View File

@@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@@ -0,0 +1,117 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
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. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice

View File

@@ -0,0 +1,174 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license.
The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such.
Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library.
Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.
(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.
In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.
Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.
If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:
a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)
b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.
d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.
7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.
b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License).
To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the library's name and an idea of what it does.
Copyright (C) year name of author
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in
the library `Frob' (a library for tweaking knobs) written
by James Random Hacker.
signature of Ty Coon, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

9
LICENSES/MIT.txt Normal file
View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

195
NEWS
View File

@@ -1,3 +1,198 @@
47.5
====
* Allow disabling the X11 session [Neal; !396, !400]
Contributors:
Neal Gompa
47.4
====
* window-list: Fix regression in chrome tracking [Florian; !379]
* Misc. bug fixes and cleanups [Florian; !376]
Contributors:
Florian Müllner
47.3
====
* places-menu: Fix opening drives with mount operations [Florian; !361]
* window-list: Fix hiding when entering overview with gestures [Florian; !364]
* workspace-indicator: Only show previews of regular windows [Florian; !363]
* Misc. bug fixes and cleanups [Florian, Bartłomiej; !362, !365, !367,
!368, !370]
Contributors:
Florian Müllner, Bartłomiej Piotrowski
Translators:
Yi-Jyun Pan [zh_TW]
47.2
====
* places-menu: Fix a11y labelling [Florian; #542]
* screenshot-window-sizer: Mention shortcut in description [Florian; !358]
* Misc. bug fixes and cleanups [Florian; !353, !354]
Contributors:
Florian Müllner
Translators:
Fabio Tomat [fur], Nathan Follens [nl], Марко Костић [sr]
47.1
====
* classic: Add missing top-bar indicators [Florian; !339]
* window-list: Fix window state styling [Florian; !342]
* window-list: Fix "ignore-workspace" setting getting reset [Florian; !341]
* Misc. bug fixes and cleanups [Florian; !337, !338, !345, !347, !349]
Contributors:
Florian Müllner
47.0
====
Translators:
twlvnn kraftwerk [bg], Alexander Shopov [bg], Fran Dieguez [gl],
Aurimas Černius [lt], Daniel [es], Andika Triwidada [id],
Andi Chandler [en_GB], Ask Hjorth Larsen [da], Aefgh Threenine [th],
Dušan Kazik [sk], Rūdolfs Mazurs [lv], Irénée THIRION [fr]
47.rc
=====
* Misc. bug fixes and cleanups [Sophie; !333]
Contributors:
Sophie Herold
Translators:
Daniel Șerbănescu [ro], Giannis Antypas [el], Ekaterine Papava [ka],
Jordi Mas i Hernandez [ca], Yuri Chornoivan [uk], Jiri Grönroos [fi],
Daniel Rusek [cs], Vasil Pupkin [be], Luming Zh [zh_CN], Brage Fuglseth [nb],
Asier Sarasua Garmendia [eu], Danial Behzadi [fa], Rafael Fontenelle [pt_BR],
Quentin PAGÈS [oc], Anders Jonsson [sv], Jürgen Benvenuti [de],
Changwoo Ryu [ko], Hugo Carvalho [pt], Piotr Drąg [pl], Sabri Ünal [tr]
47.beta
=======
* window-list: Modernize styling [Jakub; !330]
* Include "status-icons" extension [Florian; !194]
* Misc. bug fixes and cleanups [Florian; !328, !331, !327]
Contributors:
Florian Müllner, Jakub Steiner
Translators:
Sabri Ünal [tr], Chao-Hsiung Liao [zh_TW]
47.alpha
========
* Improve workspace previews in window-list and workspace-indicator
[Florian; !307, !316]
* apps-menu: Fix a11y of category labels [Florian; !319]
* window-list: Fix long-press support [Florian; !320]
* window-list: Animate transitions [Florian; !325]
* Misc. bug fixes and cleanups [Florian; !315, !321, !324]
Contributors:
Florian Müllner
Translators:
Jordi Mas i Hernandez [ca], Martin [sl], Hugo Carvalho [pt], Jose Riha [sk],
Scrambled 777 [hi], Artur S0 [ru], Милош Поповић [sr], Yosef Or Boczko [he],
Balázs Úr [hu]
46.1
====
* screenshot-window-sizer: Add flathub-recommended size [Florian; !317]
Contributors:
Florian Müllner
Translators:
Rachida SACI [kab], Matheus Polkorny [pt_BR], Fabio Tomat [fur]
46.0
====
* system-monitor: Fix net speed [Florian; !313]
* Misc. bug fixes and cleanups [Aral; !311]
Contributors:
Aral Balkan, Florian Müllner
Translators:
Anders Jonsson [sv], Piotr Drąg [pl], Balázs Úr [hu], Milo Casagrande [it],
Quentin PAGÈS [oc], Athmane MOKRAOUI [kab], Changwoo Ryu [ko],
Ask Hjorth Larsen [da]
46.rc
=====
* Fix window previews in workspace indicator [Florian; !304]
* Fix menu ornament in workspace indicator [Florian; !305]
* Misc. bug fixes and cleanups [Florian; !306, !309]
Contributors:
Florian Müllner
Translators:
Danial Behzadi [fa], Ekaterine Papava [ka], Sabri Ünal [tr], Artur S0 [ru],
Yuri Chornoivan [uk], Vasil Pupkin [be], Asier Sarasua Garmendia [eu],
Yaron Shahrabani [he], Brage Fuglseth [nb], Nathan Follens [nl],
Aurimas Černius [lt], Matej Urbančič [sl], Boyuan Yang [zh_CN],
Kukuh Syafaat [id], Fran Dieguez [gl], Andi Chandler [en_GB],
Baurzhan Muftakhidinov [kk], Rūdolfs Mazurs [lv], Guillaume Bernard [fr],
Daniel Mustieles [es], Jiri Grönroos [fi]
46.beta
=======
* apps-menu: Rename Applications to Apps [Allan; !299]
* Misc. bug fixes and cleanups [Florian; !296, !297, !300, !301, !302]
Contributors:
Allan Day, Florian Müllner
Translators:
Gabriel Brand [de], Daniel Rusek [cs], Fran Dieguez [gl],
Aefgh Threenine [th], Vasil Pupkin [be], Artur S0 [ru], Yosef Or Boczko [he],
Sabri Ünal [tr]
46.alpha
========
* workspace-indicator: Fix initial preview visibility [Florian; !280, !292]
* screenshot-window-sizer: Fix cycling between sizes backwards [Florian; !284]
* Add back overview in Classic session [Florian; !287]
* Allow running Classic session headless [Jonas; !289]
* window-list: Fix buttons not being clickable at the screen edge
[Florian; !291]
* Add system-monitor extension [Florian; !277]
* Fixed crash [Florian; !290]
* Misc. bug fixes and cleanups [Florian; !276, !275, !278, !281, !286, !288]
Contributors:
Jonas Ådahl, Florian Müllner
Translators:
Kristjan SCHMIDT [eo], Brage Fuglseth [nb]
45.0
====
Contributors:
Andre Klapper
Translators:
Bruce Cowan [en_GB]
45.rc
=====
* Misc. bug fixes and cleanups [Florian; !267, !224, !272]
Contributors:
Florian Müllner
Translators:
Sabri Ünal [tr], Florentina Musat [ro], A S Alam [pa]
45.beta
=======
* Port extensions to ESM [Florian; !259, !266, !268, !269]

View File

@@ -51,7 +51,7 @@ GSettings key.
* screenshot-window-sizer
Adds a shortcut for resizing the focus window to a size that is suitable for GNOME Software screenshots
Adds a shortcut for resizing the focus window to a size that is suitable for GNOME Software screenshots. Ctrl + Alt + s cycles forwards through the available sizes and Ctrl + Alt + Shift + s cycles backwards.
* user-theme

View File

@@ -1,11 +1,10 @@
{
"parentMode": "user",
"colorScheme": "force-light",
"hasOverview": false,
"showWelcomeDialog": false,
"enabledExtensions": [@CLASSIC_EXTENSIONS@],
"panel": { "left": [],
"panel": { "left": ["activities"],
"center": [],
"right": ["a11y", "keyboard", "dateMenu", "quickSettings"]
"right": ["screenRecording", "screenSharing", "dwellClick", "a11y", "keyboard", "dateMenu", "quickSettings"]
}
}

View File

@@ -6,3 +6,4 @@ TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Classic;GNOME;
X-GDM-SessionRegisters=true
X-GDM-CanRunHeadless=true

View File

@@ -6,3 +6,4 @@ TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Classic;GNOME;
X-GDM-SessionRegisters=true
X-GDM-CanRunHeadless=true

View File

@@ -1,38 +1,47 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
have_x11 = get_option('x11')
session_desktop_base = 'gnome-classic'
session_desktops = [
session_desktop_base,
session_desktop_base + '-xorg',
session_desktop_base + '-wayland',
]
foreach name: session_desktops
session_desktop = name + '.desktop'
if name.endswith('-xorg')
session_instdir = xsessiondir
elif name.endswith('-wayland')
session_instdir = wlsessiondir
else
# FIXME: The same target can not be copied into two directories.
# There is a workaround in meson/session-post-install.py until proper
# solution arises:
# https://github.com/mesonbuild/meson/issues/2416
session_instdir = xsessiondir
#session_instdir = [ xesssiondir, wlsessiondir ]
endif
i18n.merge_file(
input: session_desktop + '.in',
output: session_desktop,
po_dir: '../po',
install: true,
install_dir: session_instdir,
type: 'desktop'
)
if have_x11
session_desktops += [session_desktop_base + '-xorg']
endif
foreach name : session_desktops
session_desktop = name + '.desktop'
if name.endswith('-xorg')
session_instdir = xsessiondir
elif name.endswith('-wayland')
session_instdir = wlsessiondir
else
# FIXME: The same target can not be copied into two directories.
# There is a workaround in meson/session-post-install.py until proper
# solution arises:
# https://github.com/mesonbuild/meson/issues/2416
session_instdir = wlsessiondir
#session_instdir = [ xesssiondir, wlsessiondir ]
endif
i18n.merge_file(
input: session_desktop + '.in',
output: session_desktop,
po_dir: '../po',
install: true,
install_dir: session_instdir,
type: 'desktop',
)
endforeach
classic_uuids = []
foreach e : classic_extensions
classic_uuids += e + uuid_suffix
classic_uuids += e + uuid_suffix
endforeach
mode_conf = configuration_data()
@@ -43,7 +52,7 @@ configure_file(
input: mode_file + '.in',
output: mode_file,
configuration: mode_conf,
install_dir: modedir
install_dir: modedir,
)
classic_override = '00_org.gnome.shell.extensions.classic.gschema.override'

View File

@@ -1,19 +1,23 @@
#!/bin/bash
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
srcdir=`dirname $0`
srcdir=`(cd $srcdir && pwd)`
builddir=`mktemp -p $srcdir -d _build.XXXXXX` || exit 1
installdir=`mktemp -p $srcdir -d _install.XXXXXX` || exit 1
destdir=`mktemp -p $srcdir -d _dest.XXXXXX` || exit 1
meson setup --prefix=$installdir -Dextension_set=all $srcdir $builddir
meson install -C $builddir
meson setup --prefix=/usr -Dextension_set=all $srcdir $builddir
meson install --destdir $destdir -C $builddir
rm -rf $srcdir/zip-files
mkdir $srcdir/zip-files
extensiondir=$installdir/share/gnome-shell/extensions
schemadir=$installdir/share/glib-2.0/schemas
extensiondir=$destdir/usr/share/gnome-shell/extensions
schemadir=$destdir/usr/share/glib-2.0/schemas
for f in $extensiondir/*; do
name=`basename ${f%%@*}`
@@ -35,7 +39,9 @@ for f in $extensiondir/*; do
fi
cp $srcdir/NEWS $srcdir/COPYING $f
sources=(NEWS COPYING $(cd $f; ls *.js))
sources=(NEWS COPYING $(cd $f; ls *.js *.css 2>/dev/null))
[ -d $f/icons ] && sources+=(icons)
[ -f $schema ] || unset schema
@@ -44,4 +50,4 @@ for f in $extensiondir/*; do
done
rm -rf $builddir
rm -rf $installdir
rm -rf $destdir

View File

@@ -1,4 +1,10 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
// SPDX-FileCopyrightText: 2011 Vamsi Krishna Brahmajosyula <vamsikrishna.brahmajosyula@gmail.com>
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2013 Debarshi Ray <debarshir@gnome.org>
// SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Atk from 'gi://Atk';
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
@@ -118,7 +124,10 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem {
else
name = _('Favorites');
this.add_child(new St.Label({text: name}));
const label = new St.Label({text: name});
this.add_child(label);
this.actor.label_actor = label;
this.connect('motion-event', this._onMotionEvent.bind(this));
this.connect('notify::active', this._onActiveChanged.bind(this));
}
@@ -207,9 +216,9 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem {
this._grab?.dismiss();
delete this._grab;
let source = event.get_source();
if (source instanceof St.Widget)
source.sync_hover();
const targetActor = global.stage.get_event_actor(event);
if (targetActor instanceof St.Widget)
targetActor.sync_hover();
return false;
}
@@ -248,7 +257,7 @@ class DesktopTarget extends EventEmitter {
this._desktopDestroyedId = 0;
this._windowAddedId =
global.window_group.connect('actor-added',
global.window_group.connect('child-added',
this._onWindowAdded.bind(this));
global.get_window_actors().forEach(a => {
@@ -356,6 +365,20 @@ class DesktopTarget extends EventEmitter {
}
}
class MainLayout extends Clutter.BoxLayout {
static {
GObject.registerClass(this);
}
vfunc_get_preferred_height(container, forWidth) {
const [mainChild] = container;
const [minHeight, natHeight] =
mainChild.get_preferred_height(forWidth);
return [minHeight, natHeight + MENU_HEIGHT_OFFSET];
}
}
class ApplicationsButton extends PanelMenu.Button {
static {
GObject.registerClass(this);
@@ -373,12 +396,12 @@ class ApplicationsButton extends PanelMenu.Button {
this.accessible_role = Atk.Role.LABEL;
this._label = new St.Label({
text: _('Applications'),
text: _('Apps'),
y_expand: true,
y_align: Clutter.ActorAlign.CENTER,
});
this.add_actor(this._label);
this.add_child(this._label);
this.name = 'panelApplications';
this.label_actor = this._label;
@@ -425,15 +448,6 @@ class ApplicationsButton extends PanelMenu.Button {
}
}
_createVertSeparator() {
let separator = new St.DrawingArea({
style_class: 'calendar-vertical-separator',
pseudo_class: 'highlighted',
});
separator.connect('repaint', this._onVertSepRepaint.bind(this));
return separator;
}
_onDestroy() {
super._onDestroy();
@@ -455,21 +469,6 @@ class ApplicationsButton extends PanelMenu.Button {
return super._onMenuKeyPress(actor, event);
}
_onVertSepRepaint(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let stippleColor = themeNode.get_color('-stipple-color');
let stippleWidth = themeNode.get_length('-stipple-width');
let x = Math.floor(width / 2) + 0.5;
cr.moveTo(x, 0);
cr.lineTo(x, height);
Clutter.cairo_set_source_color(cr, stippleColor);
cr.setDash([1, 3], 1); // Hard-code for now
cr.setLineWidth(stippleWidth);
cr.stroke();
}
_onOpenStateChanged(menu, open) {
if (open) {
if (this.reloadFlag) {
@@ -515,7 +514,7 @@ class ApplicationsButton extends PanelMenu.Button {
}
scrollToButton(button) {
let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment();
let appsScrollBoxAdj = this.applicationsScrollBox.get_vadjustment();
let appsScrollBoxAlloc = this.applicationsScrollBox.get_allocation_box();
let currentScrollValue = appsScrollBoxAdj.get_value();
let boxHeight = appsScrollBoxAlloc.y2 - appsScrollBoxAlloc.y1;
@@ -530,7 +529,7 @@ class ApplicationsButton extends PanelMenu.Button {
}
scrollToCatButton(button) {
let catsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment();
let catsScrollBoxAdj = this.categoriesScrollBox.get_vadjustment();
let catsScrollBoxAlloc = this.categoriesScrollBox.get_allocation_box();
let currentScrollValue = catsScrollBoxAdj.get_value();
let boxHeight = catsScrollBoxAlloc.y2 - catsScrollBoxAlloc.y1;
@@ -547,43 +546,29 @@ class ApplicationsButton extends PanelMenu.Button {
_createLayout() {
let section = new PopupMenu.PopupMenuSection();
this.menu.addMenuItem(section);
this.mainBox = new St.BoxLayout({vertical: false});
this.mainBox = new St.BoxLayout({layoutManager: new MainLayout()});
this.leftBox = new St.BoxLayout({vertical: true});
this.applicationsScrollBox = new St.ScrollView({
style_class: 'apps-menu vfade',
x_expand: true,
});
this.applicationsScrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
let vscroll = this.applicationsScrollBox.get_vscroll_bar();
vscroll.connect('scroll-start', () => {
this.menu.passEvents = true;
});
vscroll.connect('scroll-stop', () => {
this.menu.passEvents = false;
});
this.categoriesScrollBox = new St.ScrollView({
style_class: 'vfade',
});
this.categoriesScrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
vscroll = this.categoriesScrollBox.get_vscroll_bar();
vscroll.connect('scroll-start', () => (this.menu.passEvents = true));
vscroll.connect('scroll-stop', () => (this.menu.passEvents = false));
this.leftBox.add_child(this.categoriesScrollBox);
this.applicationsBox = new St.BoxLayout({vertical: true});
this.applicationsScrollBox.add_actor(this.applicationsBox);
this.applicationsScrollBox.set_child(this.applicationsBox);
this.categoriesBox = new St.BoxLayout({vertical: true});
this.categoriesScrollBox.add_actor(this.categoriesBox);
this.categoriesScrollBox.set_child(this.categoriesBox);
this.mainBox.add(this.leftBox);
this.mainBox.add_child(this._createVertSeparator());
this.mainBox.add_child(this.leftBox);
this.mainBox.add_child(this.applicationsScrollBox);
section.actor.add_actor(this.mainBox);
section.actor.add_child(this.mainBox);
}
_display() {
this._applicationsButtons.clear();
this.mainBox.style = 'width: 35em;';
this.mainBox.hide();
// Load categories
@@ -591,7 +576,7 @@ class ApplicationsButton extends PanelMenu.Button {
this._tree.load_sync();
let root = this._tree.get_root_directory();
let categoryMenuItem = new CategoryMenuItem(this, null);
this.categoriesBox.add_actor(categoryMenuItem);
this.categoriesBox.add_child(categoryMenuItem);
let iter = root.iter();
let nextType;
while ((nextType = iter.next()) !== GMenu.TreeItemType.INVALID) {
@@ -607,18 +592,12 @@ class ApplicationsButton extends PanelMenu.Button {
this._loadCategory(categoryId, dir);
if (this.applicationsByCategory[categoryId].length > 0) {
categoryMenuItem = new CategoryMenuItem(this, dir);
this.categoriesBox.add_actor(categoryMenuItem);
this.categoriesBox.add_child(categoryMenuItem);
}
}
// Load applications
this._displayButtons(this._listApplications(null));
let themeContext = St.ThemeContext.get_for_stage(global.stage);
let scaleFactor = themeContext.scale_factor;
let categoriesHeight = this.categoriesBox.height / scaleFactor;
let height = Math.round(categoriesHeight) + MENU_HEIGHT_OFFSET;
this.mainBox.style += `height: ${height}px`;
}
selectCategory(dir) {
@@ -626,7 +605,7 @@ class ApplicationsButton extends PanelMenu.Button {
if (c._delegate instanceof PopupMenu.PopupSeparatorMenuItem)
c._delegate.destroy();
else
this.applicationsBox.remove_actor(c);
this.applicationsBox.remove_child(c);
});
if (dir)
@@ -649,7 +628,7 @@ class ApplicationsButton extends PanelMenu.Button {
this._applicationsButtons.set(app, item);
}
if (!item.get_parent())
this.applicationsBox.add_actor(item);
this.applicationsBox.add_child(item);
}
}

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -3,8 +3,8 @@
"uuid": "@uuid@",
"settings-schema": "@gschemaname@",
"gettext-domain": "@gettext_domain@",
"name": "Applications Menu",
"description": "Add a category-based menu for applications.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
"name": "Apps Menu",
"description": "Add a category-based menu for apps.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
"original-authors": [ "e2002@bk.ru", "debarshir@gnome.org" ],
"shell-version": [ "@shell_current@" ],
"url": "@url@"

View File

@@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: 2021 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.apps-menu"
path="/org/gnome/shell/extensions/apps-menu/">

View File

@@ -1,3 +1,11 @@
/*
* SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.apps-menu {width: 26em;}
.apps-menu:ltr {
padding-right: 3px;
}

View File

@@ -1,5 +1,8 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// Start apps on custom workspaces
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2011 Alessandro Crismani <alessandro.crismani@gmail.com>
// SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Shell from 'gi://Shell';
@@ -16,7 +19,8 @@ class WindowMover {
this._appSystem.connectObject('installed-changed',
() => this._updateAppData(), this);
this._settings.connect('changed', this._updateAppConfigs.bind(this));
this._settings.connectObject('changed',
this._updateAppConfigs.bind(this), this);
this._updateAppConfigs();
}
@@ -44,7 +48,7 @@ class WindowMover {
.map(id => this._appSystem.lookup_app(id))
.filter(app => app && !this._appData.has(app));
addedApps.forEach(app => {
app.connectObject('window-changed',
app.connectObject('windows-changed',
this._appWindowsChanged.bind(this), this);
this._appData.set(app, {windows: app.get_windows()});
});
@@ -52,11 +56,8 @@ class WindowMover {
destroy() {
this._appSystem.disconnectObject(this);
if (this._settings) {
this._settings.run_dispose();
this._settings = null;
}
this._settings.disconnectObject(this);
this._settings = null;
this._appConfigs.clear();
this._updateAppData();

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: 2016 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.auto-move-windows" path="/org/gnome/shell/extensions/auto-move-windows/">
<key name="application-list" type="as">

View File

@@ -1,5 +1,7 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// Start apps on custom workspaces
// SPDX-FileCopyrightText: 2012 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
@@ -40,11 +42,11 @@ class NewItemModel extends GObject.Object {
class Rule extends GObject.Object {
static [GObject.properties] = {
'app-info': GObject.ParamSpec.object(
'app-info', 'app-info', 'app-info',
'app-info', null, null,
GObject.ParamFlags.READWRITE,
Gio.DesktopAppInfo),
'workspace': GObject.ParamSpec.uint(
'workspace', 'workspace', 'workspace',
'workspace', null, null,
GObject.ParamFlags.READWRITE,
1, WORKSPACE_MAX, 1),
};
@@ -191,7 +193,7 @@ class AutoMoveSettingsWidget extends Adw.PreferencesGroup {
class WorkspaceSelector extends Gtk.Widget {
static [GObject.properties] = {
'number': GObject.ParamSpec.uint(
'number', 'number', 'number',
'number', null, null,
GObject.ParamFlags.READWRITE,
1, WORKSPACE_MAX, 1),
};

View File

@@ -1,3 +1,8 @@
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2018 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
// Drive menu extension
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
@@ -34,8 +39,6 @@ class MountMenuItem extends PopupMenu.PopupBaseMenuItem {
this.mount = mount;
this.connect('destroy', this._onDestroy.bind(this));
let ejectIcon = new St.Icon({
icon_name: 'media-eject-symbolic',
style_class: 'popup-menu-icon',
@@ -45,7 +48,7 @@ class MountMenuItem extends PopupMenu.PopupBaseMenuItem {
style_class: 'button',
});
ejectButton.connect('clicked', this._eject.bind(this));
this.add(ejectButton);
this.add_child(ejectButton);
this.hide();

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2020 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.drive-menu-item { spacing: 12px; }
.drive-menu-item .button {

View File

@@ -1,3 +1,8 @@
// SPDX-FileCopyrightText: 2013 Gabriel Rossetti <rossetti.gabriel@gmail.com>
// SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import {AppIcon} from 'resource:///org/gnome/shell/ui/appDisplay.js';
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,19 +1,6 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
// SPDX-FileCopyrightText: 2023 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import St from 'gi://St';

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_schemas = []
js_sources = []
@@ -12,18 +16,20 @@ foreach e : enabled_extensions
metadata_conf.set('gschemaname', 'org.gnome.shell.extensions.' + e)
metadata_conf.set('gettext_domain', gettext_domain)
metadata_conf.set('shell_current', shell_version)
metadata_conf.set('url', 'https://gitlab.gnome.org/GNOME/gnome-shell-extensions')
metadata_conf.set(
'url',
'https://gitlab.gnome.org/GNOME/gnome-shell-extensions',
)
extension_sources = files(e + '/extension.js')
extension_data = []
subdir(e)
install_data (extension_sources + extension_data,
install_dir: join_paths(extensiondir, uuid)
install_data(
extension_sources + extension_data,
install_dir: join_paths(extensiondir, uuid),
)
endforeach
install_data (extension_schemas,
install_dir: schemadir
)
install_data(extension_schemas, install_dir: schemadir)

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,4 +1,10 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2011 Stefano Facchini <stefano.facchini@gmail.com>
// SPDX-FileCopyrightText: 2011 Wepmaschda <wepmaschda@gmx.de>
// SPDX-FileCopyrightText: 2015 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: 2016 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.native-window-placement" path="/org/gnome/shell/extensions/native-window-placement/">
<key name="use-more-screen" type="b">

View File

@@ -1,4 +1,10 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
// SPDX-FileCopyrightText: 2011 Vamsi Krishna Brahmajosyula <vamsikrishna.brahmajosyula@gmail.com>
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2016 Rémy Lefevre <lefevreremy@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import St from 'gi://St';
@@ -13,32 +19,17 @@ import {PlacesManager} from './placeDisplay.js';
const N_ = x => x;
const PLACE_ICON_SIZE = 16;
class PlaceMenuItem extends PopupMenu.PopupBaseMenuItem {
class PlaceMenuItem extends PopupMenu.PopupImageMenuItem {
static {
GObject.registerClass(this);
}
constructor(info) {
super({
super(info.name, info.icon, {
style_class: 'place-menu-item',
});
this._info = info;
this._icon = new St.Icon({
gicon: info.icon,
icon_size: PLACE_ICON_SIZE,
});
this.add_child(this._icon);
this._label = new St.Label({
text: info.name,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
});
this.add_child(this._label);
if (info.isRemovable()) {
this._ejectIcon = new St.Icon({
icon_name: 'media-eject-symbolic',
@@ -63,8 +54,8 @@ class PlaceMenuItem extends PopupMenu.PopupBaseMenuItem {
}
_propertiesChanged(info) {
this._icon.gicon = info.icon;
this._label.text = info.name;
this.setIcon(info.icon);
this.label.text = info.name;
}
}
@@ -88,7 +79,7 @@ class PlacesMenu extends PanelMenu.Button {
y_expand: true,
y_align: Clutter.ActorAlign.CENTER,
});
this.add_actor(label);
this.add_child(label);
this.placesManager = new PlacesManager();

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,4 +1,11 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
// SPDX-FileCopyrightText: 2012 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2013 Debarshi Ray <debarshir@gnome.org>
// SPDX-FileCopyrightText: 2015 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2016 Rémy Lefevre <lefevreremy@gmail.com>
// SPDX-FileCopyrightText: 2017 Christian Kellner <christian@kellner.me>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import Shell from 'gi://Shell';
@@ -53,15 +60,15 @@ class PlaceInfo extends EventEmitter {
return;
}
let source = {
get_icon: () => this.icon,
const source = {
get_drive: () => null,
};
let op = new ShellMountOperation.ShellMountOperation(source);
try {
await this.file.mount_enclosing_volume(0, op.mountOp, null);
if (tryMount)
this._ensureMountAndLaunch(context, false);
this._ensureMountAndLaunch(context, false).catch(logError);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
Main.notifyError(_('Failed to mount volume for “%s”').format(this.name), e.message);
@@ -73,7 +80,7 @@ class PlaceInfo extends EventEmitter {
launch(timestamp) {
let launchContext = global.create_app_launch_context(timestamp, -1);
this._ensureMountAndLaunch(launchContext, true);
this._ensureMountAndLaunch(launchContext, true).catch(logError);
}
getIcon() {
@@ -133,8 +140,8 @@ class RootInfo extends PlaceInfo {
return;
this._proxy = obj;
this._proxy.connect('g-properties-changed',
this._propertiesChanged.bind(this));
this._proxy.connectObject('g-properties-changed',
this._propertiesChanged.bind(this), this);
this._propertiesChanged(obj);
});
}
@@ -153,10 +160,8 @@ class RootInfo extends PlaceInfo {
}
destroy() {
if (this._proxy) {
this._proxy.run_dispose();
this._proxy = null;
}
this._proxy?.disconnectObject(this);
this._proxy = null;
super.destroy();
}
}

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2020 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.place-menu-item .button {
border-radius: 99px;
padding: 3px;

View File

@@ -1,22 +1,12 @@
/* Screenshot Window Sizer for Gnome Shell
*
* Copyright (c) 2013 Owen Taylor <otaylor@redhat.com>
* Copyright (c) 2013 Richard Hughes <richard@hughsie.com>
*
* 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.
*/
// SPDX-FileCopyrightText: 2013 Owen Taylor <otaylor@redhat.com>
// SPDX-FileCopyrightText: 2013 Richard Hughes <richard@hughsie.com>
// SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2016 Will Thompson <will@willthompson.co.uk>
// SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2019 Adrien Plazas <kekun.plazas@laposte.net>
// SPDX-FileCopyrightText: 2019 Willy Stadnick <willy.stadnick@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import Meta from 'gi://Meta';
@@ -34,6 +24,7 @@ export default class ScreenshotWindowSizerExtension extends Extension {
[624, 351],
[800, 450],
[1024, 576],
[1000, 700],
[1200, 675],
[1600, 900],
[360, 654], // Phone portrait maximized
@@ -43,7 +34,7 @@ export default class ScreenshotWindowSizerExtension extends Extension {
_flashMessage(message) {
if (!this._text) {
this._text = new St.Label({style_class: 'screenshot-sizer-message'});
Main.uiGroup.add_actor(this._text);
Main.uiGroup.add_child(this._text);
}
this._text.remove_all_transitions();
@@ -75,10 +66,7 @@ export default class ScreenshotWindowSizerExtension extends Extension {
* @param {Meta.KeyBinding} binding - the key binding
*/
_cycleScreenshotSizes(display, window, binding) {
// Probably this isn't useful with 5 sizes, but you can decrease instead
// of increase by holding down shift.
let modifiers = binding.get_modifiers();
let backwards = (modifiers & Meta.VirtualModifier.SHIFT_MASK) !== 0;
const backwards = binding.is_reversed();
// Unmaximize first
if (window.get_maximized() !== 0)
@@ -109,7 +97,7 @@ export default class ScreenshotWindowSizerExtension extends Extension {
// get the next size up or down from ideal
let newIndex = (nearestIndex + (backwards ? -1 : 1)) % scaledSizes.length;
let [newWidth, newHeight] = scaledSizes[newIndex];
let [newWidth, newHeight] = scaledSizes.at(newIndex);
// Push the window onscreen if it would be resized offscreen
let newX = outerRect.x;

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -4,7 +4,7 @@
"settings-schema": "@gschemaname@",
"gettext-domain": "@gettext_domain@",
"name": "Screenshot Window Sizer",
"description": "Resize windows for GNOME Software screenshots",
"description": "Resize windows for GNOME Software screenshots with Ctrl+Alt+s shortcut",
"shell-version": [ "@shell_current@" ],
"url": "@url@"
}

View File

@@ -1,4 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
SPDX-FileCopyrightText: 2016 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.screenshot-window-sizer"
path="/org/gnome/shell/extensions/screenshot-window-sizer/">

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.screenshot-sizer-message {
font-size: 36px;
font-weight: bold;

View File

@@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: 2018 Adel Gadllah <adel.gadllah@gmail.com>
// SPDX-FileCopyrightText: 2018 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import Shell from 'gi://Shell';
import St from 'gi://St';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import {Button as PanelButton} from 'resource:///org/gnome/shell/ui/panelMenu.js';
const PANEL_ICON_SIZE = 16;
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = [
'bluetooth-applet',
'gnome-sound-applet',
'nm-applet',
'gnome-power-manager',
'keyboard',
'a11y-keyboard',
'kbd-scrolllock',
'kbd-numlock',
'kbd-capslock',
'ibus-ui-gtk',
];
export default class SysTray {
constructor() {
this._icons = new Map();
this._tray = null;
}
_onTrayIconAdded(o, icon) {
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS.includes(wmClass))
return;
let button = new PanelButton(0.5, null, true);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let iconSize = PANEL_ICON_SIZE * scaleFactor;
icon.set({
width: iconSize,
height: iconSize,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
});
let iconBin = new St.Widget({
layout_manager: new Clutter.BinLayout(),
style_class: 'system-status-icon',
});
iconBin.add_child(icon);
button.add_child(iconBin);
this._icons.set(icon, button);
button.connect('button-release-event',
(actor, event) => icon.click(event));
button.connect('key-press-event',
(actor, event) => icon.click(event));
const role = `${icon}`;
Main.panel.addToStatusArea(role, button);
}
_onTrayIconRemoved(o, icon) {
const button = this._icons.get(icon);
button?.destroy();
this._icons.delete(icon);
}
enable() {
this._tray = new Shell.TrayManager();
this._tray.connect('tray-icon-added',
this._onTrayIconAdded.bind(this));
this._tray.connect('tray-icon-removed',
this._onTrayIconRemoved.bind(this));
this._tray.manage_screen(Main.panel);
}
disable() {
this._icons.forEach(button => button.destroy());
this._icons.clear();
this._tray.unmanage_screen();
this._tray = null;
}
}

View File

@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2018 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,
configuration: metadata_conf
)

View File

@@ -0,0 +1,10 @@
{
"extension-id": "@extension_id@",
"uuid": "@uuid@",
"settings-schema": "@gschemaname@",
"gettext-domain": "@gettext_domain@",
"name": "Status Icons",
"description": "Show status icons in the top bar",
"shell-version": [ "@shell_current@" ],
"url": "@url@"
}

View File

@@ -0,0 +1,489 @@
/*
* SPDX-FileCopyrightText: 2023 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import GTop from 'gi://GTop';
import Pango from 'gi://Pango';
import Shell from 'gi://Shell';
import St from 'gi://St';
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const THRESHOLD_HIGH = 0.80;
// adapted from load-graph.cpp in gnome-system-monitor
/**
* @param {string} str
* @returns {number}
*/
function strHash(str) {
let hash = 0xcbf29ce484222325n;
for (const c of str)
hash = (hash * 0x00000100000001B3n) ^ BigInt(c.codePointAt(0));
return hash;
}
class StatSection extends St.BoxLayout {
static {
GObject.registerClass(this);
}
constructor(iconName, accessibleName) {
super({
style_class: 'system-monitor-stat-section',
accessibleName,
});
const ext = Extension.lookupByURL(import.meta.url);
const file =
ext.dir.resolve_relative_path(`icons/${iconName}.svg`);
this._icon = new St.Icon({
style_class: 'system-monitor-stat-section-icon',
gicon: new Gio.FileIcon({file}),
});
this.add_child(this._icon);
this.label = new St.Label({
style_class: 'system-monitor-stat-section-label',
y_align: Clutter.ActorAlign.CENTER,
});
this.label.clutter_text.set({
ellipsize: Pango.EllipsizeMode.NONE,
x_align: Clutter.ActorAlign.CENTER,
});
this.add_child(this.label);
this.connect('destroy', () => this._clearTimeout());
this.connect('notify::visible', () => this._sync());
this._sync();
}
_ensureTimeout() {
if (this._updateId)
return;
this._updateId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1,
() => {
this._update();
return GLib.SOURCE_CONTINUE;
});
}
_clearTimeout() {
if (this._updateId)
GLib.source_remove(this._updateId);
delete this._updateId;
}
_sync() {
if (this.visible)
this._ensureTimeout();
else
this._clearTimeout();
if (this.visible)
this._update();
}
_update() {
}
}
class LoadStatSection extends StatSection {
static {
GObject.registerClass(this);
}
#formatter = new Intl.NumberFormat(undefined, {
style: 'percent',
});
_getLoadValue() {
}
_update() {
const load = this._getLoadValue();
this.label.text = this.#formatter.format(load);
if (load >= THRESHOLD_HIGH)
this.add_style_class_name('high-usage');
else
this.remove_style_class_name('high-usage');
}
}
class CpuSection extends LoadStatSection {
static {
GObject.registerClass(this);
}
#prevCpu = new GTop.glibtop_cpu();
constructor() {
super('processor-symbolic', _('CPU stats'));
}
_getLoadValue() {
const cpu = new GTop.glibtop_cpu();
GTop.glibtop_get_cpu(cpu);
const total = cpu.total - this.#prevCpu.total;
const user = cpu.user - this.#prevCpu.user;
const sys = cpu.sys - this.#prevCpu.sys;
const nice = cpu.nice - this.#prevCpu.nice;
this.#prevCpu = cpu;
return (user + sys + nice) / Math.max(total, 1.0);
}
}
class MemSection extends LoadStatSection {
static {
GObject.registerClass(this);
}
constructor() {
super('memory-symbolic', _('Memory stats'));
}
_getLoadValue() {
const mem = new GTop.glibtop_mem();
GTop.glibtop_get_mem(mem);
const {user, total} = mem;
return user / Math.max(total, 1.0);
}
}
class SwapSection extends LoadStatSection {
static {
GObject.registerClass(this);
}
constructor() {
super('swap-symbolic', _('Swap stats'));
}
_getLoadValue() {
const swap = new GTop.glibtop_swap();
GTop.glibtop_get_swap(swap);
const {used, total} = swap;
return used / Math.max(total, 1.0);
}
}
class NetStatSection extends StatSection {
static {
GObject.registerClass(this);
}
#formats = [{
factor: 1000,
unitFactor: 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'kilobyte',
maximumFractionDigits: 1,
minimumFractionDigits: 1,
}),
}, {
factor: 1000 * 10,
unitFactor: 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'kilobyte',
maximumFractionDigits: 0,
}),
}, {
factor: 1000 * 1000,
unitFactor: 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'megabyte',
maximumFractionDigits: 1,
minimumFractionDigits: 1,
}),
}, {
factor: 1000 * 1000 * 10,
unitFactor: 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'megabyte',
maximumFractionDigits: 0,
}),
}, {
factor: 1000 * 1000 * 1000,
unitFactor: 1000 * 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'gigabyte',
maximumFractionDigits: 1,
minimumFractionDigits: 1,
}),
}, {
factor: 1000 * 1000 * 1000 * 10,
unitFactor: 1000 * 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'gigabyte',
maximumFractionDigits: 0,
}),
}, {
factor: 1000 * 1000 * 1000 * 1000,
unitFactor: 1000 * 1000 * 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'terabyte',
maximumFractionDigits: 1,
minimumFractionDigits: 1,
}),
}, {
factor: 1000 * 1000 * 1000 * 1000 * 10,
unitFactor: 1000 * 1000 * 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'terabyte',
maximumFractionDigits: 0,
}),
}, {
factor: 1000 * 1000 * 1000 * 1000 * 1000,
unitFactor: 1000 * 1000 * 1000 * 1000 * 1000,
formatter: new Intl.NumberFormat(undefined, {
style: 'unit',
unit: 'petabyte',
maximumFractionDigits: 1,
minimumFractionDigits: 1,
}),
}];
#lastBytes = 0;
#lastHash = 0;
#lastTime = 0;
_getBytes(_netload) {
}
_getFormat(bytes) {
for (let i = 1; i < this.#formats.length; i++) {
if (bytes < this.#formats.at(i).factor)
return this.#formats.at(i - 1);
}
return this.#formats.at(-1);
}
_update() {
const FLAG_LOOPBACK = 1 << 4; // GTop sucks
const netlist = new GTop.glibtop_netlist();
const ifnames = GTop.glibtop_get_netlist(netlist);
let bytes = 0;
let hash = 1n;
for (const ifname of ifnames) {
const netload = new GTop.glibtop_netload();
GTop.glibtop_get_netload(netload, ifname);
if (netload.if_flags & FLAG_LOOPBACK)
continue;
bytes += this._getBytes(netload);
hash += strHash(ifname);
}
const time = GLib.get_monotonic_time();
let dbytes = 0;
// Skip calculation if new data is less than old (interface
// removed, counters reset, ...) or if it is the first time
if (bytes >= this.#lastBytes &&
hash === this.#lastHash &&
this.#lastTime !== 0) {
const dtime = (time - this.#lastTime) / GLib.USEC_PER_SEC;
dbytes = (bytes - this.#lastBytes) / dtime;
}
this.#lastBytes = bytes;
this.#lastTime = time;
this.#lastHash = hash;
const {unitFactor, formatter} = this._getFormat(dbytes);
this.label.text = formatter.format(dbytes / unitFactor);
}
}
class UploadSection extends NetStatSection {
static {
GObject.registerClass(this);
}
constructor() {
super('upload-symbolic', _('Upload stats'));
}
_getBytes(netload) {
return netload.bytes_out;
}
}
class DownloadSection extends NetStatSection {
static {
GObject.registerClass(this);
}
constructor() {
super('download-symbolic', _('Download stats'));
}
_getBytes(netload) {
return netload.bytes_in;
}
}
class Indicator extends PanelMenu.Button {
static {
GObject.registerClass(this);
}
constructor(settings) {
super(0.5, _('System stats'));
this._settings = settings;
this.connect('destroy',
() => (this._settings = null));
const box = new St.BoxLayout({
styleClass: 'system-monitor-stat-sections',
});
this.add_child(box);
this._placeholder = new St.Icon({
styleClass: 'system-status-icon system-monitor-placeholder',
});
box.add_child(this._placeholder);
this._cpuSection = new CpuSection();
this._settings.bind('show-cpu',
this._cpuSection, 'visible',
Gio.SettingsBindFlags.GET);
box.add_child(this._cpuSection);
this._memSection = new MemSection();
this._settings.bind('show-memory',
this._memSection, 'visible',
Gio.SettingsBindFlags.GET);
box.add_child(this._memSection);
this._swapSection = new SwapSection();
this._settings.bind('show-swap',
this._swapSection, 'visible',
Gio.SettingsBindFlags.GET);
box.add_child(this._swapSection);
this._ulSection = new UploadSection();
this._settings.bind('show-upload',
this._ulSection, 'visible',
Gio.SettingsBindFlags.GET);
box.add_child(this._ulSection);
this._dlSection = new DownloadSection();
this._settings.bind('show-download',
this._dlSection, 'visible',
Gio.SettingsBindFlags.GET);
box.add_child(this._dlSection);
this.menu.addMenuItem(
new PopupMenu.PopupSeparatorMenuItem(_('Show')));
this._cpuItem = this.menu.addAction(_('CPU'),
() => this._toggleSettings('show-cpu'));
this._memItem = this.menu.addAction(_('Memory'),
() => this._toggleSettings('show-memory'));
this._swapItem = this.menu.addAction(_('Swap'),
() => this._toggleSettings('show-swap'));
this._ulItem = this.menu.addAction(_('Upload'),
() => this._toggleSettings('show-upload'));
this._dlItem = this.menu.addAction(_('Download'),
() => this._toggleSettings('show-download'));
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._appMenuItem = this.menu.addAction(_('Open System Monitor'),
() => this._openSystemMonitor());
const appSystem = Shell.AppSystem.get_default();
appSystem.connectObject('installed-changed',
() => this._updateSystemMonitorApp(), this);
this._updateSystemMonitorApp();
this._settings.connectObject('changed',
() => this._sync(), this);
this._sync();
}
_updateSystemMonitorApp() {
const appSystem = Shell.AppSystem.get_default();
this._systemMonitorApp =
appSystem.lookup_app('org.gnome.SystemMonitor.desktop');
this._placeholder.gicon = this._systemMonitorApp?.icon ?? null;
this.visible = this._systemMonitorApp != null;
}
_openSystemMonitor() {
this._systemMonitorApp.activate();
Main.overview.hide();
}
_toggleSettings(key) {
this._settings.set_boolean(key, !this._settings.get_boolean(key));
}
_sync() {
this._cpuItem.setOrnament(this._settings.get_boolean('show-cpu')
? PopupMenu.Ornament.CHECK
: PopupMenu.Ornament.NONE);
this._memItem.setOrnament(this._settings.get_boolean('show-memory')
? PopupMenu.Ornament.CHECK
: PopupMenu.Ornament.NONE);
this._swapItem.setOrnament(this._settings.get_boolean('show-swap')
? PopupMenu.Ornament.CHECK
: PopupMenu.Ornament.NONE);
this._ulItem.setOrnament(this._settings.get_boolean('show-upload')
? PopupMenu.Ornament.CHECK
: PopupMenu.Ornament.NONE);
this._dlItem.setOrnament(this._settings.get_boolean('show-download')
? PopupMenu.Ornament.CHECK
: PopupMenu.Ornament.NONE);
this._placeholder.visible =
this._settings.list_keys().every(key => !this._settings.get_boolean(key));
}
}
export default class SystemMonitorExtension extends Extension {
enable() {
this._indicator = new Indicator(this.getSettings());
Main.panel.addToStatusArea(this.uuid, this._indicator);
}
disable() {
this._indicator.destroy();
this._indicator = null;
}
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="a" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="b">
<g filter="url(#a)">
<path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.5"/>
</g>
</mask>
<clipPath id="c">
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
</clipPath>
<mask id="d">
<g filter="url(#a)">
<path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.7"/>
</g>
</mask>
<clipPath id="e">
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
</clipPath>
<mask id="f">
<g filter="url(#a)">
<path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.35"/>
</g>
</mask>
<clipPath id="g">
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
</clipPath>
<g mask="url(#b)">
<g clip-path="url(#c)" transform="matrix(1 0 0 1 -920 -120)">
<path d="m 550 182 c -0.351562 0.003906 -0.695312 0.101562 -1 0.28125 v 3.4375 c 0.304688 0.179688 0.648438 0.277344 1 0.28125 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 c -0.339844 0 -0.679688 0.058594 -1 0.175781 v 6.824219 h 4 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/>
</g>
</g>
<g mask="url(#d)">
<g clip-path="url(#e)" transform="matrix(1 0 0 1 -920 -120)">
<path d="m 569 182 v 4 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 v 7 h 3 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/>
</g>
</g>
<g mask="url(#f)">
<g clip-path="url(#g)" transform="matrix(1 0 0 1 -920 -120)">
<path d="m 573 182.269531 v 3.449219 c 0.613281 -0.355469 0.996094 -1.007812 1 -1.71875 c 0 -0.714844 -0.382812 -1.375 -1 -1.730469 z m 0 4.90625 v 6.824219 h 2 v -4 c 0 -1.269531 -0.800781 -2.402344 -2 -2.824219 z m 0 0"/>
</g>
</g>
<path d="m 7.984375 1 c -0.550781 0 -1 0.449219 -1 1 v 8.585938 l -2.292969 -2.292969 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 s -0.519531 0.105469 -0.707031 0.292969 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 l 4 4 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 l 4 -4 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 s -1.023437 -0.390625 -1.414062 0 l -2.292969 2.292969 v -8.585938 c 0 -0.550781 -0.445313 -1 -1 -1 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: Icon Development Kit
SPDX-License-Identifier: CC0-1.0

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 3 2 c -1.660156 0 -3 1.339844 -3 3 v 4 c 0 1.660156 1.339844 3 3 3 h 10 c 1.660156 0 3 -1.339844 3 -3 v -4 c 0 -1.660156 -1.339844 -3 -3 -3 z m 0 2 h 10 c 0.554688 0 1 0.445312 1 1 v 4 c 0 0.554688 -0.445312 1 -1 1 h -10 c -0.554688 0 -1 -0.445312 -1 -1 v -4 c 0 -0.554688 0.445312 -1 1 -1 z m 0 0"/><path d="m 2 10 h 12 v 4 h -12 z m 0 0"/><g fill-opacity="0.501961"><path d="m 4 5 h 2 v 4 h -2 z m 0 0"/><path d="m 7 5 h 2 v 4 h -2 z m 0 0"/><path d="m 10 5 h 2 v 4 h -2 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 631 B

View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: Icon Development Kit
SPDX-License-Identifier: CC0-1.0

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 5 5 h 6 v 6 h -6 z m 0 0"/><path d="m 13 5 h 3 v 1 h -3 z m 0 0"/><path d="m 13 7 h 3 v 1 h -3 z m 0 0"/><path d="m 13 9 h 3 v 1 h -3 z m 0 0"/><path d="m 0 6 h 3 v 1 h -3 z m 0 0"/><path d="m 0 8 h 3 v 1 h -3 z m 0 0"/><path d="m 0 10 h 3 v 1 h -3 z m 0 0"/><path d="m 5 0 h 1 v 3 h -1 z m 0 0"/><path d="m 7 0 h 1 v 3 h -1 z m 0 0"/><path d="m 9 0 h 1 v 3 h -1 z m 0 0"/><path d="m 10 13 h 1 v 3 h -1 z m 0 0"/><path d="m 8 13 h 1 v 3 h -1 z m 0 0"/><path d="m 6 13 h 1 v 3 h -1 z m 0 0"/><path d="m 5 2 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 2 h 6 c 0.570312 0 1 0.429688 1 1 v 6 c 0 0.570312 -0.429688 1 -1 1 h -6 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429688 -1 1 -1 z m 0 0"/></svg>

After

Width:  |  Height:  |  Size: 943 B

View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: Icon Development Kit
SPDX-License-Identifier: CC0-1.0

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 5 7 c -0.308594 0 -0.613281 0.089844 -0.8125 0.28125 l -3.59375 3.71875 l 3.65625 3.71875 c 0.199219 0.191406 0.441406 0.28125 0.75 0.28125 h 1 v -1 c 0 -0.257812 -0.128906 -0.527344 -0.3125 -0.71875 l -1.28125 -1.28125 h 4.59375 c 0.527344 0.007812 1 -0.472656 1 -1 s -0.472656 -1.007812 -1 -1 h -4.625 l 1.21875 -1.28125 c 0.183594 -0.191406 0.40625 -0.460938 0.40625 -0.71875 v -1 z m 0 0"/><path d="m 11 9 c 0.308594 0 0.613281 -0.089844 0.8125 -0.28125 l 3.59375 -3.71875 l -3.65625 -3.71875 c -0.199219 -0.191406 -0.441406 -0.28125 -0.75 -0.28125 h -1 v 1 c 0 0.257812 0.128906 0.527344 0.3125 0.71875 l 1.28125 1.28125 h -4.59375 c -0.527344 -0.007812 -1 0.472656 -1 1 s 0.472656 1.007812 1 1 h 4.625 l -1.21875 1.28125 c -0.183594 0.191406 -0.40625 0.460938 -0.40625 0.71875 v 1 z m 0 0"/></svg>

After

Width:  |  Height:  |  Size: 941 B

View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: Icon Development Kit
SPDX-License-Identifier: CC0-1.0

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="a" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="b">
<g filter="url(#a)">
<path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.5"/>
</g>
</mask>
<clipPath id="c">
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
</clipPath>
<mask id="d">
<g filter="url(#a)">
<path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.7"/>
</g>
</mask>
<clipPath id="e">
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
</clipPath>
<mask id="f">
<g filter="url(#a)">
<path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.35"/>
</g>
</mask>
<clipPath id="g">
<path d="m 0 0 h 1600 v 1200 h -1600 z"/>
</clipPath>
<g mask="url(#b)">
<g clip-path="url(#c)" transform="matrix(1 0 0 1 -900 -120)">
<path d="m 550 182 c -0.351562 0.003906 -0.695312 0.101562 -1 0.28125 v 3.4375 c 0.304688 0.179688 0.648438 0.277344 1 0.28125 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 c -0.339844 0 -0.679688 0.058594 -1 0.175781 v 6.824219 h 4 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/>
</g>
</g>
<g mask="url(#d)">
<g clip-path="url(#e)" transform="matrix(1 0 0 1 -900 -120)">
<path d="m 569 182 v 4 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 v 7 h 3 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/>
</g>
</g>
<g mask="url(#f)">
<g clip-path="url(#g)" transform="matrix(1 0 0 1 -900 -120)">
<path d="m 573 182.269531 v 3.449219 c 0.613281 -0.355469 0.996094 -1.007812 1 -1.71875 c 0 -0.714844 -0.382812 -1.375 -1 -1.730469 z m 0 4.90625 v 6.824219 h 2 v -4 c 0 -1.269531 -0.800781 -2.402344 -2 -2.824219 z m 0 0"/>
</g>
</g>
<path d="m 8.015625 15 c 0.550781 0 1 -0.449219 1 -1 v -8.585938 l 2.292969 2.292969 c 0.1875 0.1875 0.441406 0.292969 0.707031 0.292969 s 0.519531 -0.105469 0.707031 -0.292969 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -4 -4 c -0.390625 -0.390625 -1.023437 -0.390625 -1.414062 0 l -4 4 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 s 1.023437 0.390625 1.414062 0 l 2.292969 -2.292969 v 8.585938 c 0 0.550781 0.445313 1 1 1 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: Icon Development Kit
SPDX-License-Identifier: CC0-1.0

View File

@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,
configuration: metadata_conf
)
extension_data += files('stylesheet.css')
extension_schemas += files('schemas/' + metadata_conf.get('gschemaname') + '.gschema.xml')
install_subdir('icons', install_dir: join_paths(extensiondir, uuid))

View File

@@ -0,0 +1,10 @@
{
"extension-id": "@extension_id@",
"uuid": "@uuid@",
"settings-schema": "@gschemaname@",
"gettext-domain": "@gettext_domain@",
"name": "System Monitor",
"description": "Monitor system from the top bar",
"shell-version": [ "@shell_current@" ],
"url": "@url@"
}

View File

@@ -0,0 +1,31 @@
<!--
SPDX-FileCopyrightText: 2023 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.system-monitor"
path="/org/gnome/shell/extensions/system-monitor/">
<key name="show-cpu" type="b">
<default>true</default>
<summary>Show CPU usage</summary>
</key>
<key name="show-memory" type="b">
<default>true</default>
<summary>Show memory usage</summary>
</key>
<key name="show-swap" type="b">
<default>true</default>
<summary>Show swap usage</summary>
</key>
<key name="show-upload" type="b">
<default>true</default>
<summary>Show upload</summary>
</key>
<key name="show-download" type="b">
<default>true</default>
<summary>Show download</summary>
</key>
</schema>
</schemalist>

View File

@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2023 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.system-monitor-stat-section {
padding: 0 6px;
}
.system-monitor-stat-section-icon {icon-size: 1.08em;}
.system-monitor-stat-section-label {
min-width: 3.0em;
font-size: 0.9em;
}
.system-monitor-placeholder {-st-icon-style: symbolic;}
.panel-button .high-usage {color: #ff7800;}

View File

@@ -1,5 +1,9 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// Load shell theme from ~/.local/share/themes/name/gnome-shell
// SPDX-FileCopyrightText: 2011 John Stowers <john.stowers@gmail.com>
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2011 Elad Alfassa <el.il@doom.co.il>
// SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Gio from 'gi://Gio';
@@ -14,12 +18,13 @@ const SETTINGS_KEY = 'name';
export default class ThemeManager extends Extension {
enable() {
this._settings = this.getSettings();
this._settings.connect(`changed::${SETTINGS_KEY}`, this._changeTheme.bind(this));
this._settings.connectObject(`changed::${SETTINGS_KEY}`,
this._changeTheme.bind(this), this);
this._changeTheme();
}
disable() {
this._settings?.run_dispose();
this._settings?.disconnectObject();
this._settings = null;
Main.setThemeStylesheet(null);

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: 2016 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.user-theme" path="/org/gnome/shell/extensions/user-theme/">
<key name="name" type="s">

View File

@@ -1,4 +1,6 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// SPDX-FileCopyrightText: 2020 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
// we use async/await here to not block the mainloop, not to parallelize
/* eslint-disable no-await-in-loop */
@@ -32,7 +34,7 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
this._actionGroup.add_action(
this._settings.create_action('name'));
this.connect('destroy', () => this._settings.run_dispose());
this.connect('destroy', () => (this._settings = null));
this._rows = new Map();
this._addTheme(''); // default

View File

@@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2020 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import GLib from 'gi://GLib';
const fn = (...args) => GLib.build_filenamev(args);

View File

@@ -1,9 +1,16 @@
// SPDX-FileCopyrightText: 2012 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2013 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2014 Sylvain Pasche <sylvain.pasche@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
import Meta from 'gi://Meta';
import Mtk from 'gi://Mtk';
import Shell from 'gi://Shell';
import St from 'gi://St';
@@ -11,18 +18,14 @@ import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/ex
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as Overview from 'resource:///org/gnome/shell/ui/overview.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
import {DashItemContainer} from 'resource:///org/gnome/shell/ui/dash.js';
import {WindowPicker, WindowPickerToggle} from './windowPicker.js';
import {WorkspaceIndicator} from './workspaceIndicator.js';
const ICON_TEXTURE_SIZE = 24;
const DND_ACTIVATE_TIMEOUT = 500;
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
const GroupingMode = {
NEVER: 0,
AUTO: 1,
@@ -74,7 +77,7 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
'notify::minimized', this._updateMinimizeItem.bind(this),
'notify::maximized-horizontally', this._updateMaximizeItem.bind(this),
'notify::maximized-vertically', this._updateMaximizeItem.bind(this),
this);
this.actor);
this._updateMinimizeItem();
this._updateMaximizeItem();
@@ -117,14 +120,10 @@ class WindowTitle extends St.BoxLayout {
this._metaWindow = metaWindow;
this._icon = new St.Bin({style_class: 'window-button-icon'});
this.add(this._icon);
this.add_child(this._icon);
this.label_actor = new St.Label({y_align: Clutter.ActorAlign.CENTER});
this.label_actor.clutter_text.single_line_mode = true;
this.add(this.label_actor);
this._textureCache = St.TextureCache.get_default();
this._textureCache.connectObject('icon-theme-changed',
() => this._updateIcon(), this);
this.add_child(this.label_actor);
this._metaWindow.connectObject(
'notify::wm-class',
@@ -160,20 +159,20 @@ class WindowTitle extends St.BoxLayout {
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
} else {
this._icon.child = new St.Icon({
icon_name: 'icon-missing',
icon_name: 'application-x-executable',
icon_size: ICON_TEXTURE_SIZE,
});
}
}
}
class BaseButton extends St.Button {
class BaseButton extends DashItemContainer {
static {
GObject.registerClass({
GTypeFlags: GObject.TypeFlags.ABSTRACT,
Properties: {
'ignore-workspace': GObject.ParamSpec.boolean(
'ignore-workspace', 'ignore-workspace', 'ignore-workspace',
'ignore-workspace', null, null,
GObject.ParamFlags.READWRITE,
false),
},
@@ -181,12 +180,22 @@ class BaseButton extends St.Button {
}
constructor(perMonitor, monitorIndex) {
super({
super();
this._button = new St.Button({
style_class: 'window-button',
can_focus: true,
x_expand: true,
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
});
this.setChild(this._button);
this._button.connect('notify::hover', () => {
if (this._button.hover)
this.showLabel();
else
this.hideLabel();
});
this._perMonitor = perMonitor;
this._monitorIndex = monitorIndex;
@@ -194,7 +203,7 @@ class BaseButton extends St.Button {
this.connect('notify::allocation',
this._updateIconGeometry.bind(this));
this.connect('clicked', this._onClicked.bind(this));
this._button.connect('clicked', this._onClicked.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
this.connect('popup-menu', this._onPopupMenu.bind(this));
@@ -211,16 +220,10 @@ class BaseButton extends St.Button {
this._windowEnteredOrLeftMonitor.bind(this),
this);
}
this._tooltip = new Tooltip(this, {
style_class: 'dash-label',
visible: false,
});
Main.uiGroup.add_child(this._tooltip);
}
get active() {
return this.has_style_class_name('focused');
return this._button.has_style_class_name('focused');
}
// eslint-disable-next-line camelcase
@@ -239,6 +242,18 @@ class BaseButton extends St.Button {
this._updateVisibility();
}
showLabel() {
const [, , preferredTitleWidth] = this.label_actor.get_preferred_size();
const maxTitleWidth = this.label_actor.allocation.get_width();
const isTitleFullyShown = preferredTitleWidth <= maxTitleWidth;
const labelText = isTitleFullyShown
? '' : this.label_actor.text;
this.setLabelText(labelText);
super.showLabel();
}
_setLongPressTimeout() {
if (this._longPressTimeoutId)
return;
@@ -261,24 +276,24 @@ class BaseButton extends St.Button {
delete this._longPressTimeoutId;
}
vfunc_button_press_event(buttonEvent) {
if (buttonEvent.button === 1)
vfunc_button_press_event(event) {
if (event.get_button() === 1)
this._setLongPressTimeout();
return super.vfunc_button_press_event(buttonEvent);
return super.vfunc_button_press_event(event);
}
vfunc_button_release_event(buttonEvent) {
vfunc_button_release_event(event) {
this._removeLongPressTimeout();
return super.vfunc_button_release_event(buttonEvent);
return super.vfunc_button_release_event(event);
}
vfunc_touch_event(touchEvent) {
if (touchEvent.type === Clutter.EventType.TOUCH_BEGIN)
vfunc_touch_event(event) {
if (event.type() === Clutter.EventType.TOUCH_BEGIN)
this._setLongPressTimeout();
else if (touchEvent.type === Clutter.EventType.TOUCH_END)
else if (event.type() === Clutter.EventType.TOUCH_END)
this._removeLongPressTimeout();
return super.vfunc_touch_event(touchEvent);
return super.vfunc_touch_event(event);
}
activate() {
@@ -339,9 +354,9 @@ class BaseButton extends St.Button {
_updateStyle() {
if (this._isFocused())
this.add_style_class_name('focused');
this._button.add_style_class_name('focused');
else
this.remove_style_class_name('focused');
this._button.remove_style_class_name('focused');
}
_windowEnteredOrLeftMonitor(_metaDisplay, _monitorIndex, _metaWindow) {
@@ -363,7 +378,7 @@ class BaseButton extends St.Button {
}
_getIconGeometry() {
let rect = new Meta.Rectangle();
const rect = new Mtk.Rectangle();
[rect.x, rect.y] = this.get_transformed_position();
[rect.width, rect.height] = this.get_transformed_size();
@@ -377,7 +392,6 @@ class BaseButton extends St.Button {
}
_onDestroy() {
this._tooltip.destroy();
}
}
@@ -390,15 +404,17 @@ class WindowButton extends BaseButton {
super(perMonitor, monitorIndex);
this.metaWindow = metaWindow;
this._unmanaging = false;
metaWindow.connectObject(
'notify::skip-taskbar', () => this._updateVisibility(),
'workspace-changed', () => this._updateVisibility(),
'unmanaging', () => (this._unmanaging = true),
this);
this._updateVisibility();
this._windowTitle = new WindowTitle(this.metaWindow);
this.set_child(this._windowTitle);
this._button.set_child(this._windowTitle);
this.label_actor = this._windowTitle.label_actor;
this._contextMenu = new WindowContextMenu(this, this.metaWindow);
@@ -406,7 +422,7 @@ class WindowButton extends BaseButton {
this._onMenuStateChanged.bind(this));
this._contextMenu.actor.hide();
this._contextMenuManager.addMenu(this._contextMenu);
Main.uiGroup.add_actor(this._contextMenu.actor);
Main.uiGroup.add_child(this._contextMenu.actor);
global.display.connectObject('notify::focus-window',
() => this._updateStyle(), this);
@@ -433,9 +449,9 @@ class WindowButton extends BaseButton {
super._updateStyle();
if (this.metaWindow.minimized)
this.add_style_class_name('minimized');
this._button.add_style_class_name('minimized');
else
this.remove_style_class_name('minimized');
this._button.remove_style_class_name('minimized');
}
_windowEnteredOrLeftMonitor(metaDisplay, monitorIndex, metaWindow) {
@@ -444,6 +460,9 @@ class WindowButton extends BaseButton {
}
_updateVisibility() {
if (this._unmanaging)
return;
this.visible = this._isWindowVisible(this.metaWindow);
}
@@ -527,30 +546,30 @@ class AppButton extends BaseButton {
this._updateVisibility();
let stack = new St.Widget({layout_manager: new Clutter.BinLayout()});
this.set_child(stack);
this._button.set_child(stack);
this._singleWindowTitle = new St.Bin({
x_expand: true,
});
stack.add_actor(this._singleWindowTitle);
stack.add_child(this._singleWindowTitle);
this._multiWindowTitle = new St.BoxLayout({
style_class: 'window-button-box',
x_expand: true,
});
stack.add_actor(this._multiWindowTitle);
stack.add_child(this._multiWindowTitle);
this._icon = new St.Bin({
style_class: 'window-button-icon',
child: app.create_icon_texture(ICON_TEXTURE_SIZE),
});
this._multiWindowTitle.add(this._icon);
this._multiWindowTitle.add_child(this._icon);
let label = new St.Label({
text: app.get_name(),
y_align: Clutter.ActorAlign.CENTER,
});
this._multiWindowTitle.add(label);
this._multiWindowTitle.add_child(label);
this._multiWindowTitle.label_actor = label;
this._menuManager = new PopupMenu.PopupMenuManager(this);
@@ -560,18 +579,13 @@ class AppButton extends BaseButton {
this._menu.actor.hide();
this._menu.connect('activate', this._onMenuActivate.bind(this));
this._menuManager.addMenu(this._menu);
Main.uiGroup.add_actor(this._menu.actor);
Main.uiGroup.add_child(this._menu.actor);
this._appContextMenu = new AppContextMenu(this);
this._appContextMenu.connect('open-state-changed',
this._onMenuStateChanged.bind(this));
this._appContextMenu.actor.hide();
Main.uiGroup.add_actor(this._appContextMenu.actor);
this._textureCache = St.TextureCache.get_default();
this._textureCache.connectObject('icon-theme-changed', () => {
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
}, this);
Main.uiGroup.add_child(this._appContextMenu.actor);
this.app.connectObject('windows-changed',
() => this._windowsChanged(), this);
@@ -631,7 +645,7 @@ class AppButton extends BaseButton {
this._windowContextMenu = new WindowContextMenu(this, this.metaWindow);
this._windowContextMenu.connect(
'open-state-changed', this._onMenuStateChanged.bind(this));
Main.uiGroup.add_actor(this._windowContextMenu.actor);
Main.uiGroup.add_child(this._windowContextMenu.actor);
this._windowContextMenu.actor.hide();
this._contextMenuManager.addMenu(this._windowContextMenu);
}
@@ -676,7 +690,7 @@ class AppButton extends BaseButton {
for (let i = 0; i < windows.length; i++) {
let windowTitle = new WindowTitle(windows[i]);
let item = new PopupMenu.PopupBaseMenuItem();
item.add_actor(windowTitle);
item.add_child(windowTitle);
item._window = windows[i];
this._menu.addMenuItem(item);
}
@@ -722,36 +736,26 @@ class WindowList extends St.Widget {
this._monitor = monitor;
let box = new St.BoxLayout({x_expand: true, y_expand: true});
this.add_actor(box);
this.add_child(box);
let toggle = new WindowPickerToggle();
box.add_actor(toggle);
toggle.connect('notify::checked',
this._updateWindowListVisibility.bind(this));
let layout = new Clutter.BoxLayout({homogeneous: true});
this._windowList = new St.Widget({
this._windowList = new St.BoxLayout({
style_class: 'window-list',
reactive: true,
layout_manager: layout,
x_align: Clutter.ActorAlign.START,
x_expand: true,
y_expand: true,
});
box.add_child(this._windowList);
this._windowList.connect('style-changed', () => {
let node = this._windowList.get_theme_node();
let spacing = node.get_length('spacing');
this._windowList.layout_manager.spacing = spacing;
});
this._windowList.connect('scroll-event', this._onScrollEvent.bind(this));
let indicatorsBox = new St.BoxLayout({x_align: Clutter.ActorAlign.END});
box.add(indicatorsBox);
box.add_child(indicatorsBox);
this._workspaceIndicator = new WorkspaceIndicator();
this._workspaceIndicator = new BottomWorkspaceIndicator({
baseStyleClass: 'window-list-workspace-indicator',
settings,
});
indicatorsBox.add_child(this._workspaceIndicator.container);
this._mutterSettings = new Gio.Settings({schema_id: 'org.gnome.mutter'});
@@ -764,12 +768,15 @@ class WindowList extends St.Widget {
this._updateWorkspaceIndicatorVisibility();
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._menuManager.addMenu(this._workspaceIndicator.menu);
this._workspaceIndicator.connectObject('menu-set',
() => this._onWorkspaceMenuSet(), this);
this._onWorkspaceMenuSet();
Main.layoutManager.addChrome(this, {
const chromeOptions = {
affectsStruts: true,
trackFullscreen: true,
});
};
Main.layoutManager.addChrome(this, chromeOptions);
Main.uiGroup.set_child_above_sibling(this, Main.layoutManager.panelBox);
Main.ctrlAltTabManager.addGroup(this, _('Window List'), 'start-here-symbolic');
@@ -806,10 +813,12 @@ class WindowList extends St.Widget {
Main.overview.connectObject(
'showing', () => {
Main.layoutManager.untrackChrome(this);
this.hide();
this._updateKeyboardAnchor();
},
'hidden', () => {
Main.layoutManager.trackChrome(this, chromeOptions);
this.visible = !this._monitor.inFullscreen;
this._updateKeyboardAnchor();
}, this);
@@ -822,8 +831,8 @@ class WindowList extends St.Widget {
}, this);
this._windowSignals = new Map();
this._windowCreatedId = global.display.connect(
'window-created', (dsp, win) => this._addWindow(win));
global.display.connectObject(
'window-created', (dsp, win) => this._addWindow(win, true), this);
Main.xdndHandler.connectObject(
'drag-begin', () => this._monitorDrag(),
@@ -838,8 +847,8 @@ class WindowList extends St.Widget {
this._dndWindow = null;
this._settings = settings;
this._settings.connect('changed::grouping-mode',
() => this._groupingModeChanged());
this._settings.connectObject('changed::grouping-mode',
() => this._groupingModeChanged(), this);
this._grouped = undefined;
this._groupingModeChanged();
}
@@ -861,6 +870,11 @@ class WindowList extends St.Widget {
children[newActive].activate();
}
_onWorkspaceMenuSet() {
if (this._workspaceIndicator.menu)
this._menuManager.addMenu(this._workspaceIndicator.menu);
}
_updatePosition() {
this.set_position(
this._monitor.x,
@@ -877,20 +891,6 @@ class WindowList extends St.Widget {
this._workspaceIndicator.visible = hasWorkspaces && workspacesOnMonitor;
}
_updateWindowListVisibility() {
const {windowPicker} = Extension.lookupByURL(import.meta.url);
const visible = !windowPicker.visible;
this._windowList.ease({
opacity: visible ? 255 : 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: Overview.ANIMATION_TIME,
});
this._windowList.reactive = visible;
this._windowList.get_children().forEach(c => (c.reactive = visible));
}
_getPreferredUngroupedWindowListWidth() {
if (this._windowList.get_n_children() === 0)
return this._windowList.get_preferred_width(-1)[1];
@@ -949,14 +949,14 @@ class WindowList extends St.Widget {
w2.metaWindow.get_stable_sequence();
});
for (let i = 0; i < windows.length; i++)
this._addWindow(windows[i].metaWindow);
this._addWindow(windows[i].metaWindow, false);
} else {
let apps = this._appSystem.get_running().sort((a1, a2) => {
return _getAppStableSequence(a1) -
_getAppStableSequence(a2);
});
for (let i = 0; i < apps.length; i++)
this._addApp(apps[i]);
this._addApp(apps[i], false);
}
}
@@ -970,26 +970,26 @@ class WindowList extends St.Widget {
return;
if (app.state === Shell.AppState.RUNNING)
this._addApp(app);
this._addApp(app, true);
else if (app.state === Shell.AppState.STOPPED)
this._removeApp(app);
}
_addApp(app) {
_addApp(app, animate) {
let button = new AppButton(app, this._perMonitor, this._monitor.index);
this._settings.bind('display-all-workspaces',
button, 'ignore-workspace', Gio.SettingsBindFlags.GET);
this._windowList.add_child(button);
button.show(animate);
}
_removeApp(app) {
let children = this._windowList.get_children();
let child = children.find(c => c.app === app);
if (child)
child.destroy();
child?.animateOutAndDestroy();
}
_addWindow(win) {
_addWindow(win, animate) {
if (!this._grouped)
this._checkGrouping();
@@ -1007,6 +1007,7 @@ class WindowList extends St.Widget {
this._settings.bind('display-all-workspaces',
button, 'ignore-workspace', Gio.SettingsBindFlags.GET);
this._windowList.add_child(button);
button.show(animate);
}
_removeWindow(win) {
@@ -1023,8 +1024,7 @@ class WindowList extends St.Widget {
let children = this._windowList.get_children();
let child = children.find(c => c.metaWindow === win);
if (child)
child.destroy();
child?.animateOutAndDestroy();
}
_monitorDrag() {
@@ -1086,7 +1086,8 @@ class WindowList extends St.Widget {
this._stopMonitoringDrag();
this._settings.run_dispose();
this._settings.disconnectObject();
this._settings = null;
let windows = global.get_window_actors();
for (let i = 0; i < windows.length; i++)
@@ -1094,12 +1095,33 @@ class WindowList extends St.Widget {
}
}
class BottomWorkspaceIndicator extends WorkspaceIndicator {
static {
GObject.registerClass(this);
}
constructor(params) {
super(params);
this.remove_style_class_name('panel-button');
}
setMenu(menu) {
super.setMenu(menu);
if (!menu)
return;
this.menu.actor.updateArrowSide(St.Side.BOTTOM);
this.menu.actor.remove_style_class_name('panel-menu');
}
}
export default class WindowListExtension extends Extension {
constructor(metadata) {
super(metadata);
this._windowLists = null;
this._hideOverviewOrig = Main.overview.hide;
}
enable() {
@@ -1112,13 +1134,6 @@ export default class WindowListExtension extends Extension {
Main.layoutManager.connectObject('monitors-changed',
() => this._buildWindowLists(), this);
this.windowPicker = new WindowPicker();
Main.overview.hide = () => {
this.windowPicker.close();
this._hideOverviewOrig.call(Main.overview);
};
this._buildWindowLists();
}
@@ -1138,86 +1153,18 @@ export default class WindowListExtension extends Extension {
if (!this._windowLists)
return;
this._settings.disconnectObject(this);
Main.layoutManager.disconnectObject(this);
this._settings.disconnectObject(this);
this._settings = null;
this._windowLists.forEach(windowList => {
windowList.hide();
windowList.destroy();
});
this._windowLists = null;
this.windowPicker.destroy();
delete this.windowPicker;
Main.overview.hide = this._hideOverviewOrig;
}
someWindowListContains(actor) {
return this._windowLists.some(list => list.contains(actor));
}
}
class Tooltip extends St.Label {
static {
GObject.registerClass(this);
}
constructor(widget, params) {
super(params);
this._widget = widget;
this._widget.connect('notify::hover', () => {
if (this._widget.hover)
this.open();
else
this.close();
});
}
open() {
const buttonTitleWidget = this._widget.label_actor;
const [, , preferredTitleWidth] = buttonTitleWidget.get_preferred_size();
const maxTitleWidth = buttonTitleWidget.allocation.get_width();
const isTitleFullyShown = preferredTitleWidth <= maxTitleWidth;
if (isTitleFullyShown)
return;
this.set({
text: this._widget.label_actor.get_text(),
visible: true,
opacity: 0,
});
const [stageX, stageY] = this._widget.get_transformed_position();
const thumbWidth = this._widget.allocation.get_width();
const tipWidth = this.width;
const tipHeight = this.height;
const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
const monitor = Main.layoutManager.findMonitorForActor(this);
const x = Math.clamp(
stageX + xOffset,
monitor.x,
monitor.x + monitor.width - tipWidth);
const y = stageY - tipHeight - TOOLTIP_OFFSET;
this.set_position(x, y);
this.ease({
opacity: 255,
duration: TOOLTIP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this.visible = this._widget.hover),
});
}
close() {
this.ease({
opacity: 0,
duration: TOOLTIP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this.visible = this._widget.hover),
});
}
}

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,
@@ -8,5 +12,32 @@ extension_data += files(
'stylesheet-light.css'
)
extension_sources += files('prefs.js', 'windowPicker.js', 'workspaceIndicator.js')
transform_stylesheet = [
'sed', '-E',
'-e', 's:^\.(workspace-indicator):.window-list-\\1:',
'-e', '/^@import/d',
'@INPUT@',
]
workspaceIndicatorSources = [
configure_file(
input: '../workspace-indicator/workspaceIndicator.js',
output: '@PLAINNAME@',
copy: true,
),
configure_file(
input: '../workspace-indicator/stylesheet-dark.css',
output: 'stylesheet-workspace-switcher-dark.css',
command: transform_stylesheet,
capture: true,
),
configure_file(
input: '../workspace-indicator/stylesheet-light.css',
output: 'stylesheet-workspace-switcher-light.css',
command: transform_stylesheet,
capture: true,
),
]
extension_sources += files('prefs.js') + workspaceIndicatorSources
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')

View File

@@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: 2016 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<enum id="org.gnome.shell.extensions.window-list.GroupingMode">
<value value="0" nick="never"/>
@@ -30,5 +36,9 @@
only on the primary one.
</description>
</key>
<key name="embed-previews" type="b">
<default>true</default>
<summary>Show workspace previews in window list</summary>
</key>
</schema>
</schemalist>

View File

@@ -1,4 +1,8 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2014 Sylvain Pasche <sylvain.pasche@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
@@ -25,6 +29,8 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
this._settings.create_action('show-on-all-monitors'));
this._actionGroup.add_action(
this._settings.create_action('display-all-workspaces'));
this._actionGroup.add_action(
this._settings.create_action('embed-previews'));
const groupingGroup = new Adw.PreferencesGroup({
title: _('Window Grouping'),
@@ -53,28 +59,22 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
const miscGroup = new Adw.PreferencesGroup();
this.add(miscGroup);
let toggle = new Gtk.Switch({
action_name: 'window-list.show-on-all-monitors',
valign: Gtk.Align.CENTER,
});
let row = new Adw.ActionRow({
let row = new Adw.SwitchRow({
title: _('Show on all monitors'),
activatable_widget: toggle,
action_name: 'window-list.show-on-all-monitors',
});
row.add_suffix(toggle);
miscGroup.add(row);
toggle = new Gtk.Switch({
action_name: 'window-list.display-all-workspaces',
valign: Gtk.Align.CENTER,
});
this._settings.bind('display-all-workspaces',
toggle, 'active', Gio.SettingsBindFlags.DEFAULT);
row = new Adw.ActionRow({
row = new Adw.SwitchRow({
title: _('Show windows from all workspaces'),
activatable_widget: toggle,
action_name: 'window-list.display-all-workspaces',
});
miscGroup.add(row);
row = new Adw.SwitchRow({
title: _('Show workspace previews'),
action_name: 'window-list.embed-previews',
});
row.add_suffix(toggle);
miscGroup.add(row);
}
}

View File

@@ -1,113 +1,83 @@
/*
* SPDX-FileCopyrightText: 2012 Florian Müllner <fmuellner@gnome.org>
* SPDX-FileCopyrightText: 2013 Giovanni Campagna <gcampagna@src.gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@import url("stylesheet-workspace-switcher-dark.css");
.window-list {
spacing: 2px;
font-size: 10pt;
spacing: 2px;
font-size: 10pt;
}
.bottom-panel {
background-color: #000000;
border-top-width: 0px;
padding: 2px;
background-color: #000000;
border-top-width: 0px;
height: 2.45em;
}
.window-button {
padding: 2px, 1px;
padding: 4px, 3px;
}
.window-button:first-child:ltr {
padding-left: 2px;
padding-left: 2px;
}
.window-button:last-child:rtl {
padding-right: 2px;
padding-right: 2px;
}
.window-button-box {
spacing: 4px;
}
.window-button > StWidget,
.window-picker-toggle > StWidget {
color: #bbb;
background-color: #1d1d1d;
border-radius: 4px;
padding: 3px 6px 1px;
transition: 100ms ease;
spacing: 4px;
}
.window-button > StWidget {
-st-natural-width: 18.75em;
max-width: 18.75em;
color: #fff;
background-color: transparent;
border-radius: 4px;
padding: 3px 6px 1px;
transition: 100ms ease;
}
.window-button:hover > StWidget,
.window-picker-toggle:hover > StWidget {
color: #fff;
background-color: #303030;
.window-button > StWidget {
-st-natural-width: 18.75em;
max-width: 18.75em;
}
.window-button:hover > StWidget {
background-color: #303030;
}
.window-button:active > StWidget,
.window-button:focus > StWidget {
color: #fff;
background-color: #3f3f3f;
background-color: st-lighten(#303030, 5%);
}
.window-button.focused > StWidget,
.window-picker-toggle:checked > StWidget {
color: #fff;
background-color: #3f3f3f;
.window-button.focused > StWidget {
background-color: #5b5b5b;
}
.window-button.focused:active > StWidget,
.window-picker-toggle:checked:active > StWidget {
color: #fff;
background-color: #3f3f3f;
}
.window-button.focused:hover > StWidget {
background-color: st-lighten(#5b5b5b, 5%);
}
.window-button.focused:active > StWidget {
background-color: st-lighten(#5b5b5b, 10%);
}
.window-button.minimized > StWidget {
color: #666;
background-color: #161616;
color: #666;
background-color: #161616;
}
.window-button.minimized:active > StWidget {
color: #666;
background-color: #161616;
color: #666;
background-color: #161616;
}
.window-button-icon {
width: 24px;
height: 24px;
}
.window-list-workspace-indicator .status-label-bin {
background-color: rgba(200, 200, 200, 0.3);
padding: 0 3px;
margin: 3px;
}
.window-list-workspace-indicator .workspaces-box {
spacing: 3px;
padding: 3px;
}
.window-list-workspace-indicator .workspace {
width: 52px;
border-radius: 4px;
background-color: #1e1e1e;
}
.window-list-workspace-indicator .workspace.active {
background-color: #3f3f3f;
}
.window-list-window-preview {
background-color: #bebebe;
border-radius: 1px;
}
.window-list-window-preview.active {
background-color: #d4d4d4;
}
.notification {
font-weight: normal;
width: 24px;
height: 24px;
}

View File

@@ -1,68 +1,58 @@
/*
* SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
* SPDX-FileCopyrightText: 2015 Jakub Steiner <jimmac@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@import url("stylesheet-dark.css");
@import url("stylesheet-workspace-switcher-light.css");
#panel.bottom-panel {
border-top-width: 1px;
border-bottom-width: 0px;
height: 2.25em ;
padding: 2px;
height: 2.5em;
}
.bottom-panel .window-button > StWidget,
.bottom-panel .window-picker-toggle > StWidget {
color: #2e3436;
background-color: #eee;
.bottom-panel .window-button > StWidget {
border-radius: 3px;
padding: 3px 6px 1px;
box-shadow: none;
text-shadow: none;
border: 1px solid rgba(0,0,0,0.2);
}
.bottom-panel .window-button > StWidget {
-st-natural-width: 18.7em;
max-width: 18.75em;
}
.bottom-panel .window-button:hover > StWidget,
.bottom-panel .window-picker-toggle:hover > StWidget {
background-color: #f9f9f9;
}
.bottom-panel .window-button:active > StWidget,
.bottom-panel .window-button:focus > StWidget {
box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
}
.bottom-panel .window-button.focused > StWidget,
.bottom-panel .window-picker-toggle:checked > StWidget {
background-color: #ccc;
box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
}
.bottom-panel .window-button.focused:hover > StWidget {
background-color: #e9e9e9;
}
.bottom-panel .window-button.minimized > StWidget {
color: #888;
box-shadow: none;
}
/* workspace switcher */
.window-list-workspace-indicator .workspace {
border: 2px solid #f6f5f4;
background-color: #ccc;
.window-button > StWidget {
color: #000;
background-color: transparent;
}
.window-list-workspace-indicator .workspace.active {
border-color: #888;
.window-button:hover > StWidget {
background-color: st-darken(#eee,5%);
}
.window-list-window-preview {
background-color: #ededed;
border: 1px solid #ccc;
.window-button:active > StWidget,
.window-button:focus > StWidget {
background-color: st-darken(#eee, 10%);
}
.window-list-window-preview.active {
background-color: #f6f5f4;
.window-button.focused > StWidget {
background-color: st-darken(#eee,15%);
}
.window-button.focused:hover > StWidget {
background-color: st-darken(#eee, 20%);
}
.window-button.focused:active > StWidget {
background-color: st-darken(#eee, 25%);
}
.window-button.minimized > StWidget {
color: #aaa;
background-color: #f9f9f9;
}
.window-button.minimized:active > StWidget {
color: #aaa;
background-color: #f9f9f9;
}

View File

@@ -1,337 +0,0 @@
import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import Shell from 'gi://Shell';
import St from 'gi://St';
import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import {WorkspacesDisplay} from 'resource:///org/gnome/shell/ui/workspacesView.js';
import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js';
import {VIGNETTE_BRIGHTNESS} from 'resource:///org/gnome/shell/ui/lightbox.js';
import {
SIDE_CONTROLS_ANIMATION_TIME,
OverviewAdjustment,
ControlsState
} from 'resource:///org/gnome/shell/ui/overviewControls.js';
class MyWorkspacesDisplay extends WorkspacesDisplay {
static {
GObject.registerClass(this);
}
constructor(controls, overviewAdjustment) {
let workspaceManager = global.workspace_manager;
const workspaceAdjustment = new St.Adjustment({
value: workspaceManager.get_active_workspace_index(),
lower: 0,
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: workspaceManager.n_workspaces,
});
super(controls, workspaceAdjustment, overviewAdjustment);
this._windowPicker = controls;
this._workspaceAdjustment = workspaceAdjustment;
this._workspaceAdjustment.actor = this;
workspaceManager.connectObject('notify::n-workspaces',
() => this._updateAdjustment(), this);
this.add_constraint(
new Layout.MonitorConstraint({
primary: true,
work_area: true,
}));
}
prepareToEnterOverview(...args) {
if (!this._scrollEventId) {
this._scrollEventId = this._windowPicker.connect('scroll-event',
this._onScrollEvent.bind(this));
}
super.prepareToEnterOverview(...args);
}
vfunc_hide(...args) {
if (this._scrollEventId > 0)
this._windowPicker.disconnect(this._scrollEventId);
this._scrollEventId = 0;
super.vfunc_hide(...args);
}
_updateAdjustment() {
let workspaceManager = global.workspace_manager;
this._workspaceAdjustment.set({
upper: workspaceManager.n_workspaces,
value: workspaceManager.get_active_workspace_index(),
});
}
}
export class WindowPicker extends Clutter.Actor {
static [GObject.signals] = {
'open-state-changed': {param_types: [GObject.TYPE_BOOLEAN]},
};
static {
GObject.registerClass(this);
}
constructor() {
super({reactive: true});
this._visible = false;
this._modal = false;
this._stageKeyPressId = 0;
this._adjustment = new OverviewAdjustment(this);
this._injectionManager = new InjectionManager();
this.connect('destroy', this._onDestroy.bind(this));
global.bind_property('screen-width',
this, 'width',
GObject.BindingFlags.SYNC_CREATE);
global.bind_property('screen-height',
this, 'height',
GObject.BindingFlags.SYNC_CREATE);
this._workspacesDisplay = new MyWorkspacesDisplay(this, this._adjustment);
this.add_child(this._workspacesDisplay);
Main.uiGroup.insert_child_below(this, global.window_group);
if (!Main.sessionMode.hasOverview) {
this._injectBackgroundShade();
global.display.connectObject('overlay-key', () => {
if (!this._visible)
this.open();
else
this.close();
}, this);
}
}
_injectBackgroundShade() {
const backgroundProto = Workspace.WorkspaceBackground.prototype;
this._injectionManager.overrideMethod(backgroundProto, '_updateBorderRadius',
() => {
return function () {};
});
this._injectionManager.overrideMethod(backgroundProto, 'vfunc_allocate',
() => {
/* eslint-disable no-invalid-this */
return function (box) {
this.set_allocation(box);
const themeNode = this.get_theme_node();
const contentBox = themeNode.get_content_box(box);
this._bin.allocate(contentBox);
const [contentWidth, contentHeight] = contentBox.get_size();
const monitor = Main.layoutManager.monitors[this._monitorIndex];
const xRatio = contentWidth / this._workarea.width;
const yRatio = contentHeight / this._workarea.height;
const right = area => area.x + area.width;
const bottom = area => area.y + area.height;
const offsets = {
left: xRatio * (this._workarea.x - monitor.x),
right: xRatio * (right(monitor) - right(this._workarea)),
top: yRatio * (this._workarea.y - monitor.y),
bottom: yRatio * (bottom(monitor) - bottom(this._workarea)),
};
contentBox.set_origin(-offsets.left, -offsets.top);
contentBox.set_size(
offsets.left + contentWidth + offsets.right,
offsets.top + contentHeight + offsets.bottom);
this._backgroundGroup.allocate(contentBox);
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(backgroundProto, 'vfunc_parent_set',
() => {
/* eslint-disable no-invalid-this */
return function () {
setTimeout(() => {
const parent = this.get_parent();
if (!parent)
return;
parent._overviewAdjustment.connectObject('notify::value', () => {
const {value: progress} = parent._overviewAdjustment;
const brightness = 1 - (1 - VIGNETTE_BRIGHTNESS) * progress;
for (const bg of this._backgroundGroup ?? []) {
bg.content.set({
vignette: true,
brightness,
});
}
}, this);
});
};
/* eslint-enable */
});
}
get visible() {
return this._visible;
}
open() {
if (this._visible)
return;
this._visible = true;
if (!this._syncGrab())
return;
this._fakeOverviewVisible(true);
this._workspacesDisplay.prepareToEnterOverview();
Main.overview._animationInProgress = true;
this._adjustment.value = ControlsState.HIDDEN;
this._adjustment.ease(ControlsState.WINDOW_PICKER, {
duration: SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (Main.overview._animationInProgress = false),
});
this._stageKeyPressId = global.stage.connect('key-press-event',
(a, event) => {
let sym = event.get_key_symbol();
if (sym === Clutter.KEY_Escape) {
this.close();
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
});
this.emit('open-state-changed', this._visible);
}
close() {
if (!this._visible)
return;
this._visible = false;
if (!this._syncGrab())
return;
this._workspacesDisplay.prepareToLeaveOverview();
Main.overview._animationInProgress = true;
this._adjustment.ease(ControlsState.HIDDEN, {
duration: SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
Main.overview._animationInProgress = false;
this._workspacesDisplay.hide();
this._fakeOverviewVisible(false);
},
});
global.stage.disconnect(this._stageKeyPressId);
this._stageKeyPressId = 0;
this.emit('open-state-changed', this._visible);
}
getWorkspacesBoxForState() {
return this.allocation;
}
_fakeOverviewVisible(visible) {
// Fake overview state for WorkspacesDisplay
Main.overview._visible = visible;
// Hide real windows
Main.layoutManager._inOverview = visible;
Main.layoutManager._updateVisibility();
}
_syncGrab() {
if (this._visible) {
if (this._modal)
return true;
const grab = Main.pushModal(global.stage, {
actionMode: Shell.ActionMode.OVERVIEW,
});
if (grab.get_seat_state() !== Clutter.GrabState.NONE) {
this._grab = grab;
this._modal = true;
} else {
Main.popModal(grab);
this.hide();
return false;
}
} else if (this._modal) {
Main.popModal(this._grab);
this._modal = false;
this._grab = null;
}
return true;
}
_onDestroy() {
this._injectionManager.clear();
if (this._stageKeyPressId)
global.stage.disconnect(this._stageKeyPressId);
this._stageKeyPressId = 0;
}
}
export class WindowPickerToggle extends St.Button {
static {
GObject.registerClass(this);
}
constructor() {
let iconBin = new St.Widget({
layout_manager: new Clutter.BinLayout(),
});
iconBin.add_child(new St.Icon({
icon_name: 'focus-windows-symbolic',
icon_size: 16,
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
}));
super({
style_class: 'window-picker-toggle',
child: iconBin,
visible: !Main.sessionMode.hasOverview,
toggle_mode: true,
});
const {windowPicker} = Extension.lookupByURL(import.meta.url);
this.connect('notify::checked', () => {
if (this.checked)
windowPicker.open();
else
windowPicker.close();
});
windowPicker.connect('open-state-changed', () => {
this.checked = windowPicker.visible;
});
}
}

View File

@@ -1,420 +0,0 @@
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Meta from 'gi://Meta';
import St from 'gi://St';
import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
const MAX_THUMBNAILS = 6;
class WindowPreview extends St.Button {
static {
GObject.registerClass(this);
}
constructor(window) {
super({
style_class: 'window-list-window-preview',
});
this._delegate = this;
DND.makeDraggable(this, {restoreOnSuccess: true});
this._window = window;
this._window.connectObject(
'size-changed', () => this.queue_relayout(),
'position-changed', () => {
this._updateVisible();
this.queue_relayout();
},
'notify::minimized', this._updateVisible.bind(this),
this);
global.display.connectObject('notify::focus-window',
this._onFocusChanged.bind(this), this);
this._onFocusChanged();
}
// needed for DND
get metaWindow() {
return this._window;
}
_onFocusChanged() {
if (global.display.focus_window === this._window)
this.add_style_class_name('active');
else
this.remove_style_class_name('active');
}
_updateVisible() {
const monitor = Main.layoutManager.findIndexForActor(this);
const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
this.visible = this._window.get_frame_rect().overlap(workArea) &&
this._window.window_type !== Meta.WindowType.DESKTOP &&
this._window.showing_on_its_workspace();
}
}
class WorkspaceLayout extends Clutter.LayoutManager {
static {
GObject.registerClass(this);
}
vfunc_get_preferred_width() {
return [0, 0];
}
vfunc_get_preferred_height() {
return [0, 0];
}
vfunc_allocate(container, box) {
const monitor = Main.layoutManager.findIndexForActor(container);
const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
const hscale = box.get_width() / workArea.width;
const vscale = box.get_height() / workArea.height;
for (const child of container) {
const childBox = new Clutter.ActorBox();
const frameRect = child.metaWindow.get_frame_rect();
childBox.set_size(
Math.round(Math.min(frameRect.width, workArea.width) * hscale),
Math.round(Math.min(frameRect.height, workArea.height) * vscale));
childBox.set_origin(
Math.round((frameRect.x - workArea.x) * hscale),
Math.round((frameRect.y - workArea.y) * vscale));
child.allocate(childBox);
}
}
}
class WorkspaceThumbnail extends St.Button {
static {
GObject.registerClass(this);
}
constructor(index) {
super({
style_class: 'workspace',
child: new Clutter.Actor({
layout_manager: new WorkspaceLayout(),
clip_to_allocation: true,
}),
});
this._tooltip = new St.Label({
style_class: 'dash-label',
visible: false,
});
Main.uiGroup.add_child(this._tooltip);
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::hover', this._syncTooltip.bind(this));
this._index = index;
this._delegate = this; // needed for DND
this._windowPreviews = new Map();
let workspaceManager = global.workspace_manager;
this._workspace = workspaceManager.get_workspace_by_index(index);
this._workspace.connectObject(
'window-added', (ws, window) => this._addWindow(window),
'window-removed', (ws, window) => this._removeWindow(window),
this);
global.display.connectObject('restacked',
this._onRestacked.bind(this), this);
this._workspace.list_windows().forEach(w => this._addWindow(w));
this._onRestacked();
}
acceptDrop(source) {
if (!source.metaWindow)
return false;
this._moveWindow(source.metaWindow);
return true;
}
handleDragOver(source) {
if (source.metaWindow)
return DND.DragMotionResult.MOVE_DROP;
else
return DND.DragMotionResult.CONTINUE;
}
_addWindow(window) {
if (this._windowPreviews.has(window))
return;
let preview = new WindowPreview(window);
preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
this._windowPreviews.set(window, preview);
this.child.add_child(preview);
}
_removeWindow(window) {
let preview = this._windowPreviews.get(window);
if (!preview)
return;
this._windowPreviews.delete(window);
preview.destroy();
}
_onRestacked() {
let lastPreview = null;
let windows = global.get_window_actors().map(a => a.meta_window);
for (let i = 0; i < windows.length; i++) {
let preview = this._windowPreviews.get(windows[i]);
if (!preview)
continue;
this.child.set_child_above_sibling(preview, lastPreview);
lastPreview = preview;
}
}
_moveWindow(window) {
let monitorIndex = Main.layoutManager.findIndexForActor(this);
if (monitorIndex !== window.get_monitor())
window.move_to_monitor(monitorIndex);
window.change_workspace_by_index(this._index, false);
}
on_clicked() {
let ws = global.workspace_manager.get_workspace_by_index(this._index);
if (ws)
ws.activate(global.get_current_time());
}
_syncTooltip() {
if (this.hover) {
this._tooltip.set({
text: Meta.prefs_get_workspace_name(this._index),
visible: true,
opacity: 0,
});
const [stageX, stageY] = this.get_transformed_position();
const thumbWidth = this.allocation.get_width();
const tipWidth = this._tooltip.width;
const tipHeight = this._tooltip.height;
const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
const monitor = Main.layoutManager.findMonitorForActor(this);
const x = Math.clamp(
stageX + xOffset,
monitor.x,
monitor.x + monitor.width - tipWidth);
const y = stageY - tipHeight - TOOLTIP_OFFSET;
this._tooltip.set_position(x, y);
}
this._tooltip.ease({
opacity: this.hover ? 255 : 0,
duration: TOOLTIP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this._tooltip.visible = this.hover),
});
}
_onDestroy() {
this._tooltip.destroy();
}
}
export class WorkspaceIndicator extends PanelMenu.Button {
static {
GObject.registerClass(this);
}
constructor() {
super(0.5, _('Workspace Indicator'), true);
this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM));
this.add_style_class_name('window-list-workspace-indicator');
this.remove_style_class_name('panel-button');
this.menu.actor.remove_style_class_name('panel-menu');
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
});
this.add_actor(container);
let workspaceManager = global.workspace_manager;
this._currentWorkspace = workspaceManager.get_active_workspace_index();
this._statusLabel = new St.Label({text: this._getStatusText()});
this._statusBin = new St.Bin({
style_class: 'status-label-bin',
x_expand: true,
y_expand: true,
child: this._statusLabel,
});
container.add_actor(this._statusBin);
this._thumbnailsBox = new St.BoxLayout({
style_class: 'workspaces-box',
y_expand: true,
reactive: true,
});
this._thumbnailsBox.connect('scroll-event',
this._onScrollEvent.bind(this));
container.add_actor(this._thumbnailsBox);
this._workspacesItems = [];
workspaceManager.connectObject(
'notify::n-workspaces', this._nWorkspacesChanged.bind(this), GObject.ConnectFlags.AFTER,
'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
'notify::layout-rows', this._updateThumbnailVisibility.bind(this),
this);
this.connect('scroll-event', this._onScrollEvent.bind(this));
this._updateMenu();
this._updateThumbnails();
this._updateThumbnailVisibility();
this._settings = new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
this._settings.connectObject('changed::workspace-names',
() => this._updateMenuLabels(), this);
}
_updateThumbnailVisibility() {
const {workspaceManager} = global;
const vertical = workspaceManager.layout_rows === -1;
const useMenu =
vertical || workspaceManager.n_workspaces > MAX_THUMBNAILS;
this.reactive = useMenu;
this._statusBin.visible = useMenu;
this._thumbnailsBox.visible = !useMenu;
}
_onWorkspaceSwitched() {
let workspaceManager = global.workspace_manager;
this._currentWorkspace = workspaceManager.get_active_workspace_index();
this._updateMenuOrnament();
this._updateActiveThumbnail();
this._statusLabel.set_text(this._getStatusText());
}
_nWorkspacesChanged() {
this._updateMenu();
this._updateThumbnails();
this._updateThumbnailVisibility();
}
_updateMenuOrnament() {
for (let i = 0; i < this._workspacesItems.length; i++) {
this._workspacesItems[i].setOrnament(i === this._currentWorkspace
? PopupMenu.Ornament.DOT
: PopupMenu.Ornament.NONE);
}
}
_updateActiveThumbnail() {
let thumbs = this._thumbnailsBox.get_children();
for (let i = 0; i < thumbs.length; i++) {
if (i === this._currentWorkspace)
thumbs[i].add_style_class_name('active');
else
thumbs[i].remove_style_class_name('active');
}
}
_getStatusText() {
let workspaceManager = global.workspace_manager;
let current = workspaceManager.get_active_workspace_index();
let total = workspaceManager.n_workspaces;
return '%d / %d'.format(current + 1, total);
}
_updateMenuLabels() {
for (let i = 0; i < this._workspacesItems.length; i++) {
let item = this._workspacesItems[i];
let name = Meta.prefs_get_workspace_name(i);
item.label.text = name;
}
}
_updateMenu() {
let workspaceManager = global.workspace_manager;
this.menu.removeAll();
this._workspacesItems = [];
this._currentWorkspace = workspaceManager.get_active_workspace_index();
for (let i = 0; i < workspaceManager.n_workspaces; i++) {
let name = Meta.prefs_get_workspace_name(i);
let item = new PopupMenu.PopupMenuItem(name);
item.workspaceId = i;
item.connect('activate', () => {
this._activate(item.workspaceId);
});
if (i === this._currentWorkspace)
item.setOrnament(PopupMenu.Ornament.DOT);
this.menu.addMenuItem(item);
this._workspacesItems[i] = item;
}
this._statusLabel.set_text(this._getStatusText());
}
_updateThumbnails() {
let workspaceManager = global.workspace_manager;
this._thumbnailsBox.destroy_all_children();
for (let i = 0; i < workspaceManager.n_workspaces; i++) {
let thumb = new WorkspaceThumbnail(i);
this._thumbnailsBox.add_actor(thumb);
}
this._updateActiveThumbnail();
}
_activate(index) {
let workspaceManager = global.workspace_manager;
if (index >= 0 && index < workspaceManager.n_workspaces) {
let metaWorkspace = workspaceManager.get_workspace_by_index(index);
metaWorkspace.activate(global.get_current_time());
}
}
_onScrollEvent(actor, event) {
let direction = event.get_scroll_direction();
let diff = 0;
if (direction === Clutter.ScrollDirection.DOWN)
diff = 1;
else if (direction === Clutter.ScrollDirection.UP)
diff = -1;
else
return;
let newIndex = this._currentWorkspace + diff;
this._activate(newIndex);
}
}

View File

@@ -1,4 +1,11 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
// SPDX-FileCopyrightText: 2011 Maxim Ermilov <zaspire@rambler.ru>
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
// SPDX-FileCopyrightText: 2019 Marco Trevisan (Treviño) <mail@3v1n0.net>
// SPDX-FileCopyrightText: 2020 Thun Pin <thunpin@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import Graphene from 'gi://Graphene';
import St from 'gi://St';
@@ -78,7 +85,7 @@ export default class Extension {
style_class: 'extension-windowsNavigator-window-tooltip',
visible: false,
});
this.add_actor(this._tip);
this.add_child(this._tip);
this.connect('notify::scale-x', () => {
this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2011 Maxim Ermilov <zaspire@rambler.ru>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.extension-windowsNavigator-window-tooltip {
color: #fefefe;
background: rgba(0,0,0,0.8);
@@ -6,4 +12,4 @@
font-size: 16px;
padding: 2px 8px;
-shell-caption-spacing: 4px;
}
}

View File

@@ -1,434 +1,20 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Meta from 'gi://Meta';
import St from 'gi://St';
// SPDX-FileCopyrightText: 2011 Erick Pérez Castellanos <erick.red@gmail.com>
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
const MAX_THUMBNAILS = 6;
class WindowPreview extends St.Button {
static {
GObject.registerClass(this);
}
constructor(window) {
super({
style_class: 'workspace-indicator-window-preview',
});
this._delegate = this;
DND.makeDraggable(this, {restoreOnSuccess: true});
this._window = window;
this._window.connectObject(
'size-changed', () => this.queue_relayout(),
'position-changed', () => {
this._updateVisible();
this.queue_relayout();
},
'notify::minimized', this._updateVisible.bind(this),
this);
global.display.connectObject('notify::focus-window',
this._onFocusChanged.bind(this), this);
this._onFocusChanged();
}
// needed for DND
get metaWindow() {
return this._window;
}
_onFocusChanged() {
if (global.display.focus_window === this._window)
this.add_style_class_name('active');
else
this.remove_style_class_name('active');
}
_updateVisible() {
const monitor = Main.layoutManager.findIndexForActor(this);
const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
this.visible = this._window.get_frame_rect().overlap(workArea) &&
this._window.window_type !== Meta.WindowType.DESKTOP &&
this._window.showing_on_its_workspace();
}
}
class WorkspaceLayout extends Clutter.LayoutManager {
static {
GObject.registerClass(this);
}
vfunc_get_preferred_width() {
return [0, 0];
}
vfunc_get_preferred_height() {
return [0, 0];
}
vfunc_allocate(container, box) {
const monitor = Main.layoutManager.findIndexForActor(container);
const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
const hscale = box.get_width() / workArea.width;
const vscale = box.get_height() / workArea.height;
for (const child of container) {
const childBox = new Clutter.ActorBox();
const frameRect = child.metaWindow.get_frame_rect();
childBox.set_size(
Math.round(Math.min(frameRect.width, workArea.width) * hscale),
Math.round(Math.min(frameRect.height, workArea.height) * vscale));
childBox.set_origin(
Math.round((frameRect.x - workArea.x) * hscale),
Math.round((frameRect.y - workArea.y) * vscale));
child.allocate(childBox);
}
}
}
class WorkspaceThumbnail extends St.Button {
static {
GObject.registerClass(this);
}
constructor(index) {
super({
style_class: 'workspace',
child: new Clutter.Actor({
layout_manager: new WorkspaceLayout(),
clip_to_allocation: true,
}),
});
this._tooltip = new St.Label({
style_class: 'dash-label',
visible: false,
});
Main.uiGroup.add_child(this._tooltip);
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::hover', this._syncTooltip.bind(this));
this._index = index;
this._delegate = this; // needed for DND
this._windowPreviews = new Map();
let workspaceManager = global.workspace_manager;
this._workspace = workspaceManager.get_workspace_by_index(index);
this._workspace.connectObject(
'window-added', (ws, window) => this._addWindow(window),
'window-removed', (ws, window) => this._removeWindow(window),
this);
global.display.connectObject('restacked',
this._onRestacked.bind(this), this);
this._workspace.list_windows().forEach(w => this._addWindow(w));
this._onRestacked();
}
acceptDrop(source) {
if (!source.metaWindow)
return false;
this._moveWindow(source.metaWindow);
return true;
}
handleDragOver(source) {
if (source.metaWindow)
return DND.DragMotionResult.MOVE_DROP;
else
return DND.DragMotionResult.CONTINUE;
}
_addWindow(window) {
if (this._windowPreviews.has(window))
return;
let preview = new WindowPreview(window);
preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
this._windowPreviews.set(window, preview);
this.child.add_child(preview);
}
_removeWindow(window) {
let preview = this._windowPreviews.get(window);
if (!preview)
return;
this._windowPreviews.delete(window);
preview.destroy();
}
_onRestacked() {
let lastPreview = null;
let windows = global.get_window_actors().map(a => a.meta_window);
for (let i = 0; i < windows.length; i++) {
let preview = this._windowPreviews.get(windows[i]);
if (!preview)
continue;
this.child.set_child_above_sibling(preview, lastPreview);
lastPreview = preview;
}
}
_moveWindow(window) {
let monitorIndex = Main.layoutManager.findIndexForActor(this);
if (monitorIndex !== window.get_monitor())
window.move_to_monitor(monitorIndex);
window.change_workspace_by_index(this._index, false);
}
on_clicked() {
let ws = global.workspace_manager.get_workspace_by_index(this._index);
if (ws)
ws.activate(global.get_current_time());
}
_syncTooltip() {
if (this.hover) {
this._tooltip.set({
text: Meta.prefs_get_workspace_name(this._index),
visible: true,
opacity: 0,
});
const [stageX, stageY] = this.get_transformed_position();
const thumbWidth = this.allocation.get_width();
const thumbHeight = this.allocation.get_height();
const tipWidth = this._tooltip.width;
const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
const monitor = Main.layoutManager.findMonitorForActor(this);
const x = Math.clamp(
stageX + xOffset,
monitor.x,
monitor.x + monitor.width - tipWidth);
const y = stageY + thumbHeight + TOOLTIP_OFFSET;
this._tooltip.set_position(x, y);
}
this._tooltip.ease({
opacity: this.hover ? 255 : 0,
duration: TOOLTIP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this._tooltip.visible = this.hover),
});
}
_onDestroy() {
this._tooltip.destroy();
}
}
class WorkspaceIndicator extends PanelMenu.Button {
static {
GObject.registerClass(this);
}
constructor() {
super(0.5, _('Workspace Indicator'));
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
});
this.add_actor(container);
let workspaceManager = global.workspace_manager;
this._currentWorkspace = workspaceManager.get_active_workspace_index();
this._statusLabel = new St.Label({
style_class: 'panel-workspace-indicator',
y_align: Clutter.ActorAlign.CENTER,
text: this._labelText(),
});
container.add_actor(this._statusLabel);
this._thumbnailsBox = new St.BoxLayout({
style_class: 'panel-workspace-indicator-box',
y_expand: true,
reactive: true,
});
container.add_actor(this._thumbnailsBox);
this._workspacesItems = [];
this._workspaceSection = new PopupMenu.PopupMenuSection();
this.menu.addMenuItem(this._workspaceSection);
workspaceManager.connectObject(
'notify::n-workspaces', this._nWorkspacesChanged.bind(this), GObject.ConnectFlags.AFTER,
'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
'notify::layout-rows', this._updateThumbnailVisibility.bind(this),
this);
this.connect('scroll-event', this._onScrollEvent.bind(this));
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
this._createWorkspacesSection();
this._updateThumbnails();
this._updateThumbnailVisibility();
this._settings = new Gio.Settings({schema_id: WORKSPACE_SCHEMA});
this._settings.connectObject(`changed::${WORKSPACE_KEY}`,
this._updateMenuLabels.bind(this), this);
}
_onDestroy() {
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
super._onDestroy();
}
_updateThumbnailVisibility() {
const {workspaceManager} = global;
const vertical = workspaceManager.layout_rows === -1;
const useMenu =
vertical || workspaceManager.n_workspaces > MAX_THUMBNAILS;
this.reactive = useMenu;
this._statusLabel.visible = useMenu;
this._thumbnailsBox.visible = !useMenu;
// Disable offscreen-redirect when showing the workspace switcher
// so that clip-to-allocation works
Main.panel.set_offscreen_redirect(useMenu
? Clutter.OffscreenRedirect.ALWAYS
: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
}
_onWorkspaceSwitched() {
this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
this._updateMenuOrnament();
this._updateActiveThumbnail();
this._statusLabel.set_text(this._labelText());
}
_nWorkspacesChanged() {
this._createWorkspacesSection();
this._updateThumbnails();
this._updateThumbnailVisibility();
}
_updateMenuOrnament() {
for (let i = 0; i < this._workspacesItems.length; i++) {
this._workspacesItems[i].setOrnament(i === this._currentWorkspace
? PopupMenu.Ornament.DOT
: PopupMenu.Ornament.NONE);
}
}
_updateActiveThumbnail() {
let thumbs = this._thumbnailsBox.get_children();
for (let i = 0; i < thumbs.length; i++) {
if (i === this._currentWorkspace)
thumbs[i].add_style_class_name('active');
else
thumbs[i].remove_style_class_name('active');
}
}
_labelText(workspaceIndex) {
if (workspaceIndex === undefined) {
workspaceIndex = this._currentWorkspace;
return (workspaceIndex + 1).toString();
}
return Meta.prefs_get_workspace_name(workspaceIndex);
}
_updateMenuLabels() {
for (let i = 0; i < this._workspacesItems.length; i++)
this._workspacesItems[i].label.text = this._labelText(i);
}
_createWorkspacesSection() {
let workspaceManager = global.workspace_manager;
this._workspaceSection.removeAll();
this._workspacesItems = [];
this._currentWorkspace = workspaceManager.get_active_workspace_index();
let i = 0;
for (; i < workspaceManager.n_workspaces; i++) {
this._workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
this._workspaceSection.addMenuItem(this._workspacesItems[i]);
this._workspacesItems[i].workspaceId = i;
this._workspacesItems[i].label_actor = this._statusLabel;
this._workspacesItems[i].connect('activate', (actor, _event) => {
this._activate(actor.workspaceId);
});
if (i === this._currentWorkspace)
this._workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT);
}
this._statusLabel.set_text(this._labelText());
}
_updateThumbnails() {
let workspaceManager = global.workspace_manager;
this._thumbnailsBox.destroy_all_children();
for (let i = 0; i < workspaceManager.n_workspaces; i++) {
let thumb = new WorkspaceThumbnail(i);
this._thumbnailsBox.add_actor(thumb);
}
this._updateActiveThumbnail();
}
_activate(index) {
let workspaceManager = global.workspace_manager;
if (index >= 0 && index < workspaceManager.n_workspaces) {
let metaWorkspace = workspaceManager.get_workspace_by_index(index);
metaWorkspace.activate(global.get_current_time());
}
}
_onScrollEvent(actor, event) {
let direction = event.get_scroll_direction();
let diff = 0;
if (direction === Clutter.ScrollDirection.DOWN)
diff = 1;
else if (direction === Clutter.ScrollDirection.UP)
diff = -1;
else
return;
let newIndex = global.workspace_manager.get_active_workspace_index() + diff;
this._activate(newIndex);
}
}
import {WorkspaceIndicator} from './workspaceIndicator.js';
export default class WorkspaceIndicatorExtension extends Extension {
enable() {
this._indicator = new WorkspaceIndicator();
this._indicator = new WorkspaceIndicator({
settings: this.getSettings(),
});
Main.panel.addToStatusArea('workspace-indicator', this._indicator);
}

View File

@@ -1,8 +1,16 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
extension_data += configure_file(
input: metadata_name + '.in',
output: metadata_name,
configuration: metadata_conf
)
extension_data += files('stylesheet.css')
extension_data += files(
'stylesheet-dark.css',
'stylesheet-light.css',
)
extension_schemas += files('schemas/' + metadata_conf.get('gschemaname') + '.gschema.xml')
extension_sources += files('prefs.js')
extension_sources += files('prefs.js', 'workspaceIndicator.js')

View File

@@ -1,4 +1,8 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// SPDX-FileCopyrightText: 2012 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
@@ -13,6 +17,25 @@ const N_ = e => e;
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';
class GeneralGroup extends Adw.PreferencesGroup {
static {
GObject.registerClass(this);
}
constructor(settings) {
super();
const row = new Adw.SwitchRow({
title: _('Show Previews In Top Bar'),
});
this.add(row);
settings.bind('embed-previews',
row, 'active',
Gio.SettingsBindFlags.DEFAULT);
}
}
class NewItem extends GObject.Object {}
GObject.registerClass(NewItem);
@@ -114,7 +137,7 @@ class WorkspacesList extends GObject.Object {
}
}
class WorkspaceSettingsWidget extends Adw.PreferencesGroup {
class WorkspacesGroup extends Adw.PreferencesGroup {
static {
GObject.registerClass(this);
@@ -260,6 +283,9 @@ class NewWorkspaceRow extends Adw.PreferencesRow {
export default class WorkspaceIndicatorPrefs extends ExtensionPreferences {
getPreferencesWidget() {
return new WorkspaceSettingsWidget();
const page = new Adw.PreferencesPage();
page.add(new GeneralGroup(this.getSettings()));
page.add(new WorkspacesGroup());
return page;
}
}

View File

@@ -0,0 +1,15 @@
<!--
SPDX-FileCopyrightText: 2024 Florian Müllner <fmuellner@gnome.org>
SPDX-License-Identifier: GPL-2.0-or-later
-->
<schemalist gettext-domain="gnome-shell-extensions">
<schema id="org.gnome.shell.extensions.workspace-indicator"
path="/org/gnome/shell/extensions/workspace-indicator/">
<key name="embed-previews" type="b">
<default>true</default>
<summary>Show workspace previews in top bar</summary>
</key>
</schema>
</schemalist>

View File

@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2011 Erick Pérez Castellanos <erick.red@gmail.com>
* SPDX-FileCopyrightText: 2019 Florian Müllner <fmuellner@gnome.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.workspace-indicator .status-label {
padding: 0 8px;
}
.workspace-indicator .workspaces-view.hfade {
-st-hfade-offset: 20px;
}
.workspace-indicator-menu .workspaces-view {
max-width: 480px;
}
.workspace-indicator .workspaces-box {
spacing: 3px;
}
.workspace-indicator-menu .workspaces-box {
padding: 5px;
spacing: 6px;
}
.workspace-indicator .workspace-box {
padding-top: 5px;
padding-bottom: 5px;
}
.workspace-indicator StButton:first-child:ltr > .workspace-box,
.workspace-indicator StButton:last-child:rtl > .workspace-box {
padding-left: 5px;
}
.workspace-indicator StButton:last-child:ltr > .workspace-box,
.workspace-indicator StButton:first-child:rtl > .workspace-box {
padding-right: 5px;
}
.workspace-indicator-menu .workspace-box {
spacing: 6px;
}
.workspace-indicator-menu .workspace,
.workspace-indicator .workspace {
border: 1px solid transparent;
border-radius: 4px;
background-color: #3f3f3f;
}
.workspace-indicator .workspace {
width: 52px;
}
.workspace-indicator-menu .workspace {
height: 80px;
width: 160px;
}
.workspace-indicator-menu .workspace.active,
.workspace-indicator .workspace.active {
border-color: #fff;
}
.workspace-indicator-window-preview {
background-color: #bebebe;
border: 1px solid #828282;
border-radius: 1px;
}
.workspace-indicator-window-preview.active {
background-color: #d4d4d4;
}

View File

@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
* SPDX-FileCopyrightText: 2015 Jakub Steiner <jimmac@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@import url("stylesheet-dark.css");
.workspace-indicator .workspace {
background-color: #ccc;
}
.workspace-indicator .workspace.active {
border-color: #888;
}
.workspace-indicator-window-preview {
background-color: #ededed;
border: 1px solid #ccc;
}
.workspace-indicator-window-preview.active {
background-color: #f6f5f4;
}

View File

@@ -1,28 +0,0 @@
.panel-workspace-indicator {
padding: 0 8px;
}
.panel-workspace-indicator-box {
padding: 4px 0;
spacing: 4px;
}
.panel-workspace-indicator-box .workspace {
width: 40px;
border: 2px solid #000;
border-radius: 2px;
background-color: #595959;
}
.panel-workspace-indicator-box .workspace.active {
border-color: #fff;
}
.workspace-indicator-window-preview {
background-color: #bebebe;
border: 1px solid #828282;
}
.workspace-indicator-window-preview.active {
background-color: #d4d4d4;
}

View File

@@ -0,0 +1,537 @@
// SPDX-FileCopyrightText: 2011 Erick Pérez Castellanos <erick.red@gmail.com>
// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
// SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
//
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Meta from 'gi://Meta';
import St from 'gi://St';
import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
const SCROLL_TIME = 100;
let baseStyleClassName = '';
class WindowPreview extends St.Button {
static {
GObject.registerClass(this);
}
constructor(window) {
super({
style_class: `${baseStyleClassName}-window-preview`,
});
this._delegate = this;
DND.makeDraggable(this, {restoreOnSuccess: true});
this._window = window;
this._window.connectObject(
'size-changed', () => this._checkRelayout(),
'position-changed', () => this._checkRelayout(),
'notify::minimized', this._updateVisible.bind(this),
'notify::skip-taskbar', this._updateVisible.bind(this),
this);
this._updateVisible();
global.display.connectObject('notify::focus-window',
this._onFocusChanged.bind(this), this);
this._onFocusChanged();
}
// needed for DND
get metaWindow() {
return this._window;
}
_onFocusChanged() {
if (global.display.focus_window === this._window)
this.add_style_class_name('active');
else
this.remove_style_class_name('active');
}
_checkRelayout() {
const monitor = Main.layoutManager.findIndexForActor(this);
const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
if (this._window.get_frame_rect().overlap(workArea))
this.queue_relayout();
}
_updateVisible() {
this.visible = !this._window.skip_taskbar &&
this._window.showing_on_its_workspace();
}
}
class WorkspaceLayout extends Clutter.LayoutManager {
static {
GObject.registerClass(this);
}
vfunc_get_preferred_width() {
return [0, 0];
}
vfunc_get_preferred_height() {
return [0, 0];
}
vfunc_allocate(container, box) {
const monitor = Main.layoutManager.findIndexForActor(container);
const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
const hscale = box.get_width() / workArea.width;
const vscale = box.get_height() / workArea.height;
for (const child of container) {
const childBox = new Clutter.ActorBox();
const frameRect = child.metaWindow.get_frame_rect();
childBox.set_size(
Math.round(Math.min(frameRect.width, workArea.width) * hscale),
Math.round(Math.min(frameRect.height, workArea.height) * vscale));
childBox.set_origin(
Math.round((frameRect.x - workArea.x) * hscale),
Math.round((frameRect.y - workArea.y) * vscale));
child.allocate(childBox);
}
}
}
class WorkspaceThumbnail extends St.Button {
static [GObject.properties] = {
'active': GObject.ParamSpec.boolean(
'active', null, null,
GObject.ParamFlags.READWRITE,
false),
'show-label': GObject.ParamSpec.boolean(
'show-label', null, null,
GObject.ParamFlags.READWRITE,
false),
};
static {
GObject.registerClass(this);
}
constructor(index) {
super();
const box = new St.BoxLayout({
style_class: 'workspace-box',
y_expand: true,
vertical: true,
});
this.set_child(box);
this._preview = new St.Bin({
style_class: 'workspace',
child: new Clutter.Actor({
layout_manager: new WorkspaceLayout(),
clip_to_allocation: true,
x_expand: true,
y_expand: true,
}),
y_expand: true,
});
box.add_child(this._preview);
this._label = new St.Label({
x_align: Clutter.ActorAlign.CENTER,
text: Meta.prefs_get_workspace_name(index),
});
box.add_child(this._label);
this._tooltip = new St.Label({
style_class: 'dash-label',
visible: false,
});
Main.uiGroup.add_child(this._tooltip);
this.bind_property('show-label',
this._label, 'visible',
GObject.BindingFlags.SYNC_CREATE);
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::hover', this._syncTooltip.bind(this));
const desktopSettings =
new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
desktopSettings.connectObject('changed::workspace-names', () => {
this._label.text = Meta.prefs_get_workspace_name(index);
}, this);
this._index = index;
this._delegate = this; // needed for DND
this._windowPreviews = new Map();
let workspaceManager = global.workspace_manager;
this._workspace = workspaceManager.get_workspace_by_index(index);
this._workspace.bind_property('active',
this, 'active',
GObject.BindingFlags.SYNC_CREATE);
this._workspace.connectObject(
'window-added', (ws, window) => this._addWindow(window),
'window-removed', (ws, window) => this._removeWindow(window),
this);
global.display.connectObject('restacked',
this._onRestacked.bind(this), this);
this._workspace.list_windows().forEach(w => this._addWindow(w));
this._onRestacked();
}
get active() {
return this._preview.has_style_class_name('active');
}
set active(active) {
if (active)
this._preview.add_style_class_name('active');
else
this._preview.remove_style_class_name('active');
this.notify('active');
}
acceptDrop(source) {
if (!source.metaWindow)
return false;
this._moveWindow(source.metaWindow);
return true;
}
handleDragOver(source) {
if (source.metaWindow)
return DND.DragMotionResult.MOVE_DROP;
else
return DND.DragMotionResult.CONTINUE;
}
_addWindow(window) {
if (this._windowPreviews.has(window))
return;
let preview = new WindowPreview(window);
preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
this._windowPreviews.set(window, preview);
this._preview.child.add_child(preview);
}
_removeWindow(window) {
let preview = this._windowPreviews.get(window);
if (!preview)
return;
this._windowPreviews.delete(window);
preview.destroy();
}
_onRestacked() {
let lastPreview = null;
let windows = global.get_window_actors().map(a => a.meta_window);
for (let i = 0; i < windows.length; i++) {
let preview = this._windowPreviews.get(windows[i]);
if (!preview)
continue;
this._preview.child.set_child_above_sibling(preview, lastPreview);
lastPreview = preview;
}
}
_moveWindow(window) {
let monitorIndex = Main.layoutManager.findIndexForActor(this);
if (monitorIndex !== window.get_monitor())
window.move_to_monitor(monitorIndex);
window.change_workspace_by_index(this._index, false);
}
on_clicked() {
let ws = global.workspace_manager.get_workspace_by_index(this._index);
if (ws)
ws.activate(global.get_current_time());
}
_syncTooltip() {
if (this.showLabel)
return;
if (this.hover) {
this._tooltip.set({
text: Meta.prefs_get_workspace_name(this._index),
visible: true,
opacity: 0,
});
const [stageX, stageY] = this.get_transformed_position();
const [thumbWidth, thumbHeight] = this.allocation.get_size();
const [tipWidth, tipHeight] = this._tooltip.get_size();
const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
const monitor = Main.layoutManager.findMonitorForActor(this);
const x = Math.clamp(
stageX + xOffset,
monitor.x,
monitor.x + monitor.width - tipWidth);
const y = stageY - monitor.y > thumbHeight + TOOLTIP_OFFSET
? stageY - tipHeight - TOOLTIP_OFFSET // show above
: stageY + thumbHeight + TOOLTIP_OFFSET; // show below
this._tooltip.set_position(x, y);
}
this._tooltip.ease({
opacity: this.hover ? 255 : 0,
duration: TOOLTIP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this._tooltip.visible = this.hover),
});
}
_onDestroy() {
this._tooltip.destroy();
}
}
class WorkspacePreviews extends Clutter.Actor {
static [GObject.properties] = {
'show-labels': GObject.ParamSpec.boolean(
'show-labels', null, null,
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
};
static {
GObject.registerClass(this);
}
constructor(params) {
super({
...params,
layout_manager: new Clutter.BinLayout(),
reactive: true,
y_expand: true,
});
this.connect('scroll-event',
(a, event) => Main.wm.handleWorkspaceScroll(event));
const {workspaceManager} = global;
workspaceManager.connectObject(
'notify::n-workspaces', () => this._updateThumbnails(), GObject.ConnectFlags.AFTER,
'workspace-switched', () => this._updateScrollPosition(),
this);
this.connect('notify::mapped', () => {
if (this.mapped)
this._updateScrollPosition();
});
this._thumbnailsBox = new St.BoxLayout({
style_class: 'workspaces-box',
y_expand: true,
});
this._scrollView = new St.ScrollView({
style_class: 'workspaces-view hfade',
enable_mouse_scrolling: false,
hscrollbar_policy: St.PolicyType.EXTERNAL,
vscrollbar_policy: St.PolicyType.NEVER,
y_expand: true,
child: this._thumbnailsBox,
});
this.add_child(this._scrollView);
this._updateThumbnails();
}
_updateThumbnails() {
const {nWorkspaces} = global.workspace_manager;
this._thumbnailsBox.destroy_all_children();
for (let i = 0; i < nWorkspaces; i++) {
const thumb = new WorkspaceThumbnail(i);
this.bind_property('show-labels',
thumb, 'show-label',
GObject.BindingFlags.SYNC_CREATE);
this._thumbnailsBox.add_child(thumb);
}
if (this.mapped)
this._updateScrollPosition();
}
_updateScrollPosition() {
const adjustment = this._scrollView.hadjustment;
const {upper, pageSize} = adjustment;
let {value} = adjustment;
const activeWorkspace =
[...this._thumbnailsBox].find(a => a.active);
if (!activeWorkspace)
return;
let offset = 0;
const hfade = this._scrollView.get_effect('fade');
if (hfade)
offset = hfade.fade_margins.left;
let {x1, x2} = activeWorkspace.get_allocation_box();
let parent = activeWorkspace.get_parent();
while (parent !== this._scrollView) {
if (!parent)
throw new Error('actor not in scroll view');
const box = parent.get_allocation_box();
x1 += box.x1;
x2 += box.x1;
parent = parent.get_parent();
}
if (x1 < value + offset)
value = Math.max(0, x1 - offset);
else if (x2 > value + pageSize - offset)
value = Math.min(upper, x2 + offset - pageSize);
else
return;
adjustment.ease(value, {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: SCROLL_TIME,
});
}
}
export class WorkspaceIndicator extends PanelMenu.Button {
static {
GObject.registerClass(this);
}
constructor(params = {}) {
super(0.5, _('Workspace Indicator'), true);
const {
baseStyleClass = 'workspace-indicator',
settings,
} = params;
this._settings = settings;
baseStyleClassName = baseStyleClass;
this.add_style_class_name(baseStyleClassName);
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
});
this.add_child(container);
let workspaceManager = global.workspace_manager;
this._currentWorkspace = workspaceManager.get_active_workspace_index();
this._statusLabel = new St.Label({
style_class: 'status-label',
y_align: Clutter.ActorAlign.CENTER,
text: this._getStatusText(),
});
container.add_child(this._statusLabel);
this._thumbnails = new WorkspacePreviews();
container.add_child(this._thumbnails);
this._workspacesItems = [];
workspaceManager.connectObject(
'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
this);
this.connect('scroll-event',
(a, event) => Main.wm.handleWorkspaceScroll(event));
this._inTopBar = false;
this.connect('notify::realized', () => {
if (!this.realized)
return;
this._inTopBar = Main.panel.contains(this);
this._updateTopBarRedirect();
});
this._settings.connect('changed::embed-previews',
() => this._updateThumbnailVisibility());
this._updateThumbnailVisibility();
}
_onDestroy() {
if (this._inTopBar)
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._inTopBar = false;
super._onDestroy();
}
_updateThumbnailVisibility() {
const useMenu = !this._settings.get_boolean('embed-previews');
this.reactive = useMenu;
this._statusLabel.visible = useMenu;
this._thumbnails.visible = !useMenu;
this.setMenu(useMenu
? this._createPreviewMenu()
: null);
this._updateTopBarRedirect();
}
_updateTopBarRedirect() {
if (!this._inTopBar)
return;
// Disable offscreen-redirect when showing the workspace switcher
// so that clip-to-allocation works
Main.panel.set_offscreen_redirect(this._thumbnails.visible
? Clutter.OffscreenRedirect.ALWAYS
: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
}
_onWorkspaceSwitched() {
this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
this._statusLabel.set_text(this._getStatusText());
}
_getStatusText() {
const {nWorkspaces} = global.workspace_manager;
const current = this._currentWorkspace + 1;
return `${current} / ${nWorkspaces}`;
}
_createPreviewMenu() {
const menu = new PopupMenu.PopupMenu(this, 0.5, St.Side.TOP);
const previews = new WorkspacePreviews({show_labels: true});
menu.box.add_child(previews);
menu.actor.add_style_class_name(`${baseStyleClassName}-menu`);
return menu;
}
}

View File

@@ -1,3 +1,8 @@
<!--
SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
SPDX-License-Identifier: CC0-1.0
-->
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
@@ -13,20 +18,13 @@ Most extensions can be installed by configuring --prefix=$HOME/.local,
and will be picked automatically at next login.
</description>
<homepage rdf:resource="https://wiki.gnome.org/Projects/GnomeShell/Extensions" />
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnome-shell-list" />
<download-page rdf:resource="http://download.gnome.org/sources/gnome-shell-extensions/" />
<support-forum rdf:resource="https://discourse.gnome.org/tag/shell" />
<download-page rdf:resource="https://download.gnome.org/sources/gnome-shell-extensions/" />
<bug-database rdf:resource="https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues" />
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
<programming-language>JavaScript</programming-language>
<maintainer>
<foaf:Person>
<foaf:name>Giovanni Campagna</foaf:name>
<foaf:mbox rdf:resource="mailto:gcampagna@src.gnome.org" />
<gnome:userid>gcampagna</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Florian Müllner</foaf:name>
@@ -34,10 +32,4 @@ and will be picked automatically at next login.
<gnome:userid>fmuellner</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Marge Bot</foaf:name>
<gnome:userid>marge-bot</gnome:userid>
</foaf:Person>
</maintainer>
</Project>

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2019 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
rules:
camelcase:
- error
@@ -8,6 +12,12 @@ rules:
- error
- smart
prefer-arrow-callback: error
jsdoc/require-param-description: off
jsdoc/require-jsdoc:
- error
- exemptEmptyFunctions: true
publicOnly:
esm: true
globals:
global: readonly
parserOptions:

View File

@@ -1,7 +1,12 @@
project('gnome-shell-extensions',
version: '45.beta',
meson_version: '>= 0.58.0',
license: 'GPL2+'
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>>
#
# SPDX-License-Identifier: GPL-2.0-or-later
project(
'gnome-shell-extensions',
version: '47.5',
meson_version: '>= 1.1.0',
license: 'GPL-2.0-or-later',
)
gettext_domain = meson.project_name()
@@ -26,11 +31,13 @@ shell_version = ver_arr[0]
uuid_suffix = '@gnome-shell-extensions.gcampax.github.com'
have_x11 = get_option('x11')
classic_extensions = [
'apps-menu',
'places-menu',
'launch-new-instance',
'window-list'
'window-list',
]
default_extensions = classic_extensions
@@ -38,16 +45,14 @@ default_extensions += [
'drive-menu',
'light-style',
'screenshot-window-sizer',
'status-icons',
'system-monitor',
'windowsNavigator',
'workspace-indicator'
'workspace-indicator',
]
all_extensions = default_extensions
all_extensions += [
'auto-move-windows',
'native-window-placement',
'user-theme'
]
all_extensions += ['auto-move-windows', 'native-window-placement', 'user-theme']
enabled_extensions = get_option('enable_extensions')
@@ -66,11 +71,10 @@ endif
classic_mode_enabled = get_option('classic_mode')
if classic_mode_enabled
# Sanity check: Make sure all classic extensions are enabled
# Sanity check: Make sure all classic extensions are enabled
foreach e : classic_extensions
if not enabled_extensions.contains(e)
error('Classic mode is enabled, ' +
'but the required extension @0@ is not.'.format(e))
error(f'Classic mode is enabled, but the required extension @e@ is not')
endif
endforeach
endif
@@ -78,32 +82,30 @@ endif
# Sanity check: Make sure enabled extensions are valid
foreach e : enabled_extensions
if not all_extensions.contains(e)
error('Invalid extension @0@.'.format(e))
error(f'Invalid extension @e@.')
endif
endforeach
if classic_mode_enabled
subdir('data')
meson.add_install_script(
'meson/session-post-install.py',
join_paths(get_option('prefix'), datadir)
)
if have_x11
meson.add_install_script(
'meson/session-post-install.py',
join_paths(get_option('prefix'), datadir),
)
endif
endif
subdir('extensions')
subdir('po')
gnome.post_install(
glib_compile_schemas: true,
)
gnome.post_install(glib_compile_schemas: true)
meson.add_dist_script('meson/check-version.py',
meson.project_version(),
'NEWS')
meson.add_dist_script('meson/check-version.py', meson.project_version(), 'NEWS')
summary_options = {
'extensions': enabled_extensions,
'classic_mode': get_option('classic_mode'),
'extensions': enabled_extensions,
'classic_mode': get_option('classic_mode'),
}
summary_dirs = {

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
option('extension_set',
type: 'combo',
choices: ['classic', 'default', 'all'],
@@ -16,3 +20,9 @@ option('classic_mode',
value: false,
description: 'Enable installing data files for classic mode.'
)
option('x11',
type: 'boolean',
value: true,
description: 'Enable X11 session support.'
)

View File

@@ -1,8 +1,13 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2021 Florian Müllner <fmuellner@gnome.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os, sys
from pathlib import Path
import argparse, subprocess
from xml.etree.ElementTree import ElementTree
import argparse
def check_version(version, file, type='news'):
if type == 'news':
@@ -12,8 +17,11 @@ def check_version(version, file, type='news'):
if not ok:
raise Exception("{} does not start with {}".format(file, version))
elif type == 'metainfo':
subprocess.run(['appstream-util', 'validate-version', file, version],
check=True)
query = './releases/release[@version="{}"]'.format(version)
ok = ElementTree(file=file).find(query) is not None
print("{}: {}".format(file, "OK" if ok else "FAILED"))
if not ok:
raise Exception("{} does not contain release {}".format(file, version))
else:
raise Exception('Not implemented')

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2021 Neal Gompa <ngompa@fedoraproject.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import shutil
import sys
@@ -11,10 +15,10 @@ else:
# FIXME: Meson is unable to copy a generated target file:
# https://groups.google.com/forum/#!topic/mesonbuild/3iIoYPrN4P0
dst_dir = os.path.join(install_root, 'wayland-sessions')
dst_dir = os.path.join(install_root, 'xsessions')
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
src = os.path.join(install_root, 'xsessions', 'gnome-classic.desktop')
src = os.path.join(install_root, 'wayland-sessions', 'gnome-classic.desktop')
dst = os.path.join(dst_dir, 'gnome-classic.desktop')
shutil.copyfile(src, dst)

View File

@@ -11,11 +11,13 @@ extensions/native-window-placement/org.gnome.shell.extensions.native-window-plac
extensions/places-menu/extension.js
extensions/places-menu/placeDisplay.js
extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml
extensions/system-monitor/extension.js
extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml
extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml
extensions/window-list/extension.js
extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
extensions/window-list/prefs.js
extensions/window-list/workspaceIndicator.js
extensions/windowsNavigator/extension.js
extensions/workspace-indicator/extension.js
extensions/workspace-indicator/prefs.js
extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
extensions/workspace-indicator/workspaceIndicator.js

206
po/be.po
View File

@@ -8,17 +8,17 @@ msgstr ""
"Project-Id-Version: gnome-shell-extensions master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
"issues\n"
"POT-Creation-Date: 2022-07-10 12:54+0000\n"
"PO-Revision-Date: 2022-10-19 15:20+0300\n"
"Last-Translator: Launchpad translators\n"
"POT-Creation-Date: 2024-04-29 15:27+0000\n"
"PO-Revision-Date: 2024-08-23 16:00+0300\n"
"Last-Translator: Yuras Shumovich <shumovichy@gmail.com>\n"
"Language-Team: Belarusian <i18n-bel-gnome@googlegroups.com>\n"
"Language: be\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 3.0\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 3.4.4\n"
#: data/gnome-classic.desktop.in:3
msgid "GNOME Classic"
@@ -37,19 +37,19 @@ msgstr "Класічны GNOME на Wayland"
msgid "GNOME Classic on Xorg"
msgstr "Класічны GNOME на Xorg"
#: extensions/apps-menu/extension.js:118
#: extensions/apps-menu/extension.js:126
msgid "Favorites"
msgstr "Абраныя"
#: extensions/apps-menu/extension.js:379
msgid "Applications"
#: extensions/apps-menu/extension.js:400
msgid "Apps"
msgstr "Праграмы"
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:6
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:12
msgid "Application and workspace list"
msgstr "Праграма і спіс працоўных прастор"
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:7
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:13
msgid ""
"A list of strings, each containing an application id (desktop file name), "
"followed by a colon and the workspace number"
@@ -57,99 +57,171 @@ msgstr ""
"Спіс радкоў, кожны з якіх змяшчае ідэнтыфікатар праграмы (імя файла *."
"desktop), затым двукроп'е і нумар працоўнай прасторы"
#: extensions/auto-move-windows/prefs.js:152
#: extensions/auto-move-windows/prefs.js:159
msgid "Workspace Rules"
msgstr "Правілы для працоўнай прасторы"
#: extensions/auto-move-windows/prefs.js:306
#: extensions/auto-move-windows/prefs.js:314
msgid "Add Rule"
msgstr "Дадаць правіла"
#. TRANSLATORS: %s is the filesystem name
#: extensions/drive-menu/extension.js:126
#: extensions/places-menu/placeDisplay.js:210
#: extensions/drive-menu/extension.js:123
#: extensions/places-menu/placeDisplay.js:218
#, javascript-format
msgid "Ejecting drive “%s” failed:"
msgstr "Не ўдалося выняць дыск «%s»:"
#: extensions/drive-menu/extension.js:145
#: extensions/drive-menu/extension.js:142
msgid "Removable devices"
msgstr "Здымныя прылады"
#: extensions/drive-menu/extension.js:167
#: extensions/drive-menu/extension.js:164
msgid "Open Files"
msgstr "Адкрыць файлы"
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:5
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:11
msgid "Use more screen for windows"
msgstr "Выкарыстоўваць большую плошчу экрана для вокнаў"
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:6
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:12
msgid ""
"Try to use more screen for placing window thumbnails by adapting to screen "
"aspect ratio, and consolidating them further to reduce the bounding box. "
"This setting applies only with the natural placement strategy."
msgstr ""
"Спрабаваць выкарыстаць большую плошчу экрана для размяшчэння мініяцюр праз "
"змяненне суадносін бакоў экрана, ўшчыльняючы іх, каб зменшыць памеры "
"змяненне суадносін бакоў экрана, ушчыльняючы іх, каб зменшыць памеры "
"абмежавальнай рамкі. Гэты параметр ужываецца толькі з натуральным "
"размяшчэннем мініяцюр."
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:11
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:17
msgid "Place window captions on top"
msgstr "Размяшчаць подпіс акна зверху"
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:12
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:18
msgid ""
"If true, place window captions on top the respective thumbnail, overriding "
"shell default of placing it at the bottom. Changing this setting requires "
"restarting the shell to have any effect."
msgstr ""
"Калі выбрана, подпіс акна будзе над мініяцюрай, а не пад ей (як "
"Калі выбрана, подпіс акна будзе над мініяцюрай, а не пад ёй (як "
"перадвызначана). Каб змена налады ўступіла ў сілу, трэба перазапусціць "
"абалонку."
#: extensions/places-menu/extension.js:91
#: extensions/places-menu/extension.js:94
#: extensions/places-menu/extension.js:97
msgid "Places"
msgstr "Месцы"
#: extensions/places-menu/placeDisplay.js:49
#: extensions/places-menu/placeDisplay.js:60
#, javascript-format
msgid "Failed to launch “%s”"
msgstr "Не ўдалося запусціць «%s»"
#: extensions/places-menu/placeDisplay.js:64
#: extensions/places-menu/placeDisplay.js:75
#, javascript-format
msgid "Failed to mount volume for “%s”"
msgstr "Не ўдалося прымацаваць том для «%s»."
#: extensions/places-menu/placeDisplay.js:125
#: extensions/places-menu/placeDisplay.js:148
#: extensions/places-menu/placeDisplay.js:135
#: extensions/places-menu/placeDisplay.js:158
msgid "Computer"
msgstr "Камп'ютар"
#: extensions/places-menu/placeDisplay.js:336
#: extensions/places-menu/placeDisplay.js:333
msgid "Home"
msgstr "Хатняя папка"
#: extensions/places-menu/placeDisplay.js:381
#: extensions/places-menu/placeDisplay.js:378
msgid "Browse Network"
msgstr "Агляд сеткі"
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:7
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:14
msgid "Cycle Screenshot Sizes"
msgstr "Паслядоўнасць змены памераў для здымка экрана"
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:11
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:18
msgid "Cycle Screenshot Sizes Backward"
msgstr "Адваротная паслядоўнасць змены памераў для здымка экрана"
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:5
#: extensions/system-monitor/extension.js:135
msgid "CPU stats"
msgstr "Статыстыка выкарыстання працэсара"
#: extensions/system-monitor/extension.js:159
msgid "Memory stats"
msgstr "Статыстыка выкарыстання памяці"
#: extensions/system-monitor/extension.js:177
msgid "Swap stats"
msgstr "Статыстыка выкарыстання своп"
#: extensions/system-monitor/extension.js:336
msgid "Upload stats"
msgstr "Статыстыка адпраўлення даных"
#: extensions/system-monitor/extension.js:350
msgid "Download stats"
msgstr "Статыстыка атрымання даных"
#: extensions/system-monitor/extension.js:364
msgid "System stats"
msgstr "Статыстыка сістэмы"
#: extensions/system-monitor/extension.js:412
msgid "Show"
msgstr "Паказваць"
#: extensions/system-monitor/extension.js:414
msgid "CPU"
msgstr "Працэсар"
#: extensions/system-monitor/extension.js:416
msgid "Memory"
msgstr "Памяць"
#: extensions/system-monitor/extension.js:418
msgid "Swap"
msgstr "Своп"
#: extensions/system-monitor/extension.js:420
msgid "Upload"
msgstr "Атрыманне"
#: extensions/system-monitor/extension.js:422
msgid "Download"
msgstr "Адпраўленне"
#: extensions/system-monitor/extension.js:427
msgid "Open System Monitor"
msgstr "Адкрыць сістэмны манітор"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:12
msgid "Show CPU usage"
msgstr "Паказваць выкарыстанне працэсара"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:16
msgid "Show memory usage"
msgstr "Паказваць выкарыстанне памяці"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:20
msgid "Show swap usage"
msgstr "Паказваць выкарыстанне своп"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:24
msgid "Show upload"
msgstr "Паказваць атрыманне даных"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:28
msgid "Show download"
msgstr "Паказваць адпраўленне даных"
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:11
msgid "Theme name"
msgstr "Назва тэмы"
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:6
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:12
msgid "The name of the theme, to be loaded from ~/.themes/name/gnome-shell"
msgstr "Назва тэмы, што загрузіцца з ~/.themes/name/gnome-shell"
@@ -157,51 +229,51 @@ msgstr "Назва тэмы, што загрузіцца з ~/.themes/name/gnome
msgid "Close"
msgstr "Закрыць"
#: extensions/window-list/extension.js:92
#: extensions/window-list/extension.js:99
msgid "Unminimize"
msgstr "Скасаваць згортванне"
#: extensions/window-list/extension.js:92
#: extensions/window-list/extension.js:99
msgid "Minimize"
msgstr "Згарнуць"
#: extensions/window-list/extension.js:99
#: extensions/window-list/extension.js:106
msgid "Unmaximize"
msgstr "Скасаваць разгортванне"
#: extensions/window-list/extension.js:99
#: extensions/window-list/extension.js:106
msgid "Maximize"
msgstr "Разгарнуць"
#: extensions/window-list/extension.js:483
#: extensions/window-list/extension.js:471
msgid "Minimize all"
msgstr "Згарнуць усе"
#: extensions/window-list/extension.js:489
#: extensions/window-list/extension.js:477
msgid "Unminimize all"
msgstr "Скасаваць згортванне для ўсіх"
#: extensions/window-list/extension.js:495
#: extensions/window-list/extension.js:483
msgid "Maximize all"
msgstr "Разгарнуць усе"
#: extensions/window-list/extension.js:503
#: extensions/window-list/extension.js:491
msgid "Unmaximize all"
msgstr "Скасаваць разгортванне для ўсіх"
#: extensions/window-list/extension.js:511
#: extensions/window-list/extension.js:499
msgid "Close all"
msgstr "Закрыць усе"
#: extensions/window-list/extension.js:795
#: extensions/window-list/extension.js:778
msgid "Window List"
msgstr "Спіс вокнаў"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:12
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:18
msgid "When to group windows"
msgstr "Умовы групавання вокнаў"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:13
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:19
msgid ""
"Decides when to group windows from the same application on the window list. "
"Possible values are “never”, “auto” and “always”."
@@ -209,26 +281,30 @@ msgstr ""
"Вызначае калі групаваць вокны адной праграмы ў спісе вокнаў. Магчымыя "
"значэнні: «never» (ніколі), «auto» (аўтаматычна), «always» (заўсёды)."
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:20
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:26
#: extensions/window-list/prefs.js:79
msgid "Show windows from all workspaces"
msgstr "Паказваць вокны з усіх працоўных прастор"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:21
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:27
msgid "Whether to show windows from all workspaces or only the current one."
msgstr "Паказваць вокны з усіх працоўных прастор ці толькі з бягучай."
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:27
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:33
msgid "Show the window list on all monitors"
msgstr "Паказваць спіс вокнаў на ўсіх маніторах"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:28
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:34
msgid ""
"Whether to show the window list on all connected monitors or only on the "
"primary one."
msgstr ""
"Паказваць спіс вокнаў на ўсіх падлучаных маніторах ці толькі на асноўным."
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:41
msgid "Show workspace previews in window list"
msgstr "Паказваць папярэдні прагляд працоўных прастор у спісе акон"
#: extensions/window-list/prefs.js:35
msgid "Window Grouping"
msgstr "Групаванне вокнаў"
@@ -249,24 +325,38 @@ msgstr "Заўсёды групаваць вокны"
msgid "Show on all monitors"
msgstr "Паказваць на ўсіх маніторах"
#: extensions/window-list/workspaceIndicator.js:261
#: extensions/workspace-indicator/extension.js:266
msgid "Workspace Indicator"
msgstr "Індыкатар працоўнай прасторы"
#: extensions/window-list/prefs.js:92
msgid "Show workspace previews"
msgstr "Паказваць папярэдні прагляд працоўных прастор"
#: extensions/workspace-indicator/prefs.js:62
#: extensions/workspace-indicator/prefs.js:30
msgid "Show Previews In Top Bar"
msgstr "Паказваць папярэдні прагляд у верхняй панэлі"
#: extensions/workspace-indicator/prefs.js:88
#, javascript-format
msgid "Workspace %d"
msgstr "Працоўная прастора %d"
#: extensions/workspace-indicator/prefs.js:129
#: extensions/workspace-indicator/prefs.js:155
msgid "Workspace Names"
msgstr "Назвы працоўных прастор"
#: extensions/workspace-indicator/prefs.js:255
#: extensions/workspace-indicator/prefs.js:281
msgid "Add Workspace"
msgstr "Дадаць працоўную прастору"
#: extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml:12
msgid "Show workspace previews in top bar"
msgstr "Паказваць папярэдні прагляд працоўных прастор у верхняй панэлі"
#: extensions/workspace-indicator/workspaceIndicator.js:430
msgid "Workspace Indicator"
msgstr "Індыкатар працоўнай прасторы"
#~ msgid "Applications"
#~ msgstr "Праграмы"
#~ msgid "Attach modal dialog to the parent window"
#~ msgstr "Прымацаваць мадальны дыялог да бацькоўскага акна"
@@ -328,7 +418,7 @@ msgstr "Дадаць працоўную прастору"
#~ "If not empty, it contains the text that will be shown when clicking on "
#~ "the panel."
#~ msgstr ""
#~ "Калі не пуста, ўтрымлівае тэкст, які будзе паказвацца пры націсканні на "
#~ "Калі не пуста, змяшчае тэкст, які будзе паказвацца пры націсканні на "
#~ "панэль."
#~ msgid "Message"

224
po/bg.po
View File

@@ -1,24 +1,28 @@
# Bulgarian translation for gnome-shell-extensions po-file.
# Copyright (C) 2014, 2015, 2017 Free Software Foundation, Inc.
# Copyright (C) 2021, 2022 Alexander Shopov <ash@kambanaria.org>.
# Copyright (C) 2024 twlvnn kraftwerk <kraft_werk@tutanota.com>.
# This file is distributed under the same license as the gnome-shell-extensions package.
# Ivaylo Valkov <ivaylo@e-valkov.org>, 2014.
# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2021, 2022.
# Lyubomir Vasilev <lyubomirv@abv.bg>, 2017.
# twlvnn kraftwerk <kraft_werk@tutanota.com>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell-extensions master\n"
"Project-Id-Version: gnome-shell-extensions main\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
"issues\n"
"POT-Creation-Date: 2022-02-12 20:25+0000\n"
"PO-Revision-Date: 2022-02-13 11:40+0100\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"POT-Creation-Date: 2024-09-01 12:03+0000\n"
"PO-Revision-Date: 2024-09-02 10:49+0200\n"
"Last-Translator: twlvnn kraftwerk <kraft_werk@tutanota.com>\n"
"Language-Team: Bulgarian <dict@ludost.net>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Generator: Gtranslator 46.1\n"
#: data/gnome-classic.desktop.in:3
msgid "GNOME Classic"
@@ -37,19 +41,19 @@ msgstr "Класически GNOME в Wayland"
msgid "GNOME Classic on Xorg"
msgstr "Класически GNOME в Xorg"
#: extensions/apps-menu/extension.js:112
#: extensions/apps-menu/extension.js:126
msgid "Favorites"
msgstr "Любими"
#: extensions/apps-menu/extension.js:370
msgid "Applications"
#: extensions/apps-menu/extension.js:400
msgid "Apps"
msgstr "Програми"
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:6
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:12
msgid "Application and workspace list"
msgstr "Списък с програмите и работните плотове"
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:7
#: extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml:13
msgid ""
"A list of strings, each containing an application id (desktop file name), "
"followed by a colon and the workspace number"
@@ -57,34 +61,34 @@ msgstr ""
"Списък от низове. Всеки съдържа идентификатор на програма (име на файл „."
"desktop“), следван от знака „:“ и номер на работен плот"
#: extensions/auto-move-windows/prefs.js:19
#: extensions/auto-move-windows/prefs.js:159
msgid "Workspace Rules"
msgstr "Правила за работните плотове"
#: extensions/auto-move-windows/prefs.js:245
#: extensions/auto-move-windows/prefs.js:314
msgid "Add Rule"
msgstr "Добавяне на правило"
#. TRANSLATORS: %s is the filesystem name
#: extensions/drive-menu/extension.js:123
#: extensions/places-menu/placeDisplay.js:210
#: extensions/places-menu/placeDisplay.js:218
#, javascript-format
msgid "Ejecting drive “%s” failed:"
msgstr "Неуспешно изваждане на устройство „%s“:"
#: extensions/drive-menu/extension.js:139
#: extensions/drive-menu/extension.js:142
msgid "Removable devices"
msgstr "Преносими медии"
#: extensions/drive-menu/extension.js:161
#: extensions/drive-menu/extension.js:164
msgid "Open Files"
msgstr "Отваряне на файлове"
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:5
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:11
msgid "Use more screen for windows"
msgstr "Повече пространство за прозорците"
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:6
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:12
msgid ""
"Try to use more screen for placing window thumbnails by adapting to screen "
"aspect ratio, and consolidating them further to reduce the bounding box. "
@@ -95,11 +99,11 @@ msgstr ""
"смаляване на обхващащия ги правоъгълник. Тази настройка се прилага само при "
"естествената стратегия за поставяне на прозорците."
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:11
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:17
msgid "Place window captions on top"
msgstr "Заглавия на прозорците отгоре"
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:12
#: extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml:18
msgid ""
"If true, place window captions on top the respective thumbnail, overriding "
"shell default of placing it at the bottom. Changing this setting requires "
@@ -109,123 +113,195 @@ msgstr ""
"им, а не както е стандартно — отдолу. За прилагане на промяната на "
"настройката трябва да рестартирате обвивката на GNOME."
#: extensions/places-menu/extension.js:88
#: extensions/places-menu/extension.js:91
#: extensions/places-menu/extension.js:94
msgid "Places"
msgstr "Места"
#: extensions/places-menu/placeDisplay.js:49
#: extensions/places-menu/placeDisplay.js:60
#, javascript-format
msgid "Failed to launch “%s”"
msgstr "Неуспешно стартиране на „%s“"
#: extensions/places-menu/placeDisplay.js:64
#: extensions/places-menu/placeDisplay.js:75
#, javascript-format
msgid "Failed to mount volume for “%s”"
msgstr "Неуспешно монтиране на тома „%s“"
#: extensions/places-menu/placeDisplay.js:125
#: extensions/places-menu/placeDisplay.js:148
#: extensions/places-menu/placeDisplay.js:135
#: extensions/places-menu/placeDisplay.js:158
msgid "Computer"
msgstr "Компютър"
#: extensions/places-menu/placeDisplay.js:336
#: extensions/places-menu/placeDisplay.js:333
msgid "Home"
msgstr "Домашна папка"
#: extensions/places-menu/placeDisplay.js:381
#: extensions/places-menu/placeDisplay.js:378
msgid "Browse Network"
msgstr "Мрежа"
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:7
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:14
msgid "Cycle Screenshot Sizes"
msgstr "Смяна на размерите на снимката на екрана"
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:11
#: extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml:18
msgid "Cycle Screenshot Sizes Backward"
msgstr "Смяна на размерите на снимката на екрана наобратно"
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:5
#: extensions/system-monitor/extension.js:135
msgid "CPU stats"
msgstr "Статистика на ЦП"
#: extensions/system-monitor/extension.js:159
msgid "Memory stats"
msgstr "Статистика на паметта"
#: extensions/system-monitor/extension.js:177
msgid "Swap stats"
msgstr "Статистика на виртуалната памет"
#: extensions/system-monitor/extension.js:336
msgid "Upload stats"
msgstr "Статистика на качване"
#: extensions/system-monitor/extension.js:350
msgid "Download stats"
msgstr "Статистика на изтегляне"
#: extensions/system-monitor/extension.js:364
msgid "System stats"
msgstr "Статистика на системата"
#: extensions/system-monitor/extension.js:412
msgid "Show"
msgstr "Показване"
#: extensions/system-monitor/extension.js:414
msgid "CPU"
msgstr "ЦП"
#: extensions/system-monitor/extension.js:416
msgid "Memory"
msgstr "Памет"
#: extensions/system-monitor/extension.js:418
msgid "Swap"
msgstr "Виртуалната памет"
#: extensions/system-monitor/extension.js:420
msgid "Upload"
msgstr "Качване"
#: extensions/system-monitor/extension.js:422
msgid "Download"
msgstr "Изтегляне"
#: extensions/system-monitor/extension.js:427
msgid "Open System Monitor"
msgstr "Отваряне на „Наблюдение на системата“"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:12
msgid "Show CPU usage"
msgstr "Показване на ползван ЦП"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:16
msgid "Show memory usage"
msgstr "Показване на ползвана памет"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:20
msgid "Show swap usage"
msgstr "Показване на ползвана виртуалната памет"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:24
msgid "Show upload"
msgstr "Показване на качването"
#: extensions/system-monitor/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml:28
msgid "Show download"
msgstr "Показване на изтеглянето"
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:11
msgid "Theme name"
msgstr "Име на темата"
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:6
#: extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml:12
msgid "The name of the theme, to be loaded from ~/.themes/name/gnome-shell"
msgstr ""
"Името на темата, която да бъде заредена от „~/.themes/name/gnome-shell“"
#: extensions/window-list/extension.js:72
#: extensions/window-list/extension.js:70
msgid "Close"
msgstr "Затваряне"
#: extensions/window-list/extension.js:92
#: extensions/window-list/extension.js:97
msgid "Unminimize"
msgstr "Деминимизиране"
#: extensions/window-list/extension.js:92
#: extensions/window-list/extension.js:97
msgid "Minimize"
msgstr "Минимизиране"
#: extensions/window-list/extension.js:99
#: extensions/window-list/extension.js:104
msgid "Unmaximize"
msgstr "Демаксимизиране"
#: extensions/window-list/extension.js:99
#: extensions/window-list/extension.js:104
msgid "Maximize"
msgstr "Максимизиране"
#: extensions/window-list/extension.js:434
#: extensions/window-list/extension.js:489
msgid "Minimize all"
msgstr "Минимизиране на всички"
#: extensions/window-list/extension.js:440
#: extensions/window-list/extension.js:495
msgid "Unminimize all"
msgstr "Деминимизиране на всички"
#: extensions/window-list/extension.js:446
#: extensions/window-list/extension.js:501
msgid "Maximize all"
msgstr "Максимизиране на всички"
#: extensions/window-list/extension.js:454
#: extensions/window-list/extension.js:509
msgid "Unmaximize all"
msgstr "Демаксимизиране на всички"
#: extensions/window-list/extension.js:462
#: extensions/window-list/extension.js:517
msgid "Close all"
msgstr "Затваряне на всички"
#: extensions/window-list/extension.js:741
#: extensions/window-list/extension.js:789
msgid "Window List"
msgstr "Списък на прозорците"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:12
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:18
msgid "When to group windows"
msgstr "Кога прозорците да се групират"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:13
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:19
msgid ""
"Decides when to group windows from the same application on the window list. "
"Possible values are “never”, “auto” and “always”."
msgstr ""
"Кога прозорците на една програма да се групират в списъка с прозорците. "
"Възможните стойности са „never“ (никога), „auto“ (автоматично) и "
"„always“ (винаги)."
"Възможните стойности са „never“ (никога), „auto“ (автоматично) и „always“ "
"(винаги)."
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:20
#: extensions/window-list/prefs.js:76
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:26
#: extensions/window-list/prefs.js:79
msgid "Show windows from all workspaces"
msgstr "Да се показват прозорците от всички работни плотове"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:21
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:27
msgid "Whether to show windows from all workspaces or only the current one."
msgstr ""
"Дали да се показват прозорците от всички работни плотове или само от текущия."
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:27
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:33
msgid "Show the window list on all monitors"
msgstr "Извеждане на списъка с прозорци на всички монитори"
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:28
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:34
msgid ""
"Whether to show the window list on all connected monitors or only on the "
"primary one."
@@ -233,40 +309,58 @@ msgstr ""
"Дали списъкът с прозорци да се извежда на всички монитори или само на "
"основния"
#: extensions/window-list/prefs.js:32
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:41
msgid "Show workspace previews in window list"
msgstr "Визуализиране на работните пространства в списъка с прозорци"
#: extensions/window-list/prefs.js:35
msgid "Window Grouping"
msgstr "Групиране на прозорци"
#: extensions/window-list/prefs.js:37
#: extensions/window-list/prefs.js:40
msgid "Never group windows"
msgstr "Никога да не се групират"
#: extensions/window-list/prefs.js:38
#: extensions/window-list/prefs.js:41
msgid "Group windows when space is limited"
msgstr "Групиране при ограничено място"
#: extensions/window-list/prefs.js:39
#: extensions/window-list/prefs.js:42
msgid "Always group windows"
msgstr "Винаги да се групират"
#: extensions/window-list/prefs.js:63
#: extensions/window-list/prefs.js:66
msgid "Show on all monitors"
msgstr "На всички монитори"
#: extensions/window-list/workspaceIndicator.js:249
#: extensions/workspace-indicator/extension.js:254
msgid "Workspace Indicator"
msgstr "Индикатор на работните плотове"
#: extensions/window-list/prefs.js:92
msgid "Show workspace previews"
msgstr "Визуализиране на работните пространства"
#: extensions/workspace-indicator/prefs.js:18
msgid "Workspace Names"
msgstr "Имена на работните плотове"
#: extensions/workspace-indicator/prefs.js:30
msgid "Show Previews In Top Bar"
msgstr "Визуализиране в горната лента"
#: extensions/workspace-indicator/prefs.js:39
#: extensions/workspace-indicator/prefs.js:88
#, javascript-format
msgid "Workspace %d"
msgstr "Работен плот %d"
#: extensions/workspace-indicator/prefs.js:184
#: extensions/workspace-indicator/prefs.js:155
msgid "Workspace Names"
msgstr "Имена на работните плотове"
#: extensions/workspace-indicator/prefs.js:281
msgid "Add Workspace"
msgstr "Добавяне на работен плот"
#: extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml:12
msgid "Show workspace previews in top bar"
msgstr "Визуализиране на работните пространства в горната лента"
#: extensions/workspace-indicator/workspaceIndicator.js:430
msgid "Workspace Indicator"
msgstr "Индикатор на работните плотове"
#~ msgid "Applications"
#~ msgstr "Програми"

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