Compare commits

..

119 Commits

Author SHA1 Message Date
Jeremy Bícha e864d0d1cc New upstream version 45~beta 2023-08-16 22:55:57 -04:00
Florian Müllner 4345703c2e Bump version to 45.beta
Update NEWS.
2023-08-07 16:41:23 +02:00
Florian Müllner a911447375 js: Port to ESM
The shell pulled the trigger and switched to ESM for all its
imports, follow suit.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/269>
2023-08-06 15:59:35 +02:00
Florian Müllner 2d3307c657 window-list: Use InjectionManager instead of custom classes
Once the shell is ported to ESM, it will no longer be possible
to replace entire classes (even when imported). Prepare for that
by overriding methods of the regular WorkspaceBackground class
instead.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
2023-08-06 13:45:56 +02:00
Florian Müllner d59bc0b7f0 window-list: Do not inject WindowPicker into Main
This will become impossible once Main is converted to ESM. Instead,
use the Extension class itself to hold the window picker.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
2023-08-06 13:45:56 +02:00
Florian Müllner cb8c2eb27f windowsNavigator: Use InjectionManager instead of custom classes
Once the shell is ported to ESM, it will no longer be possible
to replace entire classes (even when exported). Prepare for that
by overriding methods of the regular classes, instead of creating
custom subclasses.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
2023-08-06 13:45:56 +02:00
Florian Müllner 0544729bba launch-new-instance: Use InjectionManager
The extension uses a straight-forward override that doesn't
benefit a lot from the new InjectionManager class, but let's
use the provided convenience API anyway.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
2023-08-05 21:32:27 +02:00
Florian Müllner 017c410a6a native-window-placement: Use InjectionManager
The new convenience class was modelled after the code in the
extension, so it's a drop-in replacement.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
2023-08-05 18:53:41 +02:00
Florian Müllner f2c73329be extensions: Use new convenience classes
Convenience APIs for extensions are now provided as Extension/Prefs
base classes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
2023-08-05 18:53:41 +02:00
Efstathios Iosifidis ce644be96f Update Greek translation 2023-08-01 20:41:56 +00:00
Florian Müllner e75a1a15ac extensions: Import ExtensionUtils as module
ExtensionUtils has been converted to ESM and split into two modules,
for extensions and prefs respectively.

Adjust to those changes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/266>
2023-07-15 14:13:25 +02:00
Florian Müllner 1155170c7c window-list: Stop using getCurrentExtension()
The method is no longer exported. There will be a nicer alternative
soon, in the meantime we can just keep track of our main Extension
object ourselves.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/266>
2023-07-15 14:10:27 +02:00
Florian Müllner 6d8f54a20b js: Really use connectObject()
I forgot in two places to change the actual connect() function
to connectObject() 🤦️

Fixes commit 3bfaf6f88a.
2023-07-10 07:22:25 +02:00
Florian Müllner 93a2e7bdba extensions: Stop using global.log()
It has been deprecated since 3.6(!) in favor of the actually
global log().

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/264>
2023-07-10 06:51:45 +02:00
Florian Müllner 3bfaf6f88a js: Use connectObject()
gnome-shell added (dis)connectObject() methods to partially automate
signal handling. It doesn't only save a significant amount of code,
but also makes it harder to miss cleaning up on destroy.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/263>
2023-07-09 18:45:07 +02:00
Florian Müllner 37baccd9fc window-list: Remove some dead code
The code that connected the signal was removed in 9fa522c29a.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/263>
2023-07-09 18:33:52 +02:00
Florian Müllner 9365725246 ci: Use wrapper to run eslint
The eslint job report its results as artifacts in junit format,
so that gitlab can present them in its UI.

However many psople miss that, and unsuccessfully check the logs
instead.

Address this by using a simplified version of gnome-shell's eslint
wrapper, so we can report results both on stdout and in a file
without re-running the linter.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/262>
2023-07-09 16:21:03 +02:00
Florian Müllner f1257c4523 Ignore some common patterns
Ignore patches, vim session files and project configuration
of GNOME Builder and VSCode.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/261>
2023-07-09 15:59:34 +02:00
Florian Müllner f0865f039e Clean up .gitignore
Meson enforces a separate build dir, so we no longer have to
care about build artifacts in the source tree. Same applies for
all the generated crap autotools like to spread around.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/261>
2023-07-09 15:59:34 +02:00
Florian Müllner 4955c20669 data: Remove left-over file
We no longer have a separate classic theme that could(*) use
custom assets, so the file is now very officially a left-over.

(*) spoiler alert: The made-up property where the image was
used has been ignored by gnome-shell for years

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/260>
2023-07-09 14:27:44 +02:00
Florian Müllner cf007dd472 extensions: Turn extensions into modules
As gnome-shell is moving to ESM, it will now load extensions as
standard modules instead of using legacy imports. The change boils
down to exporting the Extension class as default, but we can also
start using standard imports for introspected modules now, so do
that at the same time.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/259>
2023-07-07 00:35:08 +02:00
Florian Müllner 701b14ecbf extensions: Use extension class for all extensions
This will be the only supported entry point when extension loading
switches to dynamic imports, so prepare for that by wrapping the
remaining standalone enable()/disable() methods in Extension classes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/259>
2023-07-07 00:12:41 +02:00
Florian Müllner 18674b2e35 lint: Migrate eslint-plugin-jsdoc rule
Migrate a removed jsdoc, copied from the corresponding gnome-shell
change.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/259>
2023-07-07 00:11:57 +02:00
Jeremy Bicha 930595003d New upstream version 44.0 2023-03-27 08:47:18 -04:00
Jeremy Bicha 51df22adcf New upstream version 44~rc 2023-03-07 12:19:33 -05:00
Jeremy Bicha 6ff6eb2c22 New upstream version 44~beta 2023-02-15 10:59:26 -05:00
Jeremy Bicha 6bee46bf1a New upstream version 43.1 2022-11-22 14:13:08 -05:00
Jeremy Bicha f4347d240a New upstream version 43.0 2022-09-19 10:57:25 -04:00
Jeremy Bicha 81b8ad4499 New upstream version 43~rc 2022-09-06 14:38:13 -04:00
Jeremy Bicha aeee81a82c New upstream version 43~beta 2022-08-21 10:59:16 -04:00
Jeremy Bicha fcefdc3271 New upstream version 42.3 2022-07-13 17:46:10 +02:00
Jeremy Bicha 7a017c1e76 New upstream version 42.2 2022-06-03 09:19:21 -04:00
Jeremy Bicha b2455f0ecd New upstream version 42.1 2022-05-09 08:02:09 -04:00
Jeremy Bicha 573aba17d7 New upstream version 42.0 2022-03-14 11:29:53 -04:00
Jeremy Bicha 2117c42d74 New upstream version 42~rc 2022-03-08 09:32:26 -05:00
Marco Trevisan (Treviño) 5edffcd859 New upstream version 42~beta 2022-02-23 02:57:09 +01:00
Jeremy Bicha d8b526a715 New upstream version 41.1 2021-12-12 20:28:55 -05:00
Florian Müllner a5b6871562 Bump version to 41.1
Update NEWS.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/200>
2021-12-11 14:20:23 +01:00
Florian Müllner deb6031381 window-list: Fix OSK
The reveal animation moved from Main.layoutManager.keyboardBox to
the keyboard itself, so instead of applying an additional translation
for the bottom panel, we override the translation that would reveal
the keyboard (and thus prevent it from showing altogether).

Fix this by moving our translation to the keyboardBox instead.

(cherry picked from commit 02e5029eb6)

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/202>
2021-12-11 14:04:21 +01:00
Sebastian Keller 486cb59aff native-window-placement: Remove custom styling
The window-picker padding was causing it to become smaller in the
overview resulting in a jump when opening it and caused sizing issues
with the workspace view in the app picker. However it is not needed
anymore with the new overview, so this can be fixed by simply removing
it.

The horizontal- and vertical-spacing properties got replaced with a
spacing property a while ago. However this is only used in
WorkspaceLayout::_createBestLayout() which gets overridden by this
extension which does not use it. So they can simply be removed.

The shell-caption-spacing property got removed when the window captions
got changed to always use the full length and has not been doing
anything since.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/301
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/309
(cherry picked from commit 4a26cecd7d)

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/202>
2021-12-11 14:04:07 +01:00
Neal Gompa de9a3df7bd classic: Add X-GNOME-SessionRegisters
GDM has supported sessions registering with it for a few years now so
it can know when to shut down the greeter. Having the GNOME Classic
session declare that it will register itself allows GDM to avoid
executing a fallback codepath.

This has been supported with the regular GNOME session for a while,
and this session was likely forgotten about when it was added there.

(cherry picked from commit a79d2afb2d)

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/202>
2021-12-11 14:03:33 +01:00
Jeremy Bicha db131fc7da New upstream version 41.0 2021-10-03 20:42:40 -04:00
Jeremy Bicha 80c6656c4f New upstream version 40.4 2021-08-29 08:50:41 -04:00
Florian Müllner a5a3523df8 Bump version to 40.4
Update NEWS.
2021-08-18 01:18:19 +02:00
Florian Müllner 06acd9ff25 build: Rewrite gettext domain when exporting zips
Now that every extension picks up its gettext domain from
its metadata, we can easily change it when exporting the
zips.

That ensures that every extension only binds its own domain
instead of messing up other extension's translations.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/179>
2021-08-12 04:17:46 +02:00
Florian Müllner 1a1d45d9e4 build: Remove unused variable
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/335

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/179>
2021-08-12 04:17:46 +02:00
Florian Müllner 1d3775b3d1 extensions: Pick up gettext domain from metadata
Since commit a6ee142f21, the extension archives that are uploaded
to extensions.gnome.org only contain strings that are relevant for
the extension, not all translations from all extensions.

Unfortunately all extensions still share a common gettext domain,
so the extension with the last bind_textdomain() call wins and
leaves the others without translations.

We'll address this by using distinct domains when not installed
system-wide. That becomes easier if there is a canonical place
for the text domain, with the existing metadata key being the
natural choice.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/179>
2021-08-12 04:17:46 +02:00
Florian Müllner 15c83db793 drive-menu: Hide items initially
Now that the check for network mounts is non-blocking, the initial
sync doesn't take effect immediately. We don't want hidden items
to briefly flash the indicator, so create them initially hidden.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/176>
2021-07-19 16:44:37 +02:00
Florian Müllner cc021589b8 drive-menu: Fix indicator visibility
Commit 519269be9d made the check for network mounts non-blocking, and
we now update the indicator's visibility before a newly-added network
mount is hidden.

Address this by monitoring the item itself for visibility changes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/176>
2021-07-19 16:44:37 +02:00
Florian Müllner 5e316d37cb Bump version to 40.3
Update NEWS.
2021-07-12 18:18:45 +02:00
Florian Müllner 28dbb47937 window-list: Init translations
Whoops, we are missing the bindtextdomain() call, which means translations
won't work when no other extension that shares the same domain is used
(like in GNOME Classic for instance).

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/340
(cherry picked from commit c9d7f99d50f96d29c38380d9f0e3c9ddc660db9f)
2021-07-12 18:06:31 +02:00
Florian Müllner 619de9d5ee drive-menu: Avoid blocking I/O when querying filesystem
The last commit improved the heuristics for detecting network mounts,
but at the price of potentially blocking the shell. Avoid that drawback
by making the code in question async.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/27>
(cherry picked from commit 519269be9d)
2021-07-12 18:06:31 +02:00
Florian Müllner 561b8aeb03 drive-menu: Don't assume mounts without volume are local
The intention of the code is to only expose actually plugged in
devices rather than network mounts, but the existing heuristics are
based on GVolume and simply assume a local mount where there's no
associated volume. Fill that gap by querying the ::remote filesystem
attribute in that case.

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

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/27>
(cherry picked from commit 7d6670ce3c)
2021-07-12 18:06:31 +02:00
Florian Müllner 4286fd1bcc Tag release 40.2
Update NEWS.
2021-06-10 13:41:34 +02:00
Adam Goode 3bb0897bc1 window-list: Don't use panel-button class for the workspace indicator
The panel-button introduces some horizontal padding which is insensitive
to scroll events. Without this change, there is a small dead zone in the
corner that cannot be used to switch workspaces with the mouse wheel.

For useMenu mode, this has the effect of removing all of the horizontal
space to the edge of the screen, so I add some back with the
status-label-bin margin.

This a is similar change to 8bad8a3b63.

Fixes #315.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/171>
(cherry picked from commit d6648b0b5c)
2021-06-10 13:38:47 +02:00
Juliano de Souza Camargo 12eedcf6f7 Update Portuguese translation 2021-06-07 10:22:02 +00:00
Hugo Carvalho 08d382facc Update Portuguese translation 2021-06-02 16:09:54 +00:00
Marco Trevisan (Treviño) d9ae9a023a New upstream version 40.1 2021-05-30 17:53:15 +02:00
Florian Müllner 96a1de92db build: Only use major version in shell-versions
The website changed its version handling again, and now takes "40.0"
to mean "40.0, and only 40.0".

Not complaining though, as "40" is more correct in my opinion anyway ...

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/172>
2021-05-25 19:26:08 +02:00
Florian Müllner cc2f46b837 Post-release version bump 2021-05-14 17:00:35 +02:00
Simon McVittie 9f25047e24 New upstream version 3.38.2 2020-12-03 10:11:14 +00:00
Florian Müllner fb66afbf71 Bump version to 3.38.2
Update NEWS.
2020-12-03 00:14:49 +01:00
Florian Müllner 365fa6abc9 Update sass submodule 2020-12-03 00:14:49 +01:00
Florian Müllner d7a824f35f workspace-indicator: Use overlap to determine preview visibility
In order to better reflect the actual workspace, show any preview
that is at least partially located on the monitor, not only those
that have the major part on that monitor.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/142>

(cherry picked from commit 50d3ee5703)
2020-12-03 00:09:21 +01:00
Florian Müllner 0d8e412220 window-list: Use overlap to determine preview visibility
In order to better reflect the actual workspace, show any preview
that is at least partially located on the monitor, not only those
that have the major part on that monitor.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/142>

(cherry picked from commit 08dfb78815)
2020-12-03 00:09:19 +01:00
Florian Müllner 991f6ef508 workspace-indicator: Account for monitor offset in window previews
Windows' frame rects are in screen coordinates, while the workspace
thumbnails are based on the monitor work area. Unless we account
for the difference, previews end up mispositioned in multi-monitor
setups.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/142>

(cherry picked from commit 6949a5d075)
2020-12-03 00:09:16 +01:00
Florian Müllner 37f03f5e2e window-list: Account for monitor offset in window previews
Windows' frame rects are in screen coordinates, while the workspace
thumbnails are based on the monitor work area. Unless we account
for the difference, previews end up mispositioned in multi-monitor
setups.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/142>

(cherry picked from commit 893d3b0473)
2020-12-03 00:09:12 +01:00
Florian Müllner b4a4ff0a06 workspace-indicator: Round calculated preview sizes
While not strictly necessary, there's no reason to differ from the
copy in the window-list extension ...

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/142>

(cherry picked from commit f5128e13f2)
2020-12-03 00:09:09 +01:00
Ray Strode de8876bd5e window-list: Stop monitoring drag operation if window list is destroyed
If a user is in the middle of a drag in the window list and the
window list associated with the drag gets destroyed, the drag
monitor gets leaked.

Later when the drag motion is processed, spew goes to the log:

clutter_actor_contains: assertion 'CLUTTER_IS_ACTOR (self)' failed

Examples of triggers for this bug:

- The monitor topology changes
- The screen gets locked during the drag

This commit fixes the spew and the leak by ensuring any pending
drag monitoring is disabled when the window lists are destroyed.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/145>

(cherry picked from commit 8318ea919f)
2020-12-03 00:08:57 +01:00
Thun Pin 5ad272e628 window-navigator: Adjust to 3.38 overview changes
gnome-shell's overview code changed significantly in 3.38,
adjust the extension to work without the separate overlay.

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

(cherry picked from commit 737c897624)
2020-12-03 00:08:30 +01:00
Florian Müllner 3b22582752 auto-move-windows: Exclude sticky windows from empty-check
We modify gnome-shell's workspace tracker to only remove empty
workspaces from the end. However we currently don't take into
account that sticky windows appear on all workspaces, so those
are preventing any workspace from getting removed at the moment.

Exclude them when determining whether a workspace is empty to
get the expected behavior.

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/135

(cherry picked from commit 61cf679b8c)
2020-12-03 00:08:07 +01:00
Florian Müllner e734fcbd21 window-list: Adjust to overview changes
Window DND in the overview is now based on the metaWindow,
not the window actor (misnamed as "real window").

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/133
2020-11-19 04:54:07 +01:00
Florian Müllner 435879c121 workspace-indicator: Adjust to overview changes
Window DND in the overview is now based on the metaWindow,
not the window actor (misnamed as "real window").

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/133
2020-11-19 04:54:07 +01:00
Florian Müllner ed81650f55 window-list: Use custom layout manager for thumbnails
The current code positions window previews explicitly using a fixed
layout manager. For that it relies on a valid parent allocation,
which is error-prone and frequently results in warnings.

Address this by moving the positioning code into a custom layout
manager, and only update the visibility from the window preview.

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/260
2020-10-21 13:44:44 +02:00
Florian Müllner 1276a880de workspace-indicator: Use custom layout manager for thumbnails
The current code positions window previews explicitly using a fixed
layout manager. For that it relies on a valid parent allocation,
which is error-prone and frequently results in warnings.

Address this by moving the positioning code into a custom layout
manager, and only update the visibility from the window preview.

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/260
2020-10-21 13:44:44 +02:00
Sergio Costas 584016c291 window-list: Honor changes in skip-taskbar property
Although window-list checks the 'skip-taskbar' property when a
window is added to the desktop to decide wether it should be
shown in the bar or not, it doesn't honor that when the property
is changed after a window has already been added. Since the new
WaylandClient API allows to change this property for already
mapped windows, supporting this is a good idea.

This patch fixes this.

Fix https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/130


(cherry picked from commit b65f362f0d)
2020-10-08 21:50:07 +00:00
Jeremy Bicha 41664b152c New upstream version 3.38.1 2020-10-06 17:36:33 -04:00
Simon McVittie 8957c277a1 New upstream version 3.38.0 2020-09-22 09:16:27 +01:00
Marco Trevisan (Treviño) 8b9be8f120 New upstream version 3.37.91 2020-08-27 08:18:07 +02:00
Laurent Bigonville d3b687df8b New upstream version 3.36.2 2020-05-03 10:01:14 +02:00
Florian Müllner df463177e7 Bump version to 3.36.2
Update NEWS.
2020-04-29 22:45:40 +02:00
Florian Müllner 62af36ebfa Update sass submodule 2020-04-29 22:44:25 +02:00
Kristjan SCHMIDT c5246b7415 Update Esperanto translation 2020-04-18 09:00:46 +00:00
Xiaoguang Wang d39c1fd685 windowPicker: Wrong signal ID _nWorkspacesNotifyId
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/106


(cherry picked from commit f9aaa732b2)
2020-04-10 14:31:24 +00:00
Florian Müllner 665a7fbbcb ci: Update URL check
Gitlab started inserting a /-/ in its URLs, account for that.

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/113


(cherry picked from commit 7b82c5e12b)
2020-04-10 14:30:49 +00:00
Simon McVittie a4987d03b8 New upstream version 3.36.1 2020-04-02 10:14:07 +01:00
Yosef Or Boczko c477f10bfb Update Hebrew translation 2020-04-01 15:22:37 +00:00
Florian Müllner 2ae0f368b9 Bump version to 3.36.1
Update NEWS.
2020-03-31 00:58:41 +02:00
Iain Lane ac33058086 New upstream version 3.36.0 2020-03-16 12:13:26 +00:00
Marco Trevisan (Treviño) c7a08aaf74 New upstream version 3.35.91 2020-02-24 14:48:45 +01:00
Laurent Bigonville 8c1d6d88cf New upstream version 3.34.2 2019-12-30 00:41:31 +01:00
Florian Müllner 33b16681c6 Bump version to 3.34.2
Update NEWS.
2019-12-11 22:56:08 +01:00
Umarzuki Bin Mochlis Moktar 3c51716268 Update Malay translation 2019-12-09 11:59:58 +00:00
Willy Stadnick e5421b6cc6 screenshot-window-sizer: Fix cycling through all valid sizes
When cycling through window sizes, we should skip any sizes that are
bigger than the available area. We do that, but the current code
assumes that the possible sizes are sorted, which is no longer the
case since the addition of "phone" sizes in commit 5b43d4733c.

As a result, we may now skip sizes that would fit perfectly fine.
Address this by filtering out invalid sizes beforehand instead of
assuming a certain order (wich no longer work due to the addition
of a portrait format).

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/97
2019-11-27 20:56:55 +01:00
Florian Müllner f1e7ae1010 workspace-indicator: Exclude DESKTOP windows from window previews
While nautilus removed its desktop support a while ago in favor of an
extension, it's still possible that some external X11 desktop icon app
is used. As DESKTOP windows cannot be moved between workspaces or stacked,
and aren't perceived as regular windows, it doesn't make sense to show
them as previews in the workspace switcher.

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/93
2019-11-21 22:47:01 +01:00
Florian Müllner 10fe907c83 window-list: Exclude DESKTOP windows from window previews
While nautilus removed its desktop support a while ago in favor of an
extension, it's still possible that some external X11 desktop icon app
is used. As DESKTOP windows cannot be moved between workspaces or stacked,
and aren't perceived as regular windows, it doesn't make sense to show
them as previews in the workspace switcher.

https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/93
2019-11-21 22:47:01 +01:00
Stas Solovey ae9809caba Update Russian translation 2019-11-13 18:42:24 +00:00
Jeremy Bicha c95d197c5c New upstream version 3.34.1 2019-10-08 22:45:42 -04:00
Iain Lane ae8749b7e1 New upstream version 3.34.0 2019-09-10 10:53:04 +01:00
Iain Lane 84a548c0b9 New upstream version 3.33.92 2019-09-05 18:21:22 +01:00
Marco Trevisan (Treviño) f047cb0baf New upstream version 3.33.90 2019-08-13 04:25:54 +02:00
Iain Lane 28494941e1 New upstream version 3.32.0 2019-03-12 16:33:30 +00:00
Iain Lane b70059ac4d New upstream version 3.31.92 2019-03-06 15:39:47 +00:00
Iain Lane eb567c1120 New upstream version 3.31.90 2019-02-21 10:08:46 +00:00
Simon McVittie b1eb9b9080 New upstream version 3.30.1 2018-11-02 09:22:09 +00:00
Jeremy Bicha a0b6535210 New upstream version 3.30.0 2018-09-05 12:32:25 -04:00
Simon McVittie 9a9b3afa31 New upstream version 3.29.91 2018-08-20 19:55:42 +01:00
Simon McVittie 59bc054ef6 New upstream version 3.29.90 2018-08-02 10:32:10 +01:00
Simon McVittie 57e9dfe722 Merge remote-tracking branch 'origin/upstream/latest' into upstream/latest 2018-07-27 09:14:56 +01:00
Simon McVittie f17a519c38 New upstream version 3.29.3 2018-07-27 08:43:26 +01:00
Jeremy Bicha 8223ca9739 New upstream version 3.28.1 2018-05-14 21:50:46 -04:00
Jeremy Bicha fe20c27b60 New upstream version 3.28.0 2018-03-15 21:28:20 -04:00
Jeremy Bicha 5ba59d1096 New upstream version 3.27.92 2018-03-05 20:55:43 -05:00
Jeremy Bicha 0ad1e9bbc1 New upstream version 3.27.91 2018-02-23 19:30:14 -05:00
Jeremy Bicha 5ea14f063f New upstream version 3.26.2 2017-12-15 15:11:42 -05:00
Jeremy Bicha 3cc3d03f0b Initial upstream branch 2017-12-15 15:11:26 -05:00
Florian Müllner 057e5bb0c1 Bump version to 3.26.2
Update NEWS.
2017-11-02 19:51:10 +01:00
Florian Müllner 07fc66765d auto-move: Remove unused imports 2017-10-27 14:45:09 +02:00
Xavi Ivars daa7b9b6ab [l10n] Updated Catalan (Valencian) translation 2017-10-05 14:02:06 +02:00
29 changed files with 1154 additions and 4526 deletions
-29
View File
@@ -1,29 +0,0 @@
ABOUT-NLS
Makefile
Makefile.in
Makefile.in.in
aclocal.m4
autom4te.cache/
config/
configure
config.log
config.status
data/*.json
m4/
po/*.header
po/*.sed
po/*.sin
po/Makevars.template
po/POTFILES
po/Rules-quot
po/gnome-shell-extensions.pot
po/stamp-it
staging/
zip-files/
*~
*.gmo
metadata.json
*.desktop
*.gschema.valid
*.session
+2 -1
View File
@@ -107,7 +107,8 @@ eslint:
stage: review stage: review
<<: *prereview_req <<: *prereview_req
script: script:
- eslint -o $LINT_LOG -f junit --resolve-plugins-relative-to $(npm root -g) extensions - export NODE_PATH=$(npm root -g)
- ./.gitlab-ci/run-eslint --output-file ${LINT_LOG} --format junit --stdout
artifacts: artifacts:
paths: paths:
- ${LINT_LOG} - ${LINT_LOG}
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env node
const {ESLint} = require('eslint');
console.log(`Running ESLint version ${ESLint.version}...`);
const fs = require('fs');
const path = require('path');
function hasOption(...names) {
return process.argv.some(arg => names.includes(arg));
}
function getOption(...names) {
const optIndex =
process.argv.findIndex(arg => names.includes(arg)) + 1;
if (optIndex === 0)
return undefined;
return process.argv[optIndex];
}
(async function main() {
const outputOption = getOption('--output-file', '-o');
const outputPath = outputOption ? path.resolve(outputOption) : null;
const sourceDir = path.dirname(process.argv[1]);
process.chdir(path.resolve(sourceDir, '..'));
const sources = ['extensions'];
const eslint = new ESLint();
const results = await eslint.lintFiles(sources);
const formatter = await eslint.loadFormatter(getOption('--format', '-f'));
const resultText = formatter.format(results);
if (outputPath) {
fs.mkdirSync(path.dirname(outputPath), {recursive: true});
fs.writeFileSync(outputPath, resultText);
if (hasOption('--stdout')) {
const consoleFormatter = await eslint.loadFormatter();
console.log(consoleFormatter.format(results));
}
} else {
console.log(resultText);
}
process.exitCode = results.some(r => r.errorCount > 0) ? 1 : 0;
})().catch((error) => {
process.exitCode = 1;
console.error(error);
});
+11
View File
@@ -1,3 +1,14 @@
45.beta
=======
* Port extensions to ESM [Florian; !259, !266, !268, !269]
* Misc. bug fixes and cleanups [Florian; !260, !261, !262, !263, !264]
Contributors:
Florian Müllner
Translators:
Efstathios Iosifidis [el]
45.alpha 45.alpha
======== ========
* window-list: Modernize default styling [Alexander; !253] * window-list: Modernize default styling [Alexander; !253]
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 100 KiB

+45 -59
View File
@@ -1,18 +1,22 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported init enable disable */ import Atk from 'gi://Atk';
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GMenu from 'gi://GMenu';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
import Meta from 'gi://Meta';
import Shell from 'gi://Shell';
import St from 'gi://St';
import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
const { import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
Atk, Clutter, Gio, GLib, GMenu, GObject, Gtk, Meta, Shell, St,
} = imports.gi;
const {EventEmitter} = imports.misc.signals;
const DND = imports.ui.dnd; import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
const ExtensionUtils = imports.misc.extensionUtils; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Main = imports.ui.main; import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
const PanelMenu = imports.ui.panelMenu; import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const PopupMenu = imports.ui.popupMenu;
const _ = ExtensionUtils.gettext;
const appSys = Shell.AppSystem.get_default(); const appSys = Shell.AppSystem.get_default();
@@ -46,11 +50,8 @@ class ApplicationMenuItem extends PopupMenu.PopupBaseMenuItem {
this.label_actor = appLabel; this.label_actor = appLabel;
let textureCache = St.TextureCache.get_default(); let textureCache = St.TextureCache.get_default();
let iconThemeChangedId = textureCache.connect('icon-theme-changed', textureCache.connectObject('icon-theme-changed',
this._updateIcon.bind(this)); () => this._updateIcon(), this);
this.connect('destroy', () => {
textureCache.disconnect(iconThemeChangedId);
});
this._updateIcon(); this._updateIcon();
this._delegate = this; this._delegate = this;
@@ -269,9 +270,7 @@ class DesktopTarget extends EventEmitter {
_setDesktop(desktop) { _setDesktop(desktop) {
if (this._desktop) { if (this._desktop) {
this._desktop.disconnect(this._desktopDestroyedId); this._desktop.disconnectObject(this);
this._desktopDestroyedId = 0;
delete this._desktop._delegate; delete this._desktop._delegate;
} }
@@ -279,9 +278,9 @@ class DesktopTarget extends EventEmitter {
this.emit('desktop-changed'); this.emit('desktop-changed');
if (this._desktop) { if (this._desktop) {
this._desktopDestroyedId = this._desktop.connect('destroy', () => { this._desktop.connectObject('destroy', () => {
this._setDesktop(null); this._setDesktop(null);
}); }, this);
this._desktop._delegate = this; this._desktop._delegate = this;
} }
} }
@@ -321,10 +320,7 @@ class DesktopTarget extends EventEmitter {
} }
destroy() { destroy() {
if (this._windowAddedId) global.window_group.disconnectObject(this);
global.window_group.disconnect(this._windowAddedId);
this._windowAddedId = 0;
this._setDesktop(null); this._setDesktop(null);
} }
@@ -386,15 +382,14 @@ class ApplicationsButton extends PanelMenu.Button {
this.name = 'panelApplications'; this.name = 'panelApplications';
this.label_actor = this._label; this.label_actor = this._label;
this._showingId = Main.overview.connect('showing', () => { Main.overview.connectObject(
this.add_accessible_state(Atk.StateType.CHECKED); 'showing', () => this.add_accessible_state(Atk.StateType.CHECKED),
}); 'hiding', () => this.remove_accessible_state(Atk.StateType.CHECKED),
this._hidingId = Main.overview.connect('hiding', () => { this);
this.remove_accessible_state(Atk.StateType.CHECKED);
});
Main.wm.addKeybinding( Main.wm.addKeybinding(
'apps-menu-toggle-menu', 'apps-menu-toggle-menu',
ExtensionUtils.getSettings(), Extension.lookupByURL(import.meta.url).getSettings(),
Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW, Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
() => this.menu.toggle()); () => this.menu.toggle());
@@ -410,15 +405,15 @@ class ApplicationsButton extends PanelMenu.Button {
}); });
this._tree = new GMenu.Tree({menu_basename: 'applications.menu'}); this._tree = new GMenu.Tree({menu_basename: 'applications.menu'});
this._treeChangedId = this._tree.connect('changed', this._tree.connectObject('changed',
this._onTreeChanged.bind(this)); () => this._onTreeChanged(), this);
this._applicationsButtons = new Map(); this._applicationsButtons = new Map();
this.reloadFlag = false; this.reloadFlag = false;
this._createLayout(); this._createLayout();
this._display(); this._display();
this._installedChangedId = appSys.connect('installed-changed', appSys.connectObject('installed-changed',
this._onTreeChanged.bind(this)); () => this._onTreeChanged(), this);
} }
_onTreeChanged() { _onTreeChanged() {
@@ -442,11 +437,7 @@ class ApplicationsButton extends PanelMenu.Button {
_onDestroy() { _onDestroy() {
super._onDestroy(); super._onDestroy();
Main.overview.disconnect(this._showingId); delete this._tree;
Main.overview.disconnect(this._hidingId);
appSys.disconnect(this._installedChangedId);
this._tree.disconnect(this._treeChangedId);
this._tree = null;
Main.wm.removeKeybinding('apps-menu-toggle-menu'); Main.wm.removeKeybinding('apps-menu-toggle-menu');
@@ -677,22 +668,17 @@ class ApplicationsButton extends PanelMenu.Button {
} }
} }
let appsMenuButton; export default class AppsMenuExtension extends Extension {
enable() {
this._appsMenuButton = new ApplicationsButton();
const index = Main.sessionMode.panel.left.indexOf('activities') + 1;
Main.panel.addToStatusArea(
'apps-menu', this._appsMenuButton, index, 'left');
}
/** */ disable() {
function enable() { Main.panel.menuManager.removeMenu(this._appsMenuButton.menu);
appsMenuButton = new ApplicationsButton(); this._appsMenuButton.destroy();
let index = Main.sessionMode.panel.left.indexOf('activities') + 1; delete this._appsMenuButton;
Main.panel.addToStatusArea('apps-menu', appsMenuButton, index, 'left'); }
}
/** */
function disable() {
Main.panel.menuManager.removeMenu(appsMenuButton.menu);
appsMenuButton.destroy();
}
/** */
function init() {
ExtensionUtils.initTranslations();
} }
+46 -61
View File
@@ -1,22 +1,20 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// Start apps on custom workspaces // Start apps on custom workspaces
/* exported init enable disable */
const {Shell} = imports.gi; import Shell from 'gi://Shell';
const ExtensionUtils = imports.misc.extensionUtils; import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
const Main = imports.ui.main; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
class WindowMover { class WindowMover {
constructor() { constructor(settings) {
this._settings = ExtensionUtils.getSettings(); this._settings = settings;
this._appSystem = Shell.AppSystem.get_default(); this._appSystem = Shell.AppSystem.get_default();
this._appConfigs = new Map(); this._appConfigs = new Map();
this._appData = new Map(); this._appData = new Map();
this._appsChangedId = this._appSystem.connectObject('installed-changed',
this._appSystem.connect('installed-changed', () => this._updateAppData(), this);
this._updateAppData.bind(this));
this._settings.connect('changed', this._updateAppConfigs.bind(this)); this._settings.connect('changed', this._updateAppConfigs.bind(this));
this._updateAppConfigs(); this._updateAppConfigs();
@@ -38,7 +36,7 @@ class WindowMover {
let removedApps = [...this._appData.keys()] let removedApps = [...this._appData.keys()]
.filter(a => !ids.includes(a.id)); .filter(a => !ids.includes(a.id));
removedApps.forEach(app => { removedApps.forEach(app => {
app.disconnect(this._appData.get(app).windowsChangedId); app.disconnectObject(this);
this._appData.delete(app); this._appData.delete(app);
}); });
@@ -46,21 +44,14 @@ class WindowMover {
.map(id => this._appSystem.lookup_app(id)) .map(id => this._appSystem.lookup_app(id))
.filter(app => app && !this._appData.has(app)); .filter(app => app && !this._appData.has(app));
addedApps.forEach(app => { addedApps.forEach(app => {
let data = { app.connectObject('window-changed',
windowsChangedId: app.connect('windows-changed', this._appWindowsChanged.bind(this), this);
this._appWindowsChanged.bind(this)), this._appData.set(app, {windows: app.get_windows()});
moveWindowsId: 0,
windows: app.get_windows(),
};
this._appData.set(app, data);
}); });
} }
destroy() { destroy() {
if (this._appsChangedId) { this._appSystem.disconnectObject(this);
this._appSystem.disconnect(this._appsChangedId);
this._appsChangedId = 0;
}
if (this._settings) { if (this._settings) {
this._settings.run_dispose(); this._settings.run_dispose();
@@ -105,47 +96,41 @@ class WindowMover {
} }
} }
let prevCheckWorkspaces; export default class AutoMoveExtension extends Extension {
let winMover; enable() {
this._prevCheckWorkspaces = Main.wm._workspaceTracker._checkWorkspaces;
/** */ Main.wm._workspaceTracker._checkWorkspaces =
function init() { this._getCheckWorkspaceOverride(this._prevCheckWorkspaces);
ExtensionUtils.initTranslations(); this._windowMover = new WindowMover(this.getSettings());
}
/**
* @returns {bool} - false (used as MetaLater handler)
*/
function myCheckWorkspaces() {
let keepAliveWorkspaces = [];
let foundNonEmpty = false;
for (let i = this._workspaces.length - 1; i >= 0; i--) {
if (!foundNonEmpty) {
foundNonEmpty = this._workspaces[i].list_windows().some(
w => !w.is_on_all_workspaces());
} else if (!this._workspaces[i]._keepAliveId) {
keepAliveWorkspaces.push(this._workspaces[i]);
}
} }
// make sure the original method only removes empty workspaces at the end disable() {
keepAliveWorkspaces.forEach(ws => (ws._keepAliveId = 1)); Main.wm._workspaceTracker._checkWorkspaces = this._prevCheckWorkspaces;
prevCheckWorkspaces.call(this); this._windowMover.destroy();
keepAliveWorkspaces.forEach(ws => delete ws._keepAliveId); delete this._windowMover;
}
return false; _getCheckWorkspaceOverride(originalMethod) {
} /* eslint-disable no-invalid-this */
return function () {
/** */ const keepAliveWorkspaces = [];
function enable() { let foundNonEmpty = false;
prevCheckWorkspaces = Main.wm._workspaceTracker._checkWorkspaces; for (let i = this._workspaces.length - 1; i >= 0; i--) {
Main.wm._workspaceTracker._checkWorkspaces = myCheckWorkspaces; if (!foundNonEmpty) {
foundNonEmpty = this._workspaces[i].list_windows().some(
winMover = new WindowMover(); w => !w.is_on_all_workspaces());
} } else if (!this._workspaces[i]._keepAliveId) {
keepAliveWorkspaces.push(this._workspaces[i]);
/** */ }
function disable() { }
Main.wm._workspaceTracker._checkWorkspaces = prevCheckWorkspaces;
winMover.destroy(); // make sure the original method only removes empty workspaces at the end
keepAliveWorkspaces.forEach(ws => (ws._keepAliveId = 1));
originalMethod.call(this);
keepAliveWorkspaces.forEach(ws => delete ws._keepAliveId);
return false;
};
/* eslint-enable no-invalid-this */
}
} }
+19 -22
View File
@@ -1,12 +1,13 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// Start apps on custom workspaces // Start apps on custom workspaces
/* exported init buildPrefsWidget */
const {Adw, Gio, GLib, GObject, Gtk} = imports.gi; import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
const ExtensionUtils = imports.misc.extensionUtils; import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
const _ = ExtensionUtils.gettext;
const SETTINGS_KEY = 'application-list'; const SETTINGS_KEY = 'application-list';
@@ -59,13 +60,14 @@ class RulesList extends GObject.Object {
GObject.registerClass(this); GObject.registerClass(this);
} }
#settings = ExtensionUtils.getSettings(); #settings;
#rules = []; #rules = [];
#changedId; #changedId;
constructor() { constructor(settings) {
super(); super();
this.#settings = settings;
this.#changedId = this.#changedId =
this.#settings.connect(`changed::${SETTINGS_KEY}`, this.#settings.connect(`changed::${SETTINGS_KEY}`,
() => this.#sync()); () => this.#sync());
@@ -147,12 +149,13 @@ class AutoMoveSettingsWidget extends Adw.PreferencesGroup {
(self, name, param) => self._rules.changeWorkspace(...param.deepUnpack())); (self, name, param) => self._rules.changeWorkspace(...param.deepUnpack()));
} }
constructor() { constructor(settings) {
super({ super({
title: _('Workspace Rules'), title: _('Workspace Rules'),
}); });
this._rules = new RulesList(); this._settings = settings;
this._rules = new RulesList(this._settings);
const store = new Gio.ListStore({item_type: Gio.ListModel}); const store = new Gio.ListStore({item_type: Gio.ListModel});
const listModel = new Gtk.FlattenListModel({model: store}); const listModel = new Gtk.FlattenListModel({model: store});
@@ -173,7 +176,7 @@ class AutoMoveSettingsWidget extends Adw.PreferencesGroup {
} }
_addNewRule() { _addNewRule() {
const dialog = new NewRuleDialog(this.get_root()); const dialog = new NewRuleDialog(this.get_root(), this._settings);
dialog.connect('response', (dlg, id) => { dialog.connect('response', (dlg, id) => {
const appInfo = id === Gtk.ResponseType.OK const appInfo = id === Gtk.ResponseType.OK
? dialog.get_widget().get_app_info() : null; ? dialog.get_widget().get_app_info() : null;
@@ -312,13 +315,13 @@ class NewRuleDialog extends Gtk.AppChooserDialog {
GObject.registerClass(this); GObject.registerClass(this);
} }
constructor(parent) { constructor(parent, settings) {
super({ super({
transient_for: parent, transient_for: parent,
modal: true, modal: true,
}); });
this._settings = ExtensionUtils.getSettings(); this._settings = settings;
this.get_widget().set({ this.get_widget().set({
show_all: true, show_all: true,
@@ -338,14 +341,8 @@ class NewRuleDialog extends Gtk.AppChooserDialog {
} }
} }
/** */ export default class AutoMovePrefs extends ExtensionPreferences {
function init() { getPreferencesWidget() {
ExtensionUtils.initTranslations(); return new AutoMoveSettingsWidget(this.getSettings());
} }
/**
* @returns {Gtk.Widget} - the prefs widget
*/
function buildPrefsWidget() {
return new AutoMoveSettingsWidget();
} }
+27 -50
View File
@@ -1,14 +1,16 @@
/* exported init enable disable */
// Drive menu extension // Drive menu extension
const {Clutter, Gio, GObject, Shell, St} = imports.gi; import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Shell from 'gi://Shell';
import St from 'gi://St';
const ExtensionUtils = imports.misc.extensionUtils; import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const ShellMountOperation = imports.ui.shellMountOperation;
const _ = ExtensionUtils.gettext; 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';
import * as ShellMountOperation from 'resource:///org/gnome/shell/ui/shellMountOperation.js';
Gio._promisify(Gio.File.prototype, 'query_filesystem_info_async'); Gio._promisify(Gio.File.prototype, 'query_filesystem_info_async');
@@ -47,19 +49,11 @@ class MountMenuItem extends PopupMenu.PopupBaseMenuItem {
this.hide(); this.hide();
this._changedId = mount.connect('changed', this._syncVisibility.bind(this)); mount.connectObject('changed',
() => this._syncVisibility(), this);
this._syncVisibility(); this._syncVisibility();
} }
_onDestroy() {
if (this._changedId) {
this.mount.disconnect(this._changedId);
this._changedId = 0;
}
super.destroy();
}
async _isInteresting() { async _isInteresting() {
if (!this.mount.can_eject() && !this.mount.can_unmount()) if (!this.mount.can_eject() && !this.mount.can_unmount())
return false; return false;
@@ -152,12 +146,12 @@ class DriveMenu extends PanelMenu.Button {
this.add_child(icon); this.add_child(icon);
this._monitor = Gio.VolumeMonitor.get(); this._monitor = Gio.VolumeMonitor.get();
this._addedId = this._monitor.connect('mount-added', this._monitor.connectObject(
(monitor, mount) => this._addMount(mount)); 'mount-added', (monitor, mount) => this._addMount(mount),
this._removedId = this._monitor.connect('mount-removed', (monitor, mount) => { 'mount-removed', (monitor, mount) => {
this._removeMount(mount); this._removeMount(mount);
this._updateMenuVisibility(); this._updateMenuVisibility();
}); }, this);
this._mounts = []; this._mounts = [];
@@ -199,33 +193,16 @@ class DriveMenu extends PanelMenu.Button {
} }
log('Removing a mount that was never added to the menu'); log('Removing a mount that was never added to the menu');
} }
}
_onDestroy() { export default class PlaceMenuExtension extends Extension {
if (this._addedId) { enable() {
this._monitor.disconnect(this._addedId); this._indicator = new DriveMenu();
this._monitor.disconnect(this._removedId); Main.panel.addToStatusArea('drive-menu', this._indicator);
this._addedId = 0; }
this._removedId = 0;
}
super._onDestroy(); disable() {
this._indicator.destroy();
delete this._indicator;
} }
} }
/** */
function init() {
ExtensionUtils.initTranslations();
}
let _indicator;
/** */
function enable() {
_indicator = new DriveMenu();
Main.panel.addToStatusArea('drive-menu', _indicator);
}
/** */
function disable() {
_indicator.destroy();
}
+19 -14
View File
@@ -1,17 +1,22 @@
/* exported enable disable */ import {AppIcon} from 'resource:///org/gnome/shell/ui/appDisplay.js';
const AppDisplay = imports.ui.appDisplay; import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
let _activateOriginal = null; export default class Extension {
constructor() {
this._injectionManager = new InjectionManager();
}
/** */ enable() {
function enable() { this._injectionManager.overrideMethod(AppIcon.prototype, 'activate',
_activateOriginal = AppDisplay.AppIcon.prototype.activate; originalMethod => {
AppDisplay.AppIcon.prototype.activate = function () { return function () {
_activateOriginal.call(this, 2); // eslint-disable-next-line no-invalid-this
}; originalMethod.call(this, 2);
} };
});
/** */ }
function disable() {
AppDisplay.AppIcon.prototype.activate = _activateOriginal; disable() {
this._injectionManager.clear();
}
} }
+3 -9
View File
@@ -1,4 +1,3 @@
/* exported init */
/* /*
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -16,11 +15,11 @@
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
*/ */
const {St} = imports.gi; import St from 'gi://St';
const Main = imports.ui.main; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
class Extension { export default class Extension {
_updateColorScheme(scheme) { _updateColorScheme(scheme) {
Main.sessionMode.colorScheme = scheme; Main.sessionMode.colorScheme = scheme;
St.Settings.get().notify('color-scheme'); St.Settings.get().notify('color-scheme');
@@ -35,8 +34,3 @@ class Extension {
this._updateColorScheme(this._savedColorScheme); this._updateColorScheme(this._savedColorScheme);
} }
} }
/** */
function init() {
return new Extension();
}
+65 -76
View File
@@ -1,11 +1,11 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported enable disable */ import Clutter from 'gi://Clutter';
const {Clutter} = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils; import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
const Main = imports.ui.main;
const {WindowPreview} = imports.ui.windowPreview; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Workspace = imports.ui.workspace; import {WindowPreview} from 'resource:///org/gnome/shell/ui/windowPreview.js';
import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js';
// testing settings for natural window placement strategy: // testing settings for natural window placement strategy:
const WINDOW_PLACEMENT_NATURAL_ACCURACY = 20; // accuracy of window translate moves (KDE-default: 20) const WINDOW_PLACEMENT_NATURAL_ACCURACY = 20; // accuracy of window translate moves (KDE-default: 20)
@@ -236,75 +236,64 @@ class NaturalLayoutStrategy extends Workspace.LayoutStrategy {
} }
} }
let winInjections, workspaceInjections; export default class NativeWindowPlacementExtension extends Extension {
constructor(metadata) {
super(metadata);
/** */ this._injectionManager = new InjectionManager();
function resetState() { }
winInjections = { };
workspaceInjections = { }; enable() {
} const settings = this.getSettings();
/** */ const layoutProto = Workspace.WorkspaceLayout.prototype;
function enable() { const previewProto = WindowPreview.prototype;
resetState();
this._injectionManager.overrideMethod(layoutProto, '_createBestLayout', () => {
let settings = ExtensionUtils.getSettings(); /* eslint-disable no-invalid-this */
return function () {
workspaceInjections['_createBestLayout'] = Workspace.WorkspaceLayout.prototype._createBestLayout; this._layoutStrategy = new NaturalLayoutStrategy({
Workspace.WorkspaceLayout.prototype._createBestLayout = function (_area) { monitor: Main.layoutManager.monitors[this._monitorIndex],
this._layoutStrategy = new NaturalLayoutStrategy({ }, settings);
monitor: Main.layoutManager.monitors[this._monitorIndex], return this._layoutStrategy.computeLayout(this._sortedWindows);
}, settings); };
return this._layoutStrategy.computeLayout(this._sortedWindows); /* eslint-enable no-invalid-this */
}; });
// position window titles on top of windows in overlay // position window titles on top of windows in overlay
winInjections['_init'] = WindowPreview.prototype._init; this._injectionManager.overrideMethod(previewProto, '_init', originalMethod => {
WindowPreview.prototype._init = function (...args) { /* eslint-disable no-invalid-this */
winInjections['_init'].call(this, ...args); return function (...args) {
originalMethod.call(this, ...args);
if (!settings.get_boolean('window-captions-on-top'))
return; if (!settings.get_boolean('window-captions-on-top'))
return;
const alignConstraint = this._title.get_constraints().find(
c => c.align_axis && c.align_axis === Clutter.AlignAxis.Y_AXIS); const alignConstraint = this._title.get_constraints().find(
alignConstraint.factor = 0; c => c.align_axis && c.align_axis === Clutter.AlignAxis.Y_AXIS);
alignConstraint.factor = 0;
const bindConstraint = this._title.get_constraints().find(
c => c.coordinate && c.coordinate === Clutter.BindCoordinate.Y); const bindConstraint = this._title.get_constraints().find(
bindConstraint.offset = 0; c => c.coordinate && c.coordinate === Clutter.BindCoordinate.Y);
}; bindConstraint.offset = 0;
winInjections['_adjustOverlayOffsets'] = };
WindowPreview.prototype._adjustOverlayOffsets; /* eslint-enable no-invalid-this */
WindowPreview.prototype._adjustOverlayOffsets = function (...args) { });
winInjections['_adjustOverlayOffsets'].call(this, ...args);
this._injectionManager.overrideMethod(previewProto, '_adjustOverlayOffsets', originalMethod => {
if (settings.get_boolean('window-captions-on-top')) /* eslint-disable no-invalid-this */
this._title.translation_y = -this._title.translation_y; return function (...args) {
}; originalMethod.call(this, ...args);
}
if (settings.get_boolean('window-captions-on-top'))
/** this._title.translation_y = -this._title.translation_y;
* @param {object} object - object that was modified };
* @param {object} injection - the map of previous injections /* eslint-enable no-invalid-this */
* @param {string} name - the @injection key that should be removed });
*/ }
function removeInjection(object, injection, name) {
if (injection[name] === undefined) disable() {
delete object[name]; this._injectionManager.clear();
else global.stage.queue_relayout();
object[name] = injection[name]; }
}
/** */
function disable() {
var i;
for (i in workspaceInjections)
removeInjection(Workspace.WorkspaceLayout.prototype, workspaceInjections, i);
for (i in winInjections)
removeInjection(WindowPreview.prototype, winInjections, i);
global.stage.queue_relayout();
resetState();
} }
+25 -41
View File
@@ -1,17 +1,16 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported init enable disable */ import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import St from 'gi://St';
const {Clutter, GObject, St} = imports.gi; import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const ExtensionUtils = imports.misc.extensionUtils; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Main = imports.ui.main; import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
const PanelMenu = imports.ui.panelMenu; import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const PopupMenu = imports.ui.popupMenu;
const Me = ExtensionUtils.getCurrentExtension(); import {PlacesManager} from './placeDisplay.js';
const PlaceDisplay = Me.imports.placeDisplay;
const _ = ExtensionUtils.gettext;
const N_ = x => x; const N_ = x => x;
const PLACE_ICON_SIZE = 16; const PLACE_ICON_SIZE = 16;
@@ -53,17 +52,8 @@ class PlaceMenuItem extends PopupMenu.PopupBaseMenuItem {
this.add_child(this._ejectButton); this.add_child(this._ejectButton);
} }
this._changedId = info.connect('changed', info.connectObject('changed',
this._propertiesChanged.bind(this)); this._propertiesChanged.bind(this), this);
}
destroy() {
if (this._changedId) {
this._info.disconnect(this._changedId);
this._changedId = 0;
}
super.destroy();
} }
activate(event) { activate(event) {
@@ -100,7 +90,7 @@ class PlacesMenu extends PanelMenu.Button {
}); });
this.add_actor(label); this.add_actor(label);
this.placesManager = new PlaceDisplay.PlacesManager(); this.placesManager = new PlacesManager();
this._sections = { }; this._sections = { };
@@ -138,24 +128,18 @@ class PlacesMenu extends PanelMenu.Button {
} }
} }
/** */ export default class PlacesMenuExtension extends Extension {
function init() { enable() {
ExtensionUtils.initTranslations(); this._indicator = new PlacesMenu();
}
let pos = Main.sessionMode.panel.left.length;
let _indicator; if ('apps-menu' in Main.panel.statusArea)
pos++;
/** */ Main.panel.addToStatusArea('places-menu', this._indicator, pos, 'left');
function enable() { }
_indicator = new PlacesMenu();
disable() {
let pos = Main.sessionMode.panel.left.length; this._indicator.destroy();
if ('apps-menu' in Main.panel.statusArea) delete this._indicator;
pos++; }
Main.panel.addToStatusArea('places-menu', _indicator, pos, 'left');
}
/** */
function disable() {
_indicator.destroy();
} }
+24 -37
View File
@@ -1,14 +1,14 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported PlacesManager */ import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import Shell from 'gi://Shell';
import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
const {Gio, GLib, Shell} = imports.gi; import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const {EventEmitter} = imports.misc.signals;
const ExtensionUtils = imports.misc.extensionUtils; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Main = imports.ui.main; import * as ShellMountOperation from 'resource:///org/gnome/shell/ui/shellMountOperation.js';
const ShellMountOperation = imports.ui.shellMountOperation;
const _ = ExtensionUtils.gettext;
const N_ = x => x; const N_ = x => x;
Gio._promisify(Gio.AppInfo, 'launch_default_for_uri_async'); Gio._promisify(Gio.AppInfo, 'launch_default_for_uri_async');
@@ -248,7 +248,7 @@ const DEFAULT_DIRECTORIES = [
GLib.UserDirectory.DIRECTORY_VIDEOS, GLib.UserDirectory.DIRECTORY_VIDEOS,
]; ];
var PlacesManager = class extends EventEmitter { export class PlacesManager extends EventEmitter {
constructor() { constructor() {
super(); super();
@@ -260,15 +260,25 @@ var PlacesManager = class extends EventEmitter {
}; };
this._settings = new Gio.Settings({schema_id: BACKGROUND_SCHEMA}); this._settings = new Gio.Settings({schema_id: BACKGROUND_SCHEMA});
this._showDesktopIconsChangedId = this._settings.connect( this._settings.connectObject('changed::show-desktop-icons',
'changed::show-desktop-icons', this._updateSpecials.bind(this)); () => this._updateSpecials(), this);
this._updateSpecials(); this._updateSpecials();
/* /*
* Show devices, code more or less ported from nautilus-places-sidebar.c * Show devices, code more or less ported from nautilus-places-sidebar.c
*/ */
this._volumeMonitor = Gio.VolumeMonitor.get(); this._volumeMonitor = Gio.VolumeMonitor.get();
this._connectVolumeMonitorSignals(); this._volumeMonitor.connectObject(
'volume-added', () => this._updateMounts(),
'volume-removed', () => this._updateMounts(),
'volume-changed', () => this._updateMounts(),
'mount-added', () => this._updateMounts(),
'mount-removed', () => this._updateMounts(),
'mount-changed', () => this._updateMounts(),
'drive-connected', () => this._updateMounts(),
'drive-disconnected', () => this._updateMounts(),
'drive-changed', () => this._updateMounts(),
this);
this._updateMounts(); this._updateMounts();
this._bookmarksFile = this._findBookmarksFile(); this._bookmarksFile = this._findBookmarksFile();
@@ -293,34 +303,11 @@ var PlacesManager = class extends EventEmitter {
} }
} }
_connectVolumeMonitorSignals() {
const signals = [
'volume-added',
'volume-removed',
'volume-changed',
'mount-added',
'mount-removed',
'mount-changed',
'drive-connected',
'drive-disconnected',
'drive-changed',
];
this._volumeMonitorSignals = [];
let func = this._updateMounts.bind(this);
for (let i = 0; i < signals.length; i++) {
let id = this._volumeMonitor.connect(signals[i], func);
this._volumeMonitorSignals.push(id);
}
}
destroy() { destroy() {
if (this._settings) this._settings?.disconnectObject(this);
this._settings.disconnect(this._showDesktopIconsChangedId);
this._settings = null; this._settings = null;
for (let i = 0; i < this._volumeMonitorSignals.length; i++) this._volumeMonitor.disconnectObject(this);
this._volumeMonitor.disconnect(this._volumeMonitorSignals[i]);
if (this._monitor) if (this._monitor)
this._monitor.cancel(); this._monitor.cancel();
@@ -546,4 +533,4 @@ var PlacesManager = class extends EventEmitter {
get(kind) { get(kind) {
return this._places[kind]; return this._places[kind];
} }
}; }
+137 -140
View File
@@ -1,4 +1,3 @@
/* exported enable disable */
/* Screenshot Window Sizer for Gnome Shell /* Screenshot Window Sizer for Gnome Shell
* *
* Copyright (c) 2013 Owen Taylor <otaylor@redhat.com> * Copyright (c) 2013 Owen Taylor <otaylor@redhat.com>
@@ -19,153 +18,151 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
const {Clutter, Meta, Shell, St} = imports.gi; import Clutter from 'gi://Clutter';
import Meta from 'gi://Meta';
import Shell from 'gi://Shell';
import St from 'gi://St';
const ExtensionUtils = imports.misc.extensionUtils; import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
const Main = imports.ui.main;
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const MESSAGE_FADE_TIME = 2000; const MESSAGE_FADE_TIME = 2000;
let text; export default class ScreenshotWindowSizerExtension extends Extension {
SIZES = [
[624, 351],
[800, 450],
[1024, 576],
[1200, 675],
[1600, 900],
[360, 654], // Phone portrait maximized
[720, 360], // Phone landscape fullscreen
];
/** */ _flashMessage(message) {
function hideMessage() { if (!this._text) {
text.destroy(); this._text = new St.Label({style_class: 'screenshot-sizer-message'});
text = null; Main.uiGroup.add_actor(this._text);
}
/**
* @param {string} message - the message to flash
*/
function flashMessage(message) {
if (!text) {
text = new St.Label({style_class: 'screenshot-sizer-message'});
Main.uiGroup.add_actor(text);
}
text.remove_all_transitions();
text.text = message;
text.opacity = 255;
let monitor = Main.layoutManager.primaryMonitor;
text.set_position(
monitor.x + Math.floor(monitor.width / 2 - text.width / 2),
monitor.y + Math.floor(monitor.height / 2 - text.height / 2));
text.ease({
opacity: 0,
duration: MESSAGE_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: hideMessage,
});
}
let SIZES = [
[624, 351],
[800, 450],
[1024, 576],
[1200, 675],
[1600, 900],
[360, 654], // Phone portrait maximized
[720, 360], // Phone landscape fullscreen
];
/**
* @param {Meta.Display} display - the display
* @param {Meta.Window=} window - for per-window bindings, the window
* @param {Meta.KeyBinding} binding - the key binding
*/
function 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;
// Unmaximize first
if (window.get_maximized() !== 0)
window.unmaximize(Meta.MaximizeFlags.BOTH);
let workArea = window.get_work_area_current_monitor();
let outerRect = window.get_frame_rect();
// Double both axes if on a hidpi display
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let scaledSizes = SIZES.map(size => size.map(wh => wh * scaleFactor))
.filter(([w, h]) => w <= workArea.width && h <= workArea.height);
// Find the nearest 16:9 size for the current window size
let nearestIndex;
let nearestError;
for (let i = 0; i < scaledSizes.length; i++) {
let [width, height] = scaledSizes[i];
// get the best initial window size
let error = Math.abs(width - outerRect.width) + Math.abs(height - outerRect.height);
if (nearestIndex === undefined || error < nearestError) {
nearestIndex = i;
nearestError = error;
} }
this._text.remove_all_transitions();
this._text.text = message;
this._text.opacity = 255;
const monitor = Main.layoutManager.primaryMonitor;
this._text.set_position(
monitor.x + Math.floor(monitor.width / 2 - this._text.width / 2),
monitor.y + Math.floor(monitor.height / 2 - this._text.height / 2));
this._text.ease({
opacity: 0,
duration: MESSAGE_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._hideMessage(),
});
} }
// get the next size up or down from ideal _hideMessage() {
let newIndex = (nearestIndex + (backwards ? -1 : 1)) % scaledSizes.length; this._text.destroy();
let [newWidth, newHeight] = scaledSizes[newIndex]; delete this._text;
}
// Push the window onscreen if it would be resized offscreen /**
let newX = outerRect.x; * @param {Meta.Display} display - the display
let newY = outerRect.y; * @param {Meta.Window=} window - for per-window bindings, the window
if (newX + newWidth > workArea.x + workArea.width) * @param {Meta.KeyBinding} binding - the key binding
newX = Math.max(workArea.x + workArea.width - newWidth); */
if (newY + newHeight > workArea.y + workArea.height) _cycleScreenshotSizes(display, window, binding) {
newY = Math.max(workArea.y + workArea.height - newHeight); // 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 id = window.connect('size-changed', () => { // Unmaximize first
window.disconnect(id); if (window.get_maximized() !== 0)
_notifySizeChange(window); window.unmaximize(Meta.MaximizeFlags.BOTH);
});
window.move_resize_frame(true, newX, newY, newWidth, newHeight); let workArea = window.get_work_area_current_monitor();
} let outerRect = window.get_frame_rect();
/** // Double both axes if on a hidpi display
* @param {Meta.Window} window - the window whose size changed let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
*/ let scaledSizes = this.SIZES.map(size => size.map(wh => wh * scaleFactor))
function _notifySizeChange(window) { .filter(([w, h]) => w <= workArea.width && h <= workArea.height);
const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage);
let newOuterRect = window.get_frame_rect(); // Find the nearest 16:9 size for the current window size
let message = '%d×%d'.format( let nearestIndex;
newOuterRect.width / scaleFactor, let nearestError;
newOuterRect.height / scaleFactor);
for (let i = 0; i < scaledSizes.length; i++) {
// The new size might have been constrained by geometry hints (e.g. for let [width, height] = scaledSizes[i];
// a terminal) - in that case, include the actual ratio to the message
// we flash // get the best initial window size
let actualNumerator = 9 * newOuterRect.width / newOuterRect.height; let error = Math.abs(width - outerRect.width) + Math.abs(height - outerRect.height);
if (Math.abs(actualNumerator - 16) > 0.01) if (nearestIndex === undefined || error < nearestError) {
message += ' (%.2f:9)'.format(actualNumerator); nearestIndex = i;
nearestError = error;
flashMessage(message); }
} }
/** */ // get the next size up or down from ideal
function enable() { let newIndex = (nearestIndex + (backwards ? -1 : 1)) % scaledSizes.length;
Main.wm.addKeybinding( let [newWidth, newHeight] = scaledSizes[newIndex];
'cycle-screenshot-sizes',
ExtensionUtils.getSettings(), // Push the window onscreen if it would be resized offscreen
Meta.KeyBindingFlags.PER_WINDOW, let newX = outerRect.x;
Shell.ActionMode.NORMAL, let newY = outerRect.y;
cycleScreenshotSizes); if (newX + newWidth > workArea.x + workArea.width)
Main.wm.addKeybinding( newX = Math.max(workArea.x + workArea.width - newWidth);
'cycle-screenshot-sizes-backward', if (newY + newHeight > workArea.y + workArea.height)
ExtensionUtils.getSettings(), newY = Math.max(workArea.y + workArea.height - newHeight);
Meta.KeyBindingFlags.PER_WINDOW | Meta.KeyBindingFlags.IS_REVERSED,
Shell.ActionMode.NORMAL, const id = window.connect('size-changed', () => {
cycleScreenshotSizes); window.disconnect(id);
} this._notifySizeChange(window);
});
/** */ window.move_resize_frame(true, newX, newY, newWidth, newHeight);
function disable() { }
Main.wm.removeKeybinding('cycle-screenshot-sizes');
Main.wm.removeKeybinding('cycle-screenshot-sizes-backward'); /**
* @param {Meta.Window} window - the window whose size changed
*/
_notifySizeChange(window) {
const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage);
let newOuterRect = window.get_frame_rect();
let message = '%d×%d'.format(
newOuterRect.width / scaleFactor,
newOuterRect.height / scaleFactor);
// The new size might have been constrained by geometry hints (e.g. for
// a terminal) - in that case, include the actual ratio to the message
// we flash
let actualNumerator = 9 * newOuterRect.width / newOuterRect.height;
if (Math.abs(actualNumerator - 16) > 0.01)
message += ' (%.2f:9)'.format(actualNumerator);
this._flashMessage(message);
}
enable() {
Main.wm.addKeybinding(
'cycle-screenshot-sizes',
this.getSettings(),
Meta.KeyBindingFlags.PER_WINDOW,
Shell.ActionMode.NORMAL,
this._cycleScreenshotSizes.bind(this));
Main.wm.addKeybinding(
'cycle-screenshot-sizes-backward',
this.getSettings(),
Meta.KeyBindingFlags.PER_WINDOW | Meta.KeyBindingFlags.IS_REVERSED,
Shell.ActionMode.NORMAL,
this._cycleScreenshotSizes.bind(this));
}
disable() {
Main.wm.removeKeybinding('cycle-screenshot-sizes');
Main.wm.removeKeybinding('cycle-screenshot-sizes-backward');
}
} }
+11 -19
View File
@@ -1,20 +1,19 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
// Load shell theme from ~/.local/share/themes/name/gnome-shell // Load shell theme from ~/.local/share/themes/name/gnome-shell
/* exported init */
const {Gio} = imports.gi; import Gio from 'gi://Gio';
const ExtensionUtils = imports.misc.extensionUtils; import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
const Main = imports.ui.main;
const Me = ExtensionUtils.getCurrentExtension(); import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Util = Me.imports.util;
import {getThemeDirs, getModeThemeDirs} from './util.js';
const SETTINGS_KEY = 'name'; const SETTINGS_KEY = 'name';
class ThemeManager { export default class ThemeManager extends Extension {
enable() { enable() {
this._settings = ExtensionUtils.getSettings(); this._settings = this.getSettings();
this._settings.connect(`changed::${SETTINGS_KEY}`, this._changeTheme.bind(this)); this._settings.connect(`changed::${SETTINGS_KEY}`, this._changeTheme.bind(this));
this._changeTheme(); this._changeTheme();
} }
@@ -32,10 +31,10 @@ class ThemeManager {
let themeName = this._settings.get_string(SETTINGS_KEY); let themeName = this._settings.get_string(SETTINGS_KEY);
if (themeName) { if (themeName) {
const stylesheetPaths = Util.getThemeDirs() const stylesheetPaths = getThemeDirs()
.map(dir => `${dir}/${themeName}/gnome-shell/gnome-shell.css`); .map(dir => `${dir}/${themeName}/gnome-shell/gnome-shell.css`);
stylesheetPaths.push(...Util.getModeThemeDirs() stylesheetPaths.push(...getModeThemeDirs()
.map(dir => `${dir}/${themeName}.css`)); .map(dir => `${dir}/${themeName}.css`));
stylesheet = stylesheetPaths.find(path => { stylesheet = stylesheetPaths.find(path => {
@@ -45,17 +44,10 @@ class ThemeManager {
} }
if (stylesheet) if (stylesheet)
global.log(`loading user theme: ${stylesheet}`); log(`loading user theme: ${stylesheet}`);
else else
global.log('loading default theme (Adwaita)'); log('loading default theme (Adwaita)');
Main.setThemeStylesheet(stylesheet); Main.setThemeStylesheet(stylesheet);
Main.loadTheme(); Main.loadTheme();
} }
} }
/**
* @returns {ThemeManager} - the extension state object
*/
function init() {
return new ThemeManager();
}
+15 -18
View File
@@ -1,15 +1,17 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init buildPrefsWidget */
// we use async/await here to not block the mainloop, not to parallelize // we use async/await here to not block the mainloop, not to parallelize
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const {Adw, Gio, GLib, GObject, Gtk} = imports.gi; import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
const ExtensionUtils = imports.misc.extensionUtils; import {ExtensionPreferences} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
const Me = ExtensionUtils.getCurrentExtension(); import {getThemeDirs, getModeThemeDirs} from './util.js';
const Util = Me.imports.util;
Gio._promisify(Gio.File.prototype, 'enumerate_children_async'); Gio._promisify(Gio.File.prototype, 'enumerate_children_async');
Gio._promisify(Gio.File.prototype, 'query_info_async'); Gio._promisify(Gio.File.prototype, 'query_info_async');
@@ -20,13 +22,13 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
GObject.registerClass(this); GObject.registerClass(this);
} }
constructor() { constructor(settings) {
super({title: 'Themes'}); super({title: 'Themes'});
this._actionGroup = new Gio.SimpleActionGroup(); this._actionGroup = new Gio.SimpleActionGroup();
this.insert_action_group('theme', this._actionGroup); this.insert_action_group('theme', this._actionGroup);
this._settings = ExtensionUtils.getSettings(); this._settings = settings;
this._actionGroup.add_action( this._actionGroup.add_action(
this._settings.create_action('name')); this._settings.create_action('name'));
@@ -39,7 +41,7 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
} }
async _collectThemes() { async _collectThemes() {
for (const dirName of Util.getThemeDirs()) { for (const dirName of getThemeDirs()) {
const dir = Gio.File.new_for_path(dirName); const dir = Gio.File.new_for_path(dirName);
for (const name of await this._enumerateDir(dir)) { for (const name of await this._enumerateDir(dir)) {
if (this._rows.has(name)) if (this._rows.has(name))
@@ -60,7 +62,7 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
} }
} }
for (const dirName of Util.getModeThemeDirs()) { for (const dirName of getModeThemeDirs()) {
const dir = Gio.File.new_for_path(dirName); const dir = Gio.File.new_for_path(dirName);
for (const filename of await this._enumerateDir(dir)) { for (const filename of await this._enumerateDir(dir)) {
if (!filename.endsWith('.css')) if (!filename.endsWith('.css'))
@@ -125,13 +127,8 @@ class ThemeRow extends Adw.ActionRow {
} }
} }
/** */ export default class UserThemePrefs extends ExtensionPreferences {
function init() { getPreferencesWidget() {
} return new UserThemePrefsWidget(this.getSettings());
}
/**
* @returns {Gtk.Widget} - the prefs widget
*/
function buildPrefsWidget() {
return new UserThemePrefsWidget();
} }
+3 -4
View File
@@ -1,12 +1,11 @@
/* exported getThemeDirs getModeThemeDirs */ import GLib from 'gi://GLib';
const {GLib} = imports.gi;
const fn = (...args) => GLib.build_filenamev(args); const fn = (...args) => GLib.build_filenamev(args);
/** /**
* @returns {string[]} - an ordered list of theme directories * @returns {string[]} - an ordered list of theme directories
*/ */
function getThemeDirs() { export function getThemeDirs() {
return [ return [
fn(GLib.get_home_dir(), '.themes'), fn(GLib.get_home_dir(), '.themes'),
fn(GLib.get_user_data_dir(), 'themes'), fn(GLib.get_user_data_dir(), 'themes'),
@@ -17,7 +16,7 @@ function getThemeDirs() {
/** /**
* @returns {string[]} - an ordered list of mode theme directories * @returns {string[]} - an ordered list of mode theme directories
*/ */
function getModeThemeDirs() { export function getModeThemeDirs() {
return GLib.get_system_data_dirs() return GLib.get_system_data_dirs()
.map(dir => fn(dir, 'gnome-shell', 'theme')); .map(dir => fn(dir, 'gnome-shell', 'theme'));
} }
+119 -184
View File
@@ -1,17 +1,21 @@
/* exported init */ import Clutter from 'gi://Clutter';
const {Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St} = imports.gi; 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 Shell from 'gi://Shell';
import St from 'gi://St';
const DND = imports.ui.dnd; import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const Me = ExtensionUtils.getCurrentExtension(); import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
const {WindowPicker, WindowPickerToggle} = Me.imports.windowPicker; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const {WorkspaceIndicator} = Me.imports.workspaceIndicator; import * as Overview from 'resource:///org/gnome/shell/ui/overview.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const _ = ExtensionUtils.gettext; import {WindowPicker, WindowPickerToggle} from './windowPicker.js';
import {WorkspaceIndicator} from './workspaceIndicator.js';
const ICON_TEXTURE_SIZE = 24; const ICON_TEXTURE_SIZE = 24;
const DND_ACTIVATE_TIMEOUT = 500; const DND_ACTIVATE_TIMEOUT = 500;
@@ -51,10 +55,6 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
}); });
this.addMenuItem(this._minimizeItem); this.addMenuItem(this._minimizeItem);
this._notifyMinimizedId = this._metaWindow.connect(
'notify::minimized', this._updateMinimizeItem.bind(this));
this._updateMinimizeItem();
this._maximizeItem = new PopupMenu.PopupMenuItem(''); this._maximizeItem = new PopupMenu.PopupMenuItem('');
this._maximizeItem.connect('activate', () => { this._maximizeItem.connect('activate', () => {
if (this._metaWindow.get_maximized() === Meta.MaximizeFlags.BOTH) if (this._metaWindow.get_maximized() === Meta.MaximizeFlags.BOTH)
@@ -64,21 +64,20 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
}); });
this.addMenuItem(this._maximizeItem); this.addMenuItem(this._maximizeItem);
this._notifyMaximizedHId = this._metaWindow.connect(
'notify::maximized-horizontally',
this._updateMaximizeItem.bind(this));
this._notifyMaximizedVId = this._metaWindow.connect(
'notify::maximized-vertically',
this._updateMaximizeItem.bind(this));
this._updateMaximizeItem();
this._closeItem = new PopupMenu.PopupMenuItem(_('Close')); this._closeItem = new PopupMenu.PopupMenuItem(_('Close'));
this._closeItem.connect('activate', () => { this._closeItem.connect('activate', () => {
this._metaWindow.delete(global.get_current_time()); this._metaWindow.delete(global.get_current_time());
}); });
this.addMenuItem(this._closeItem); this.addMenuItem(this._closeItem);
this.actor.connect('destroy', this._onDestroy.bind(this)); this._metaWindow.connectObject(
'notify::minimized', this._updateMinimizeItem.bind(this),
'notify::maximized-horizontally', this._updateMaximizeItem.bind(this),
'notify::maximized-vertically', this._updateMaximizeItem.bind(this),
this);
this._updateMinimizeItem();
this._updateMaximizeItem();
this.connect('open-state-changed', () => { this.connect('open-state-changed', () => {
if (!this.isOpen) if (!this.isOpen)
@@ -101,12 +100,6 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
this._maximizeItem.label.text = maximized this._maximizeItem.label.text = maximized
? _('Unmaximize') : _('Maximize'); ? _('Unmaximize') : _('Maximize');
} }
_onDestroy() {
this._metaWindow.disconnect(this._notifyMinimizedId);
this._metaWindow.disconnect(this._notifyMaximizedHId);
this._metaWindow.disconnect(this._notifyMaximizedVId);
}
} }
class WindowTitle extends St.BoxLayout { class WindowTitle extends St.BoxLayout {
@@ -130,20 +123,19 @@ class WindowTitle extends St.BoxLayout {
this.add(this.label_actor); this.add(this.label_actor);
this._textureCache = St.TextureCache.get_default(); this._textureCache = St.TextureCache.get_default();
this._iconThemeChangedId = this._textureCache.connect( this._textureCache.connectObject('icon-theme-changed',
'icon-theme-changed', this._updateIcon.bind(this)); () => this._updateIcon(), this);
this._notifyWmClass = this._metaWindow.connect_after(
'notify::wm-class', this._updateIcon.bind(this)); this._metaWindow.connectObject(
this._notifyAppId = this._metaWindow.connect_after( 'notify::wm-class',
'notify::gtk-application-id', this._updateIcon.bind(this)); () => this._updateIcon(), GObject.ConnectFlags.AFTER,
'notify::gtk-application-id',
() => this._updateIcon(), GObject.ConnectFlags.AFTER,
'notify::title', () => this._updateTitle(),
'notify::minimized', () => this._minimizedChanged(),
this);
this._updateIcon(); this._updateIcon();
this.connect('destroy', this._onDestroy.bind(this));
this._notifyTitleId = this._metaWindow.connect(
'notify::title', this._updateTitle.bind(this));
this._notifyMinimizedId = this._metaWindow.connect(
'notify::minimized', this._minimizedChanged.bind(this));
this._minimizedChanged(); this._minimizedChanged();
} }
@@ -173,14 +165,6 @@ class WindowTitle extends St.BoxLayout {
}); });
} }
} }
_onDestroy() {
this._textureCache.disconnect(this._iconThemeChangedId);
this._metaWindow.disconnect(this._notifyTitleId);
this._metaWindow.disconnect(this._notifyMinimizedId);
this._metaWindow.disconnect(this._notifyWmClass);
this._metaWindow.disconnect(this._notifyAppId);
}
} }
class BaseButton extends St.Button { class BaseButton extends St.Button {
@@ -216,16 +200,16 @@ class BaseButton extends St.Button {
this._contextMenuManager = new PopupMenu.PopupMenuManager(this); this._contextMenuManager = new PopupMenu.PopupMenuManager(this);
this._switchWorkspaceId = global.window_manager.connect( global.window_manager.connectObject('switch-workspace',
'switch-workspace', this._updateVisibility.bind(this)); () => this._updateVisibility(), this);
if (this._perMonitor) { if (this._perMonitor) {
this._windowEnteredMonitorId = global.display.connect( global.display.connectObject(
'window-entered-monitor', 'window-entered-monitor',
this._windowEnteredOrLeftMonitor.bind(this)); this._windowEnteredOrLeftMonitor.bind(this),
this._windowLeftMonitorId = global.display.connect(
'window-left-monitor', 'window-left-monitor',
this._windowEnteredOrLeftMonitor.bind(this)); this._windowEnteredOrLeftMonitor.bind(this),
this);
} }
this._tooltip = new Tooltip(this, { this._tooltip = new Tooltip(this, {
@@ -334,9 +318,11 @@ class BaseButton extends St.Button {
if (isOpen) if (isOpen)
return; return;
const extension = Extension.lookupByURL(import.meta.url);
let [x, y] = global.get_pointer(); let [x, y] = global.get_pointer();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y); let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
if (Me.stateObj.someWindowListContains(actor)) if (extension.someWindowListContains(actor))
actor.sync_hover(); actor.sync_hover();
} }
@@ -391,16 +377,6 @@ class BaseButton extends St.Button {
} }
_onDestroy() { _onDestroy() {
global.window_manager.disconnect(this._switchWorkspaceId);
if (this._windowEnteredMonitorId)
global.display.disconnect(this._windowEnteredMonitorId);
this._windowEnteredMonitorId = 0;
if (this._windowLeftMonitorId)
global.display.disconnect(this._windowLeftMonitorId);
this._windowLeftMonitorId = 0;
this._tooltip.destroy(); this._tooltip.destroy();
} }
} }
@@ -414,9 +390,11 @@ class WindowButton extends BaseButton {
super(perMonitor, monitorIndex); super(perMonitor, monitorIndex);
this.metaWindow = metaWindow; this.metaWindow = metaWindow;
this._skipTaskbarId = metaWindow.connect('notify::skip-taskbar', () => { metaWindow.connectObject(
this._updateVisibility(); 'notify::skip-taskbar', () => this._updateVisibility(),
}); 'workspace-changed', () => this._updateVisibility(),
this);
this._updateVisibility(); this._updateVisibility();
this._windowTitle = new WindowTitle(this.metaWindow); this._windowTitle = new WindowTitle(this.metaWindow);
@@ -430,11 +408,8 @@ class WindowButton extends BaseButton {
this._contextMenuManager.addMenu(this._contextMenu); this._contextMenuManager.addMenu(this._contextMenu);
Main.uiGroup.add_actor(this._contextMenu.actor); Main.uiGroup.add_actor(this._contextMenu.actor);
this._workspaceChangedId = this.metaWindow.connect( global.display.connectObject('notify::focus-window',
'workspace-changed', this._updateVisibility.bind(this)); () => this._updateStyle(), this);
this._notifyFocusId = global.display.connect(
'notify::focus-window', this._updateStyle.bind(this));
this._updateStyle(); this._updateStyle();
} }
@@ -478,9 +453,6 @@ class WindowButton extends BaseButton {
_onDestroy() { _onDestroy() {
super._onDestroy(); super._onDestroy();
this.metaWindow.disconnect(this._skipTaskbarId);
this.metaWindow.disconnect(this._workspaceChangedId);
global.display.disconnect(this._notifyFocusId);
this._contextMenu.destroy(); this._contextMenu.destroy();
} }
} }
@@ -597,18 +569,17 @@ class AppButton extends BaseButton {
Main.uiGroup.add_actor(this._appContextMenu.actor); Main.uiGroup.add_actor(this._appContextMenu.actor);
this._textureCache = St.TextureCache.get_default(); this._textureCache = St.TextureCache.get_default();
this._iconThemeChangedId = this._textureCache.connectObject('icon-theme-changed', () => {
this._textureCache.connect('icon-theme-changed', () => { this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE); }, this);
});
this._windowsChangedId = this.app.connect( this.app.connectObject('windows-changed',
'windows-changed', this._windowsChanged.bind(this)); () => this._windowsChanged(), this);
this._windowsChanged(); this._windowsChanged();
this._windowTracker = Shell.WindowTracker.get_default(); this._windowTracker = Shell.WindowTracker.get_default();
this._notifyFocusId = this._windowTracker.connect( this._windowTracker.connectObject('notify::focus-app',
'notify::focus-app', this._updateStyle.bind(this)); () => this._updateStyle(), this);
this._updateStyle(); this._updateStyle();
} }
@@ -728,9 +699,6 @@ class AppButton extends BaseButton {
_onDestroy() { _onDestroy() {
super._onDestroy(); super._onDestroy();
this._textureCache.disconnect(this._iconThemeChangedId);
this._windowTracker.disconnect(this._notifyFocusId);
this.app.disconnect(this._windowsChangedId);
this._menu.destroy(); this._menu.destroy();
} }
} }
@@ -740,7 +708,7 @@ class WindowList extends St.Widget {
GObject.registerClass(this); GObject.registerClass(this);
} }
constructor(perMonitor, monitor) { constructor(perMonitor, monitor, settings) {
super({ super({
name: 'panel', name: 'panel',
style_class: 'bottom-panel solid', style_class: 'bottom-panel solid',
@@ -787,12 +755,12 @@ class WindowList extends St.Widget {
indicatorsBox.add_child(this._workspaceIndicator.container); indicatorsBox.add_child(this._workspaceIndicator.container);
this._mutterSettings = new Gio.Settings({schema_id: 'org.gnome.mutter'}); this._mutterSettings = new Gio.Settings({schema_id: 'org.gnome.mutter'});
this._workspacesOnlyOnPrimaryChangedId = this._mutterSettings.connect( this._mutterSettings.connectObject(
'changed::workspaces-only-on-primary', 'changed::workspaces-only-on-primary',
this._updateWorkspaceIndicatorVisibility.bind(this)); () => this._updateWorkspaceIndicatorVisibility(),
this._dynamicWorkspacesChangedId = this._mutterSettings.connect(
'changed::dynamic-workspaces', 'changed::dynamic-workspaces',
this._updateWorkspaceIndicatorVisibility.bind(this)); () => this._updateWorkspaceIndicatorVisibility(),
this);
this._updateWorkspaceIndicatorVisibility(); this._updateWorkspaceIndicatorVisibility();
this._menuManager = new PopupMenu.PopupMenuManager(this); this._menuManager = new PopupMenu.PopupMenuManager(this);
@@ -810,59 +778,58 @@ class WindowList extends St.Widget {
this._updatePosition(); this._updatePosition();
this._appSystem = Shell.AppSystem.get_default(); this._appSystem = Shell.AppSystem.get_default();
this._appStateChangedId = this._appSystem.connect( this._appSystem.connectObject('app-state-changed',
'app-state-changed', this._onAppStateChanged.bind(this)); this._onAppStateChanged.bind(this), this);
// Hack: OSK gesture is tied to visibility, piggy-back on that // Hack: OSK gesture is tied to visibility, piggy-back on that
this._keyboardVisiblechangedId = Main.keyboard._bottomDragAction.connectObject('notify::enabled',
Main.keyboard._bottomDragAction.connect('notify::enabled', action => {
action => { const visible = !action.enabled;
const visible = !action.enabled; if (visible) {
if (visible) { Main.uiGroup.set_child_above_sibling(
Main.uiGroup.set_child_above_sibling( this, Main.layoutManager.keyboardBox);
this, Main.layoutManager.keyboardBox); } else {
} else { Main.uiGroup.set_child_above_sibling(
Main.uiGroup.set_child_above_sibling( this, Main.layoutManager.panelBox);
this, Main.layoutManager.panelBox); }
} this._updateKeyboardAnchor();
this._updateKeyboardAnchor(); }, this);
});
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
this._nWorkspacesChangedId = workspaceManager.connect( workspaceManager.connectObject('notify::n-workspaces',
'notify::n-workspaces', this._updateWorkspaceIndicatorVisibility.bind(this)); () => this._updateWorkspaceIndicatorVisibility(), this);
this._updateWorkspaceIndicatorVisibility(); this._updateWorkspaceIndicatorVisibility();
this._switchWorkspaceId = global.window_manager.connect( global.window_manager.connectObject('switch-workspace',
'switch-workspace', this._checkGrouping.bind(this)); () => this._checkGrouping(), this);
this._overviewShowingId = Main.overview.connect('showing', () => { Main.overview.connectObject(
this.hide(); 'showing', () => {
this._updateKeyboardAnchor(); this.hide();
});
this._overviewHidingId = Main.overview.connect('hidden', () => {
this.visible = !this._monitor.inFullscreen;
this._updateKeyboardAnchor();
});
this._fullscreenChangedId =
global.display.connect('in-fullscreen-changed', () => {
// Work-around for initial change from unknown to !fullscreen
if (Main.overview.visible)
this.hide();
this._updateKeyboardAnchor(); this._updateKeyboardAnchor();
}); },
'hidden', () => {
this.visible = !this._monitor.inFullscreen;
this._updateKeyboardAnchor();
}, this);
global.display.connectObject('in-fullscreen-changed', () => {
// Work-around for initial change from unknown to !fullscreen
if (Main.overview.visible)
this.hide();
this._updateKeyboardAnchor();
}, this);
this._windowSignals = new Map(); this._windowSignals = new Map();
this._windowCreatedId = global.display.connect( this._windowCreatedId = global.display.connect(
'window-created', (dsp, win) => this._addWindow(win)); 'window-created', (dsp, win) => this._addWindow(win));
this._dragBeginId = Main.xdndHandler.connect('drag-begin', Main.xdndHandler.connectObject(
this._monitorDrag.bind(this)); 'drag-begin', () => this._monitorDrag(),
this._dragEndId = Main.xdndHandler.connect('drag-end', 'drag-end', () => this._stopMonitoringDrag(),
this._stopMonitoringDrag.bind(this)); this);
this._dragMonitor = { this._dragMonitor = {
dragMotion: this._onDragMotion.bind(this), dragMotion: this._onDragMotion.bind(this),
}; };
@@ -870,7 +837,7 @@ class WindowList extends St.Widget {
this._dndTimeoutId = 0; this._dndTimeoutId = 0;
this._dndWindow = null; this._dndWindow = null;
this._settings = ExtensionUtils.getSettings(); this._settings = settings;
this._settings.connect('changed::grouping-mode', this._settings.connect('changed::grouping-mode',
() => this._groupingModeChanged()); () => this._groupingModeChanged());
this._grouped = undefined; this._grouped = undefined;
@@ -911,7 +878,8 @@ class WindowList extends St.Widget {
} }
_updateWindowListVisibility() { _updateWindowListVisibility() {
let visible = !Main.windowPicker.visible; const {windowPicker} = Extension.lookupByURL(import.meta.url);
const visible = !windowPicker.visible;
this._windowList.ease({ this._windowList.ease({
opacity: visible ? 255 : 0, opacity: visible ? 255 : 0,
@@ -1109,37 +1077,14 @@ class WindowList extends St.Widget {
} }
_onDestroy() { _onDestroy() {
this._mutterSettings.disconnect(this._workspacesOnlyOnPrimaryChangedId);
this._mutterSettings.disconnect(this._dynamicWorkspacesChangedId);
this._workspaceIndicator.destroy(); this._workspaceIndicator.destroy();
Main.ctrlAltTabManager.removeGroup(this); Main.ctrlAltTabManager.removeGroup(this);
this._appSystem.disconnect(this._appStateChangedId);
this._appStateChangedId = 0;
Main.keyboard._bottomDragAction.disconnect(this._keyboardVisiblechangedId);
this._keyboardVisiblechangedId = 0;
global.workspace_manager.disconnect(this._nWorkspacesChangedId);
this._nWorkspacesChangedId = 0;
global.window_manager.disconnect(this._switchWorkspaceId);
this._switchWorkspaceId = 0;
this._windowSignals.forEach((id, win) => win.disconnect(id)); this._windowSignals.forEach((id, win) => win.disconnect(id));
this._windowSignals.clear(); this._windowSignals.clear();
Main.overview.disconnect(this._overviewShowingId);
Main.overview.disconnect(this._overviewHidingId);
global.display.disconnect(this._fullscreenChangedId);
global.display.disconnect(this._windowCreatedId);
this._stopMonitoringDrag(); this._stopMonitoringDrag();
Main.xdndHandler.disconnect(this._dragBeginId);
Main.xdndHandler.disconnect(this._dragEndId);
this._settings.run_dispose(); this._settings.run_dispose();
@@ -1149,9 +1094,9 @@ class WindowList extends St.Widget {
} }
} }
class Extension { export default class WindowListExtension extends Extension {
constructor() { constructor(metadata) {
ExtensionUtils.initTranslations(); super(metadata);
this._windowLists = null; this._windowLists = null;
this._hideOverviewOrig = Main.overview.hide; this._hideOverviewOrig = Main.overview.hide;
@@ -1160,17 +1105,17 @@ class Extension {
enable() { enable() {
this._windowLists = []; this._windowLists = [];
this._settings = ExtensionUtils.getSettings(); this._settings = this.getSettings();
this._showOnAllMonitorsChangedId = this._settings.connect( this._settings.connectObject('changed::show-on-all-monitors',
'changed::show-on-all-monitors', this._buildWindowLists.bind(this)); () => this._buildWindowLists(), this);
this._monitorsChangedId = Main.layoutManager.connect( Main.layoutManager.connectObject('monitors-changed',
'monitors-changed', this._buildWindowLists.bind(this)); () => this._buildWindowLists(), this);
Main.windowPicker = new WindowPicker(); this.windowPicker = new WindowPicker();
Main.overview.hide = () => { Main.overview.hide = () => {
Main.windowPicker.close(); this.windowPicker.close();
this._hideOverviewOrig.call(Main.overview); this._hideOverviewOrig.call(Main.overview);
}; };
@@ -1185,7 +1130,7 @@ class Extension {
Main.layoutManager.monitors.forEach(monitor => { Main.layoutManager.monitors.forEach(monitor => {
if (showOnAllMonitors || monitor === Main.layoutManager.primaryMonitor) if (showOnAllMonitors || monitor === Main.layoutManager.primaryMonitor)
this._windowLists.push(new WindowList(showOnAllMonitors, monitor)); this._windowLists.push(new WindowList(showOnAllMonitors, monitor, this.getSettings()));
}); });
} }
@@ -1193,11 +1138,8 @@ class Extension {
if (!this._windowLists) if (!this._windowLists)
return; return;
this._settings.disconnect(this._showOnAllMonitorsChangedId); this._settings.disconnectObject(this);
this._showOnAllMonitorsChangedId = 0; Main.layoutManager.disconnectObject(this);
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
this._windowLists.forEach(windowList => { this._windowLists.forEach(windowList => {
windowList.hide(); windowList.hide();
@@ -1205,8 +1147,8 @@ class Extension {
}); });
this._windowLists = null; this._windowLists = null;
Main.windowPicker.destroy(); this.windowPicker.destroy();
delete Main.windowPicker; delete this.windowPicker;
Main.overview.hide = this._hideOverviewOrig; Main.overview.hide = this._hideOverviewOrig;
} }
@@ -1279,10 +1221,3 @@ class Tooltip extends St.Label {
}); });
} }
} }
/**
* @returns {Extension} - the extension's state object
*/
function init() {
return new Extension();
}
+12 -18
View File
@@ -1,29 +1,24 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init buildPrefsWidget */ import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
const {Adw, Gio, GLib, GObject, Gtk} = imports.gi; import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
const ExtensionUtils = imports.misc.extensionUtils;
const _ = ExtensionUtils.gettext;
/** */
function init() {
ExtensionUtils.initTranslations();
}
class WindowListPrefsWidget extends Adw.PreferencesPage { class WindowListPrefsWidget extends Adw.PreferencesPage {
static { static {
GObject.registerClass(this); GObject.registerClass(this);
} }
constructor() { constructor(settings) {
super(); super();
this._actionGroup = new Gio.SimpleActionGroup(); this._actionGroup = new Gio.SimpleActionGroup();
this.insert_action_group('window-list', this._actionGroup); this.insert_action_group('window-list', this._actionGroup);
this._settings = ExtensionUtils.getSettings(); this._settings = settings;
this._actionGroup.add_action( this._actionGroup.add_action(
this._settings.create_action('grouping-mode')); this._settings.create_action('grouping-mode'));
this._actionGroup.add_action( this._actionGroup.add_action(
@@ -84,9 +79,8 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
} }
} }
/** export default class WindowListPrefs extends ExtensionPreferences {
* @returns {Gtk.Widget} - the prefs widget getPreferencesWidget() {
*/ return new WindowListPrefsWidget(this.getSettings());
function buildPrefsWidget() { }
return new WindowListPrefsWidget();
} }
+93 -120
View File
@@ -1,17 +1,20 @@
/* exported WindowPicker, WindowPickerToggle */ import Clutter from 'gi://Clutter';
const {Clutter, GObject, Shell, St} = imports.gi; import GObject from 'gi://GObject';
import Shell from 'gi://Shell';
import St from 'gi://St';
const Layout = imports.ui.layout; import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
const Main = imports.ui.main; import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
const {WorkspacesDisplay} = imports.ui.workspacesView; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Workspace = imports.ui.workspace; import {WorkspacesDisplay} from 'resource:///org/gnome/shell/ui/workspacesView.js';
import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js';
const {VIGNETTE_BRIGHTNESS} = imports.ui.lightbox; import {VIGNETTE_BRIGHTNESS} from 'resource:///org/gnome/shell/ui/lightbox.js';
const { import {
SIDE_CONTROLS_ANIMATION_TIME, SIDE_CONTROLS_ANIMATION_TIME,
OverviewAdjustment, OverviewAdjustment,
ControlsState, ControlsState
} = imports.ui.overviewControls; } from 'resource:///org/gnome/shell/ui/overviewControls.js';
class MyWorkspacesDisplay extends WorkspacesDisplay { class MyWorkspacesDisplay extends WorkspacesDisplay {
static { static {
@@ -32,12 +35,13 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
super(controls, workspaceAdjustment, overviewAdjustment); super(controls, workspaceAdjustment, overviewAdjustment);
this._windowPicker = controls;
this._workspaceAdjustment = workspaceAdjustment; this._workspaceAdjustment = workspaceAdjustment;
this._workspaceAdjustment.actor = this; this._workspaceAdjustment.actor = this;
this._nWorkspacesChangedId = workspaceManager.connectObject('notify::n-workspaces',
workspaceManager.connect('notify::n-workspaces', () => this._updateAdjustment(), this);
this._updateAdjustment.bind(this));
this.add_constraint( this.add_constraint(
new Layout.MonitorConstraint({ new Layout.MonitorConstraint({
@@ -48,7 +52,7 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
prepareToEnterOverview(...args) { prepareToEnterOverview(...args) {
if (!this._scrollEventId) { if (!this._scrollEventId) {
this._scrollEventId = Main.windowPicker.connect('scroll-event', this._scrollEventId = this._windowPicker.connect('scroll-event',
this._onScrollEvent.bind(this)); this._onScrollEvent.bind(this));
} }
@@ -57,7 +61,7 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
vfunc_hide(...args) { vfunc_hide(...args) {
if (this._scrollEventId > 0) if (this._scrollEventId > 0)
Main.windowPicker.disconnect(this._scrollEventId); this._windowPicker.disconnect(this._scrollEventId);
this._scrollEventId = 0; this._scrollEventId = 0;
super.vfunc_hide(...args); super.vfunc_hide(...args);
@@ -70,86 +74,9 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
value: workspaceManager.get_active_workspace_index(), value: workspaceManager.get_active_workspace_index(),
}); });
} }
_onDestroy() {
if (this._nWorkspacesChangedId)
global.workspace_manager.disconnect(this._nWorkspacesChangedId);
this._nWorkspacesChangedId = 0;
super._onDestroy();
}
} }
class MyWorkspace extends Workspace.Workspace { export class WindowPicker extends Clutter.Actor {
static {
GObject.registerClass(this);
}
constructor(...args) {
super(...args);
this._adjChangedId =
this._overviewAdjustment.connect('notify::value', () => {
const {value: progress} = this._overviewAdjustment;
const brightness = 1 - (1 - VIGNETTE_BRIGHTNESS) * progress;
for (const bg of this._background?._backgroundGroup ?? []) {
bg.content.set({
vignette: true,
brightness,
});
}
});
}
_onDestroy() {
super._onDestroy();
if (this._adjChangedId)
this._overviewAdjustment.disconnect(this._adjChangedId);
this._adjChangedId = 0;
}
}
class MyWorkspaceBackground extends Workspace.WorkspaceBackground {
static {
GObject.registerClass(this);
}
_updateBorderRadius() {
}
vfunc_allocate(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);
}
}
var WindowPicker = class WindowPicker extends Clutter.Actor {
static [GObject.signals] = { static [GObject.signals] = {
'open-state-changed': {param_types: [GObject.TYPE_BOOLEAN]}, 'open-state-changed': {param_types: [GObject.TYPE_BOOLEAN]},
}; };
@@ -164,11 +91,11 @@ var WindowPicker = class WindowPicker extends Clutter.Actor {
this._visible = false; this._visible = false;
this._modal = false; this._modal = false;
this._overlayKeyId = 0;
this._stageKeyPressId = 0; this._stageKeyPressId = 0;
this._adjustment = new OverviewAdjustment(this); this._adjustment = new OverviewAdjustment(this);
this._injectionManager = new InjectionManager();
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
global.bind_property('screen-width', global.bind_property('screen-width',
@@ -186,21 +113,78 @@ var WindowPicker = class WindowPicker extends Clutter.Actor {
if (!Main.sessionMode.hasOverview) { if (!Main.sessionMode.hasOverview) {
this._injectBackgroundShade(); this._injectBackgroundShade();
this._overlayKeyId = global.display.connect('overlay-key', () => { global.display.connectObject('overlay-key', () => {
if (!this._visible) if (!this._visible)
this.open(); this.open();
else else
this.close(); this.close();
}); }, this);
} }
} }
_injectBackgroundShade() { _injectBackgroundShade() {
this._origWorkspace = Workspace.Workspace; const backgroundProto = Workspace.WorkspaceBackground.prototype;
this._origWorkspaceBackground = Workspace.WorkspaceBackground; 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);
Workspace.Workspace = MyWorkspace; const themeNode = this.get_theme_node();
Workspace.WorkspaceBackground = MyWorkspaceBackground; 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() { get visible() {
@@ -306,27 +290,15 @@ var WindowPicker = class WindowPicker extends Clutter.Actor {
} }
_onDestroy() { _onDestroy() {
if (this._origWorkspace) this._injectionManager.clear();
Workspace.Workspace = this._origWorkspace;
if (this._origWorkspaceBackground)
Workspace.WorkspaceBackground = this._origWorkspaceBackground;
if (this._monitorsChangedId)
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
if (this._overlayKeyId)
global.display.disconnect(this._overlayKeyId);
this._overlayKeyId = 0;
if (this._stageKeyPressId) if (this._stageKeyPressId)
global.stage.disconnect(this._stageKeyPressId); global.stage.disconnect(this._stageKeyPressId);
this._stageKeyPressId = 0; this._stageKeyPressId = 0;
} }
}; }
var WindowPickerToggle = class WindowPickerToggle extends St.Button { export class WindowPickerToggle extends St.Button {
static { static {
GObject.registerClass(this); GObject.registerClass(this);
} }
@@ -350,15 +322,16 @@ var WindowPickerToggle = class WindowPickerToggle extends St.Button {
toggle_mode: true, toggle_mode: true,
}); });
const {windowPicker} = Extension.lookupByURL(import.meta.url);
this.connect('notify::checked', () => { this.connect('notify::checked', () => {
if (this.checked) if (this.checked)
Main.windowPicker.open(); windowPicker.open();
else else
Main.windowPicker.close(); windowPicker.close();
}); });
Main.windowPicker.connect('open-state-changed', () => { windowPicker.connect('open-state-changed', () => {
this.checked = Main.windowPicker.visible; this.checked = windowPicker.visible;
}); });
} }
}; }
+34 -64
View File
@@ -1,13 +1,15 @@
/* exported WorkspaceIndicator */ import Clutter from 'gi://Clutter';
const {Clutter, Gio, GObject, Meta, St} = imports.gi; import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Meta from 'gi://Meta';
import St from 'gi://St';
const DND = imports.ui.dnd; import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const _ = ExtensionUtils.gettext; 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_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150; const TOOLTIP_ANIMATION_TIME = 150;
@@ -29,20 +31,17 @@ class WindowPreview extends St.Button {
this._window = window; this._window = window;
this.connect('destroy', this._onDestroy.bind(this)); this._window.connectObject(
'size-changed', () => this.queue_relayout(),
this._sizeChangedId = this._window.connect('size-changed', 'position-changed', () => {
() => this.queue_relayout());
this._positionChangedId = this._window.connect('position-changed',
() => {
this._updateVisible(); this._updateVisible();
this.queue_relayout(); this.queue_relayout();
}); },
this._minimizedChangedId = this._window.connect('notify::minimized', 'notify::minimized', this._updateVisible.bind(this),
this._updateVisible.bind(this)); this);
this._focusChangedId = global.display.connect('notify::focus-window', global.display.connectObject('notify::focus-window',
this._onFocusChanged.bind(this)); this._onFocusChanged.bind(this), this);
this._onFocusChanged(); this._onFocusChanged();
} }
@@ -51,13 +50,6 @@ class WindowPreview extends St.Button {
return this._window; return this._window;
} }
_onDestroy() {
this._window.disconnect(this._sizeChangedId);
this._window.disconnect(this._positionChangedId);
this._window.disconnect(this._minimizedChangedId);
global.display.disconnect(this._focusChangedId);
}
_onFocusChanged() { _onFocusChanged() {
if (global.display.focus_window === this._window) if (global.display.focus_window === this._window)
this.add_style_class_name('active'); this.add_style_class_name('active');
@@ -138,16 +130,13 @@ class WorkspaceThumbnail extends St.Button {
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
this._workspace = workspaceManager.get_workspace_by_index(index); this._workspace = workspaceManager.get_workspace_by_index(index);
this._windowAddedId = this._workspace.connect('window-added', this._workspace.connectObject(
(ws, window) => { 'window-added', (ws, window) => this._addWindow(window),
this._addWindow(window); 'window-removed', (ws, window) => this._removeWindow(window),
}); this);
this._windowRemovedId = this._workspace.connect('window-removed',
(ws, window) => { global.display.connectObject('restacked',
this._removeWindow(window); this._onRestacked.bind(this), this);
});
this._restackedId = global.display.connect('restacked',
this._onRestacked.bind(this));
this._workspace.list_windows().forEach(w => this._addWindow(w)); this._workspace.list_windows().forEach(w => this._addWindow(w));
this._onRestacked(); this._onRestacked();
@@ -245,14 +234,10 @@ class WorkspaceThumbnail extends St.Button {
_onDestroy() { _onDestroy() {
this._tooltip.destroy(); this._tooltip.destroy();
this._workspace.disconnect(this._windowAddedId);
this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId);
} }
} }
var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button { export class WorkspaceIndicator extends PanelMenu.Button {
static { static {
GObject.registerClass(this); GObject.registerClass(this);
} }
@@ -295,14 +280,11 @@ var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
this._workspacesItems = []; this._workspacesItems = [];
this._workspaceManagerSignals = [ workspaceManager.connectObject(
workspaceManager.connect('notify::n-workspaces', 'notify::n-workspaces', this._nWorkspacesChanged.bind(this), GObject.ConnectFlags.AFTER,
this._nWorkspacesChanged.bind(this)), 'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
workspaceManager.connect_after('workspace-switched', 'notify::layout-rows', this._updateThumbnailVisibility.bind(this),
this._onWorkspaceSwitched.bind(this)), this);
workspaceManager.connect('notify::layout-rows',
this._updateThumbnailVisibility.bind(this)),
];
this.connect('scroll-event', this._onScrollEvent.bind(this)); this.connect('scroll-event', this._onScrollEvent.bind(this));
this._updateMenu(); this._updateMenu();
@@ -310,20 +292,8 @@ var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
this._updateThumbnailVisibility(); this._updateThumbnailVisibility();
this._settings = new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'}); this._settings = new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
this._settingsChangedId = this._settings.connect( this._settings.connectObject('changed::workspace-names',
'changed::workspace-names', this._updateMenuLabels.bind(this)); () => this._updateMenuLabels(), this);
}
_onDestroy() {
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
if (this._settingsChangedId) {
this._settings.disconnect(this._settingsChangedId);
this._settingsChangedId = 0;
}
super._onDestroy();
} }
_updateThumbnailVisibility() { _updateThumbnailVisibility() {
@@ -447,4 +417,4 @@ var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
let newIndex = this._currentWorkspace + diff; let newIndex = this._currentWorkspace + diff;
this._activate(newIndex); this._activate(newIndex);
} }
}; }
+276 -262
View File
@@ -1,276 +1,290 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported init */ import Clutter from 'gi://Clutter';
const {Clutter, Graphene, GObject, St} = imports.gi; import Graphene from 'gi://Graphene';
import St from 'gi://St';
const Main = imports.ui.main; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const OverviewControls = imports.ui.overviewControls; import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js';
const Workspace = imports.ui.workspace; import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
const WorkspacesView = imports.ui.workspacesView; import {WindowPreview} from 'resource:///org/gnome/shell/ui/windowPreview.js';
import {Workspace} from 'resource:///org/gnome/shell/ui/workspace.js';
import {WorkspacesView} from 'resource:///org/gnome/shell/ui/workspacesView.js';
const WINDOW_SLOT = 4; const WINDOW_SLOT = 4;
class MyWorkspace extends Workspace.Workspace { export default class Extension {
static {
GObject.registerClass(this);
}
constructor(...args) {
super(...args);
if (this.metaWorkspace && this.metaWorkspace.index() < 9) {
this._tip = new St.Label({
style_class: 'extension-windowsNavigator-window-tooltip',
visible: false,
});
this.add_actor(this._tip);
this.connect('notify::scale-x', () => {
this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);
});
} else {
this._tip = null;
}
}
vfunc_allocate(box) {
super.vfunc_allocate(box);
if (this._tip)
this._tip.allocate_preferred_size(0, 0);
}
showTooltip() {
if (!this._tip)
return;
this._tip.text = (this.metaWorkspace.index() + 1).toString();
this._tip.show();
this.set_child_below_sibling(this._tip, null);
}
hideTooltip() {
if (this._tip)
this._tip.hide();
}
getWindowWithTooltip(id) {
const {layoutManager} = this._container;
const slot = layoutManager._windowSlots[id - 1];
return slot ? slot[WINDOW_SLOT].metaWindow : null;
}
showWindowsTooltips() {
const {layoutManager} = this._container;
for (let i = 0; i < layoutManager._windowSlots.length; i++) {
if (layoutManager._windowSlots[i])
layoutManager._windowSlots[i][WINDOW_SLOT].showTooltip(`${i + 1}`);
}
}
hideWindowsTooltips() {
const {layoutManager} = this._container;
for (let i in layoutManager._windowSlots) {
if (layoutManager._windowSlots[i])
layoutManager._windowSlots[i][WINDOW_SLOT].hideTooltip();
}
}
// overriding _addWindowClone to apply the tooltip patch on the cloned
// windowPreview
_addWindowClone(metaWindow) {
const clone = super._addWindowClone(metaWindow);
// appling the tooltip patch
(function patchPreview() {
this._text = new St.Label({
style_class: 'extension-windowsNavigator-window-tooltip',
visible: false,
});
this._text.add_constraint(new Clutter.BindConstraint({
source: this.windowContainer,
coordinate: Clutter.BindCoordinate.POSITION,
}));
this._text.add_constraint(new Clutter.AlignConstraint({
source: this.windowContainer,
align_axis: Clutter.AlignAxis.X_AXIS,
pivot_point: new Graphene.Point({x: 0.5, y: -1}),
factor: this._closeButtonSide === St.Side.LEFT ? 1 : 0,
}));
this._text.add_constraint(new Clutter.AlignConstraint({
source: this.windowContainer,
align_axis: Clutter.AlignAxis.Y_AXIS,
pivot_point: new Graphene.Point({x: -1, y: 0.5}),
factor: 0,
}));
this.add_child(this._text);
}).call(clone);
clone.showTooltip = function (text) {
this._text.set({text});
this._text.show();
};
clone.hideTooltip = function () {
if (this._text && this._text.visible)
this._text.hide();
};
return clone;
}
}
class MyWorkspacesView extends WorkspacesView.WorkspacesView {
static {
GObject.registerClass(this);
}
constructor(...args) {
super(...args);
this._pickWorkspace = false;
this._pickWindow = false;
this._keyPressEventId =
global.stage.connect('key-press-event', this._onKeyPress.bind(this));
this._keyReleaseEventId =
global.stage.connect('key-release-event', this._onKeyRelease.bind(this));
}
_onDestroy() {
super._onDestroy();
global.stage.disconnect(this._keyPressEventId);
global.stage.disconnect(this._keyReleaseEventId);
}
_hideTooltips() {
if (global.stage.get_key_focus() === global.stage)
global.stage.set_key_focus(this._prevFocusActor);
this._pickWindow = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].hideWindowsTooltips();
}
_hideWorkspacesTooltips() {
global.stage.set_key_focus(this._prevFocusActor);
this._pickWorkspace = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].hideTooltip();
}
_onKeyRelease(s, o) {
if (this._pickWindow &&
(o.get_key_symbol() === Clutter.KEY_Alt_L ||
o.get_key_symbol() === Clutter.KEY_Alt_R))
this._hideTooltips();
if (this._pickWorkspace &&
(o.get_key_symbol() === Clutter.KEY_Control_L ||
o.get_key_symbol() === Clutter.KEY_Control_R))
this._hideWorkspacesTooltips();
}
_onKeyPress(s, o) {
const {ControlsState} = OverviewControls;
if (this._overviewAdjustment.value !== ControlsState.WINDOW_PICKER)
return false;
let workspaceManager = global.workspace_manager;
if ((o.get_key_symbol() === Clutter.KEY_Alt_L ||
o.get_key_symbol() === Clutter.KEY_Alt_R) &&
!this._pickWorkspace) {
this._prevFocusActor = global.stage.get_key_focus();
global.stage.set_key_focus(null);
this._active = workspaceManager.get_active_workspace_index();
this._pickWindow = true;
this._workspaces[workspaceManager.get_active_workspace_index()].showWindowsTooltips();
return true;
}
if ((o.get_key_symbol() === Clutter.KEY_Control_L ||
o.get_key_symbol() === Clutter.KEY_Control_R) &&
!this._pickWindow) {
this._prevFocusActor = global.stage.get_key_focus();
global.stage.set_key_focus(null);
this._pickWorkspace = true;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].showTooltip();
return true;
}
if (global.stage.get_key_focus() !== global.stage)
return false;
// ignore shift presses, they're required to get numerals in azerty keyboards
if ((this._pickWindow || this._pickWorkspace) &&
(o.get_key_symbol() === Clutter.KEY_Shift_L ||
o.get_key_symbol() === Clutter.KEY_Shift_R))
return true;
if (this._pickWindow) {
if (this._active !== workspaceManager.get_active_workspace_index()) {
this._hideTooltips();
return false;
}
let c = o.get_key_symbol() - Clutter.KEY_KP_0;
if (c > 9 || c <= 0) {
c = o.get_key_symbol() - Clutter.KEY_0;
if (c > 9 || c <= 0) {
this._hideTooltips();
global.log(c);
return false;
}
}
let win = this._workspaces[this._active].getWindowWithTooltip(c);
this._hideTooltips();
if (win)
Main.activateWindow(win, global.get_current_time());
return true;
}
if (this._pickWorkspace) {
let c = o.get_key_symbol() - Clutter.KEY_KP_0;
if (c > 9 || c <= 0) {
c = o.get_key_symbol() - Clutter.KEY_0;
if (c > 9 || c <= 0) {
this._hideWorkspacesTooltips();
return false;
}
}
let workspace = this._workspaces[c - 1];
if (workspace !== undefined)
workspace.metaWorkspace.activate(global.get_current_time());
this._hideWorkspacesTooltips();
return true;
}
return false;
}
}
class Extension {
constructor() { constructor() {
this._origWorkspace = Workspace.Workspace; this._injectionManager = new InjectionManager();
this._origWorkspacesView = WorkspacesView.WorkspacesView;
} }
enable() { enable() {
Workspace.Workspace = MyWorkspace; const previewProto = WindowPreview.prototype;
WorkspacesView.WorkspacesView = MyWorkspacesView;
this._injectionManager.overrideMethod(previewProto, '_init', originalMethod => {
/* eslint-disable no-invalid-this */
return function (...args) {
originalMethod.call(this, ...args);
this._text = new St.Label({
style_class: 'extension-windowsNavigator-window-tooltip',
visible: false,
});
this._text.add_constraint(new Clutter.BindConstraint({
source: this.windowContainer,
coordinate: Clutter.BindCoordinate.POSITION,
}));
this._text.add_constraint(new Clutter.AlignConstraint({
source: this.windowContainer,
align_axis: Clutter.AlignAxis.X_AXIS,
pivot_point: new Graphene.Point({x: 0.5, y: -1}),
factor: this._closeButtonSide === St.Side.LEFT ? 1 : 0,
}));
this._text.add_constraint(new Clutter.AlignConstraint({
source: this.windowContainer,
align_axis: Clutter.AlignAxis.Y_AXIS,
pivot_point: new Graphene.Point({x: -1, y: 0.5}),
factor: 0,
}));
this.add_child(this._text);
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(previewProto, 'showTooltip', () => {
/* eslint-disable no-invalid-this */
return function (text) {
this._text.set({text});
this._text.show();
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(previewProto, 'hideTooltip', () => {
/* eslint-disable no-invalid-this */
return function () {
this._text?.hide();
};
/* eslint-enable */
});
const workspaceProto = Workspace.prototype;
this._injectionManager.overrideMethod(workspaceProto, '_init', originalMethod => {
/* eslint-disable no-invalid-this */
return function (...args) {
originalMethod.call(this, ...args);
if (this.metaWorkspace && this.metaWorkspace.index() < 9) {
this._tip = new St.Label({
style_class: 'extension-windowsNavigator-window-tooltip',
visible: false,
});
this.add_actor(this._tip);
this.connect('notify::scale-x', () => {
this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);
});
} else {
this._tip = null;
}
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(workspaceProto, 'vfunc_allocate', originalMethod => {
/* eslint-disable no-invalid-this */
return function (box) {
originalMethod.call(this, box);
this._tip?.allocate_preferred_size(0, 0);
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(workspaceProto, 'showTooltip', () => {
/* eslint-disable no-invalid-this */
return function () {
if (!this._tip)
return;
this._tip.text = (this.metaWorkspace.index() + 1).toString();
this._tip.show();
this.set_child_below_sibling(this._tip, null);
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(workspaceProto, 'hideTooltip', () => {
/* eslint-disable no-invalid-this */
return function () {
this._tip?.hide();
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(workspaceProto, 'getWindowWithTooltip', () => {
/* eslint-disable no-invalid-this */
return function (id) {
const {layoutManager} = this._container;
const slot = layoutManager._windowSlots[id - 1];
return slot ? slot[WINDOW_SLOT].metaWindow : null;
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(workspaceProto, 'showWindowsTooltips', () => {
/* eslint-disable no-invalid-this */
return function () {
const {layoutManager} = this._container;
for (let i = 0; i < layoutManager._windowSlots.length; i++) {
if (layoutManager._windowSlots[i])
layoutManager._windowSlots[i][WINDOW_SLOT].showTooltip(`${i + 1}`);
}
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(workspaceProto, 'hideWindowsTooltips', () => {
/* eslint-disable no-invalid-this */
return function () {
const {layoutManager} = this._container;
for (let i in layoutManager._windowSlots) {
if (layoutManager._windowSlots[i])
layoutManager._windowSlots[i][WINDOW_SLOT].hideTooltip();
}
};
/* eslint-enable */
});
const viewProto = WorkspacesView.prototype;
this._injectionManager.overrideMethod(viewProto, '_init', originalMethod => {
/* eslint-disable no-invalid-this */
return function (...args) {
originalMethod.call(this, ...args);
this._pickWorkspace = false;
this._pickWindow = false;
global.stage.connectObject(
'key-press-event', this._onKeyPress.bind(this),
'key-release-event', this._onKeyRelease.bind(this),
this);
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(viewProto, '_hideTooltips', () => {
/* eslint-disable no-invalid-this */
return function () {
if (global.stage.get_key_focus() === global.stage)
global.stage.set_key_focus(this._prevFocusActor);
this._pickWindow = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].hideWindowsTooltips();
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(viewProto, '_hideWorkspacesTooltips', () => {
/* eslint-disable no-invalid-this */
return function () {
global.stage.set_key_focus(this._prevFocusActor);
this._pickWorkspace = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].hideTooltip();
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(viewProto, '_onKeyRelease', () => {
/* eslint-disable no-invalid-this */
return function (actor, event) {
if (this._pickWindow &&
(event.get_key_symbol() === Clutter.KEY_Alt_L ||
event.get_key_symbol() === Clutter.KEY_Alt_R))
this._hideTooltips();
if (this._pickWorkspace &&
(event.get_key_symbol() === Clutter.KEY_Control_L ||
event.get_key_symbol() === Clutter.KEY_Control_R))
this._hideWorkspacesTooltips();
};
/* eslint-enable */
});
this._injectionManager.overrideMethod(viewProto, '_onKeyPress', () => {
/* eslint-disable no-invalid-this */
return function (actor, event) {
const {ControlsState} = OverviewControls;
if (this._overviewAdjustment.value !== ControlsState.WINDOW_PICKER)
return false;
let workspaceManager = global.workspace_manager;
if ((event.get_key_symbol() === Clutter.KEY_Alt_L ||
event.get_key_symbol() === Clutter.KEY_Alt_R) &&
!this._pickWorkspace) {
this._prevFocusActor = global.stage.get_key_focus();
global.stage.set_key_focus(null);
this._active = workspaceManager.get_active_workspace_index();
this._pickWindow = true;
this._workspaces[workspaceManager.get_active_workspace_index()].showWindowsTooltips();
return true;
}
if ((event.get_key_symbol() === Clutter.KEY_Control_L ||
event.get_key_symbol() === Clutter.KEY_Control_R) &&
!this._pickWindow) {
this._prevFocusActor = global.stage.get_key_focus();
global.stage.set_key_focus(null);
this._pickWorkspace = true;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].showTooltip();
return true;
}
if (global.stage.get_key_focus() !== global.stage)
return false;
// ignore shift presses, they're required to get numerals in azerty keyboards
if ((this._pickWindow || this._pickWorkspace) &&
(event.get_key_symbol() === Clutter.KEY_Shift_L ||
event.get_key_symbol() === Clutter.KEY_Shift_R))
return true;
if (this._pickWindow) {
if (this._active !== workspaceManager.get_active_workspace_index()) {
this._hideTooltips();
return false;
}
let c = event.get_key_symbol() - Clutter.KEY_KP_0;
if (c > 9 || c <= 0) {
c = event.get_key_symbol() - Clutter.KEY_0;
if (c > 9 || c <= 0) {
this._hideTooltips();
log(c);
return false;
}
}
let win = this._workspaces[this._active].getWindowWithTooltip(c);
this._hideTooltips();
if (win)
Main.activateWindow(win, global.get_current_time());
return true;
}
if (this._pickWorkspace) {
let c = event.get_key_symbol() - Clutter.KEY_KP_0;
if (c > 9 || c <= 0) {
c = event.get_key_symbol() - Clutter.KEY_0;
if (c > 9 || c <= 0) {
this._hideWorkspacesTooltips();
return false;
}
}
let workspace = this._workspaces[c - 1];
if (workspace !== undefined)
workspace.metaWorkspace.activate(global.get_current_time());
this._hideWorkspacesTooltips();
return true;
}
return false;
};
/* eslint-enable */
});
} }
disable() { disable() {
Workspace.Workspace = this._origWorkspace; this._injectionManager.clear();
WorkspacesView.WorkspacesView = this._origWorkspacesView;
} }
} }
/**
* @returns {Extension} - the extension's state object
*/
function init() {
return new Extension();
}
+41 -75
View File
@@ -1,15 +1,16 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init enable disable */ 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';
const {Clutter, Gio, GObject, Meta, St} = imports.gi; import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const DND = imports.ui.dnd; import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
const ExtensionUtils = imports.misc.extensionUtils; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Main = imports.ui.main; import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
const PanelMenu = imports.ui.panelMenu; import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
const PopupMenu = imports.ui.popupMenu;
const _ = ExtensionUtils.gettext;
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names'; const WORKSPACE_KEY = 'workspace-names';
@@ -34,20 +35,17 @@ class WindowPreview extends St.Button {
this._window = window; this._window = window;
this.connect('destroy', this._onDestroy.bind(this)); this._window.connectObject(
'size-changed', () => this.queue_relayout(),
this._sizeChangedId = this._window.connect('size-changed', 'position-changed', () => {
() => this.queue_relayout());
this._positionChangedId = this._window.connect('position-changed',
() => {
this._updateVisible(); this._updateVisible();
this.queue_relayout(); this.queue_relayout();
}); },
this._minimizedChangedId = this._window.connect('notify::minimized', 'notify::minimized', this._updateVisible.bind(this),
this._updateVisible.bind(this)); this);
this._focusChangedId = global.display.connect('notify::focus-window', global.display.connectObject('notify::focus-window',
this._onFocusChanged.bind(this)); this._onFocusChanged.bind(this), this);
this._onFocusChanged(); this._onFocusChanged();
} }
@@ -56,13 +54,6 @@ class WindowPreview extends St.Button {
return this._window; return this._window;
} }
_onDestroy() {
this._window.disconnect(this._sizeChangedId);
this._window.disconnect(this._positionChangedId);
this._window.disconnect(this._minimizedChangedId);
global.display.disconnect(this._focusChangedId);
}
_onFocusChanged() { _onFocusChanged() {
if (global.display.focus_window === this._window) if (global.display.focus_window === this._window)
this.add_style_class_name('active'); this.add_style_class_name('active');
@@ -143,16 +134,13 @@ class WorkspaceThumbnail extends St.Button {
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
this._workspace = workspaceManager.get_workspace_by_index(index); this._workspace = workspaceManager.get_workspace_by_index(index);
this._windowAddedId = this._workspace.connect('window-added', this._workspace.connectObject(
(ws, window) => { 'window-added', (ws, window) => this._addWindow(window),
this._addWindow(window); 'window-removed', (ws, window) => this._removeWindow(window),
}); this);
this._windowRemovedId = this._workspace.connect('window-removed',
(ws, window) => { global.display.connectObject('restacked',
this._removeWindow(window); this._onRestacked.bind(this), this);
});
this._restackedId = global.display.connect('restacked',
this._onRestacked.bind(this));
this._workspace.list_windows().forEach(w => this._addWindow(w)); this._workspace.list_windows().forEach(w => this._addWindow(w));
this._onRestacked(); this._onRestacked();
@@ -250,10 +238,6 @@ class WorkspaceThumbnail extends St.Button {
_onDestroy() { _onDestroy() {
this._tooltip.destroy(); this._tooltip.destroy();
this._workspace.disconnect(this._windowAddedId);
this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId);
} }
} }
@@ -295,14 +279,11 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._workspaceSection = new PopupMenu.PopupMenuSection(); this._workspaceSection = new PopupMenu.PopupMenuSection();
this.menu.addMenuItem(this._workspaceSection); this.menu.addMenuItem(this._workspaceSection);
this._workspaceManagerSignals = [ workspaceManager.connectObject(
workspaceManager.connect_after('notify::n-workspaces', 'notify::n-workspaces', this._nWorkspacesChanged.bind(this), GObject.ConnectFlags.AFTER,
this._nWorkspacesChanged.bind(this)), 'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
workspaceManager.connect_after('workspace-switched', 'notify::layout-rows', this._updateThumbnailVisibility.bind(this),
this._onWorkspaceSwitched.bind(this)), this);
workspaceManager.connect('notify::layout-rows',
this._updateThumbnailVisibility.bind(this)),
];
this.connect('scroll-event', this._onScrollEvent.bind(this)); this.connect('scroll-event', this._onScrollEvent.bind(this));
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this)); this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
@@ -311,20 +292,11 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._updateThumbnailVisibility(); this._updateThumbnailVisibility();
this._settings = new Gio.Settings({schema_id: WORKSPACE_SCHEMA}); this._settings = new Gio.Settings({schema_id: WORKSPACE_SCHEMA});
this._settingsChangedId = this._settings.connect( this._settings.connectObject(`changed::${WORKSPACE_KEY}`,
`changed::${WORKSPACE_KEY}`, this._updateMenuLabels.bind(this), this);
this._updateMenuLabels.bind(this));
} }
_onDestroy() { _onDestroy() {
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
if (this._settingsChangedId) {
this._settings.disconnect(this._settingsChangedId);
this._settingsChangedId = 0;
}
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
super._onDestroy(); super._onDestroy();
@@ -454,20 +426,14 @@ class WorkspaceIndicator extends PanelMenu.Button {
} }
} }
/** */ export default class WorkspaceIndicatorExtension extends Extension {
function init() { enable() {
ExtensionUtils.initTranslations(); this._indicator = new WorkspaceIndicator();
} Main.panel.addToStatusArea('workspace-indicator', this._indicator);
}
let _indicator; disable() {
this._indicator.destroy();
/** */ delete this._indicator;
function enable() { }
_indicator = new WorkspaceIndicator();
Main.panel.addToStatusArea('workspace-indicator', _indicator);
}
/** */
function disable() {
_indicator.destroy();
} }
+11 -15
View File
@@ -1,11 +1,13 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init buildPrefsWidget */ import Adw from 'gi://Adw';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
import Pango from 'gi://Pango';
const {Adw, Gio, GLib, GObject, Gtk, Pango} = imports.gi; import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
const ExtensionUtils = imports.misc.extensionUtils;
const _ = ExtensionUtils.gettext;
const N_ = e => e; const N_ = e => e;
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
@@ -256,14 +258,8 @@ class NewWorkspaceRow extends Adw.PreferencesRow {
} }
} }
/** */ export default class WorkspaceIndicatorPrefs extends ExtensionPreferences {
function init() { getPreferencesWidget() {
ExtensionUtils.initTranslations(); return new WorkspaceSettingsWidget();
} }
/**
* @returns {Gtk.Widget} - the prefs widget
*/
function buildPrefsWidget() {
return new WorkspaceSettingsWidget();
} }
+4 -1
View File
@@ -68,7 +68,10 @@ rules:
jsdoc/check-tag-names: error jsdoc/check-tag-names: error
jsdoc/check-types: error jsdoc/check-types: error
jsdoc/implements-on-classes: error jsdoc/implements-on-classes: error
jsdoc/newline-after-description: error jsdoc/tag-lines:
- error
- any
- startLines: 1
jsdoc/require-jsdoc: error jsdoc/require-jsdoc: error
jsdoc/require-param: error jsdoc/require-param: error
jsdoc/require-param-description: error jsdoc/require-param-description: error
+2
View File
@@ -10,3 +10,5 @@ rules:
prefer-arrow-callback: error prefer-arrow-callback: error
globals: globals:
global: readonly global: readonly
parserOptions:
sourceType: module
+1 -1
View File
@@ -1,5 +1,5 @@
project('gnome-shell-extensions', project('gnome-shell-extensions',
version: '45.alpha', version: '45.beta',
meson_version: '>= 0.58.0', meson_version: '>= 0.58.0',
license: 'GPL2+' license: 'GPL2+'
) )
+55 -46
View File
@@ -12,8 +12,8 @@ msgstr ""
"Project-Id-Version: gnome-shell-extensions master\n" "Project-Id-Version: gnome-shell-extensions master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
"issues\n" "issues\n"
"POT-Creation-Date: 2020-05-28 00:55+0000\n" "POT-Creation-Date: 2023-02-18 15:10+0000\n"
"PO-Revision-Date: 2020-07-14 00:40+0300\n" "PO-Revision-Date: 2023-08-01 23:41+0300\n"
"Last-Translator: Efstathios Iosifidis <eiosifidis@gnome.org>\n" "Last-Translator: Efstathios Iosifidis <eiosifidis@gnome.org>\n"
"Language-Team: Greek, Modern (1453-) <gnome-el-list@gnome.org>\n" "Language-Team: Greek, Modern (1453-) <gnome-el-list@gnome.org>\n"
"Language: el\n" "Language: el\n"
@@ -21,22 +21,31 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.7.1\n" "X-Generator: Poedit 3.3.2\n"
"X-Project-Style: gnome\n" "X-Project-Style: gnome\n"
#: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3 #: data/gnome-classic.desktop.in:3
msgid "GNOME Classic" msgid "GNOME Classic"
msgstr "GNOME Classic" msgstr "GNOME Classic"
#: data/gnome-classic.desktop.in:4 #: data/gnome-classic.desktop.in:4 data/gnome-classic-wayland.desktop.in:4
#: data/gnome-classic-xorg.desktop.in:4
msgid "This session logs you into GNOME Classic" msgid "This session logs you into GNOME Classic"
msgstr "Αυτή η συνεδρία σας συνδέει στο GNOME Classic" msgstr "Αυτή η συνεδρία σας συνδέει στο GNOME Classic"
#: extensions/apps-menu/extension.js:113 #: data/gnome-classic-wayland.desktop.in:3
msgid "GNOME Classic on Wayland"
msgstr "GNOME Classic σε Wayland"
#: data/gnome-classic-xorg.desktop.in:3
msgid "GNOME Classic on Xorg"
msgstr "GNOME Classic σε Xorg"
#: extensions/apps-menu/extension.js:118
msgid "Favorites" msgid "Favorites"
msgstr "Αγαπημένα" msgstr "Αγαπημένα"
#: extensions/apps-menu/extension.js:369 #: extensions/apps-menu/extension.js:380
msgid "Applications" msgid "Applications"
msgstr "Εφαρμογές" msgstr "Εφαρμογές"
@@ -53,26 +62,26 @@ msgstr ""
"(όνομα αρχείου επιφάνειας εργασίας), ακολουθούμενη από άνω-κάτω τελεία και " "(όνομα αρχείου επιφάνειας εργασίας), ακολουθούμενη από άνω-κάτω τελεία και "
"τον αριθμό του χώρου εργασίας" "τον αριθμό του χώρου εργασίας"
#: extensions/auto-move-windows/prefs.js:35 #: extensions/auto-move-windows/prefs.js:152
msgid "Workspace Rules" msgid "Workspace Rules"
msgstr "Κανόνες χώρων εργασίας" msgstr "Κανόνες χώρων εργασίας"
#: extensions/auto-move-windows/prefs.js:243 #: extensions/auto-move-windows/prefs.js:306
msgid "Add Rule" msgid "Add Rule"
msgstr "Προσθήκη κανόνα" msgstr "Προσθήκη κανόνα"
#. TRANSLATORS: %s is the filesystem name #. TRANSLATORS: %s is the filesystem name
#: extensions/drive-menu/extension.js:112 #: extensions/drive-menu/extension.js:126
#: extensions/places-menu/placeDisplay.js:233 #: extensions/places-menu/placeDisplay.js:212
#, javascript-format #, javascript-format
msgid "Ejecting drive “%s” failed:" msgid "Ejecting drive “%s” failed:"
msgstr "Αποτυχία εξαγωγής του δίσκου «%s»:" msgstr "Αποτυχία εξαγωγής του δίσκου «%s»:"
#: extensions/drive-menu/extension.js:128 #: extensions/drive-menu/extension.js:145
msgid "Removable devices" msgid "Removable devices"
msgstr "Αφαιρούμενες συσκευές" msgstr "Αφαιρούμενες συσκευές"
#: extensions/drive-menu/extension.js:155 #: extensions/drive-menu/extension.js:167
msgid "Open Files" msgid "Open Files"
msgstr "Άνοιγμα αρχείων" msgstr "Άνοιγμα αρχείων"
@@ -106,31 +115,31 @@ msgstr ""
"στο κάτω μέρος. Η αλλαγή αυτής της ρύθμισης απαιτεί επανεκκίνηση του " "στο κάτω μέρος. Η αλλαγή αυτής της ρύθμισης απαιτεί επανεκκίνηση του "
"κελύφους για να υπάρξει κάποιο αποτέλεσμα." "κελύφους για να υπάρξει κάποιο αποτέλεσμα."
#: extensions/places-menu/extension.js:89 #: extensions/places-menu/extension.js:94
#: extensions/places-menu/extension.js:93 #: extensions/places-menu/extension.js:97
msgid "Places" msgid "Places"
msgstr "Τοποθεσίες" msgstr "Τοποθεσίες"
#: extensions/places-menu/placeDisplay.js:46 #: extensions/places-menu/placeDisplay.js:52
#, javascript-format #, javascript-format
msgid "Failed to launch “%s”" msgid "Failed to launch “%s”"
msgstr "Αποτυχία εκκίνησης «%s»" msgstr "Αποτυχία εκκίνησης «%s»"
#: extensions/places-menu/placeDisplay.js:61 #: extensions/places-menu/placeDisplay.js:67
#, javascript-format #, javascript-format
msgid "Failed to mount volume for “%s”" msgid "Failed to mount volume for “%s”"
msgstr "Αποτυχία προσάρτησης τόμου για «%s»" msgstr "Αποτυχία προσάρτησης τόμου για «%s»"
#: extensions/places-menu/placeDisplay.js:148 #: extensions/places-menu/placeDisplay.js:127
#: extensions/places-menu/placeDisplay.js:171 #: extensions/places-menu/placeDisplay.js:150
msgid "Computer" msgid "Computer"
msgstr "Υπολογιστής" msgstr "Υπολογιστής"
#: extensions/places-menu/placeDisplay.js:359 #: extensions/places-menu/placeDisplay.js:340
msgid "Home" msgid "Home"
msgstr "Προσωπικός φάκελος" msgstr "Προσωπικός φάκελος"
#: extensions/places-menu/placeDisplay.js:404 #: extensions/places-menu/placeDisplay.js:385
msgid "Browse Network" msgid "Browse Network"
msgstr "Περιήγηση δικτύου" msgstr "Περιήγηση δικτύου"
@@ -151,47 +160,47 @@ msgid "The name of the theme, to be loaded from ~/.themes/name/gnome-shell"
msgstr "" msgstr ""
"Το όνομα του θέματος που θα φορτωθεί από το ~ /.themes/name/gnome-shell" "Το όνομα του θέματος που θα φορτωθεί από το ~ /.themes/name/gnome-shell"
#: extensions/window-list/extension.js:98 #: extensions/window-list/extension.js:72
msgid "Close" msgid "Close"
msgstr "Κλείσιμο" msgstr "Κλείσιμο"
#: extensions/window-list/extension.js:118 #: extensions/window-list/extension.js:92
msgid "Unminimize" msgid "Unminimize"
msgstr "Αποελαχιστοποίηση" msgstr "Αποελαχιστοποίηση"
#: extensions/window-list/extension.js:118 #: extensions/window-list/extension.js:92
msgid "Minimize" msgid "Minimize"
msgstr "Ελαχιστοποίηση" msgstr "Ελαχιστοποίηση"
#: extensions/window-list/extension.js:125 #: extensions/window-list/extension.js:99
msgid "Unmaximize" msgid "Unmaximize"
msgstr "Απομεγιστοποίηση" msgstr "Απομεγιστοποίηση"
#: extensions/window-list/extension.js:125 #: extensions/window-list/extension.js:99
msgid "Maximize" msgid "Maximize"
msgstr "Μεγιστοποίηση" msgstr "Μεγιστοποίηση"
#: extensions/window-list/extension.js:428 #: extensions/window-list/extension.js:483
msgid "Minimize all" msgid "Minimize all"
msgstr "Ελαχιστοποίηση όλων" msgstr "Ελαχιστοποίηση όλων"
#: extensions/window-list/extension.js:434 #: extensions/window-list/extension.js:489
msgid "Unminimize all" msgid "Unminimize all"
msgstr "Αποελαχιστοποίηση όλων" msgstr "Αποελαχιστοποίηση όλων"
#: extensions/window-list/extension.js:440 #: extensions/window-list/extension.js:495
msgid "Maximize all" msgid "Maximize all"
msgstr "Μεγιστοποίηση όλων" msgstr "Μεγιστοποίηση όλων"
#: extensions/window-list/extension.js:448 #: extensions/window-list/extension.js:503
msgid "Unmaximize all" msgid "Unmaximize all"
msgstr "Απομεγιστοποίηση όλων" msgstr "Απομεγιστοποίηση όλων"
#: extensions/window-list/extension.js:456 #: extensions/window-list/extension.js:511
msgid "Close all" msgid "Close all"
msgstr "Κλείσιμο όλων" msgstr "Κλείσιμο όλων"
#: extensions/window-list/extension.js:734 #: extensions/window-list/extension.js:795
msgid "Window List" msgid "Window List"
msgstr "Λίστα παραθύρου" msgstr "Λίστα παραθύρου"
@@ -209,7 +218,7 @@ msgstr ""
"«always» (πάντα)." "«always» (πάντα)."
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:20 #: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:20
#: extensions/window-list/prefs.js:100 #: extensions/window-list/prefs.js:79
msgid "Show windows from all workspaces" msgid "Show windows from all workspaces"
msgstr "Εμφάνιση των παραθύρων από όλους τους χώρους εργασίας" msgstr "Εμφάνιση των παραθύρων από όλους τους χώρους εργασίας"
@@ -230,41 +239,41 @@ msgstr ""
"Αν θα εμφανίζεται ο κατάλογος παραθύρων όλων των συνδεμένων οθονών ή μόνο " "Αν θα εμφανίζεται ο κατάλογος παραθύρων όλων των συνδεμένων οθονών ή μόνο "
"της κύριας οθόνης." "της κύριας οθόνης."
#: extensions/window-list/prefs.js:29 #: extensions/window-list/prefs.js:35
msgid "Window Grouping" msgid "Window Grouping"
msgstr "Ομαδοποίηση παραθύρου" msgstr "Ομαδοποίηση παραθύρου"
#: extensions/window-list/prefs.js:58 #: extensions/window-list/prefs.js:40
msgid "Never group windows" msgid "Never group windows"
msgstr "Να μη γίνεται ποτέ ομαδοποίηση παραθύρων" msgstr "Να μη γίνεται ποτέ ομαδοποίηση παραθύρων"
#: extensions/window-list/prefs.js:59 #: extensions/window-list/prefs.js:41
msgid "Group windows when space is limited" msgid "Group windows when space is limited"
msgstr "Ομαδοποίηση παραθύρων όταν ο χώρος είναι περιορισμένος" msgstr "Ομαδοποίηση παραθύρων όταν ο χώρος είναι περιορισμένος"
#: extensions/window-list/prefs.js:60 #: extensions/window-list/prefs.js:42
msgid "Always group windows" msgid "Always group windows"
msgstr "Να γίνεται πάντα ομαδοποίηση παραθύρων" msgstr "Να γίνεται πάντα ομαδοποίηση παραθύρων"
#: extensions/window-list/prefs.js:94 #: extensions/window-list/prefs.js:66
msgid "Show on all monitors" msgid "Show on all monitors"
msgstr "Να εμφανίζεται σε όλες τις οθόνες" msgstr "Να εμφανίζεται σε όλες τις οθόνες"
#: extensions/window-list/workspaceIndicator.js:207 #: extensions/window-list/workspaceIndicator.js:261
#: extensions/workspace-indicator/extension.js:213 #: extensions/workspace-indicator/extension.js:266
msgid "Workspace Indicator" msgid "Workspace Indicator"
msgstr "Δείκτης χώρου εργασίας" msgstr "Δείκτης χώρου εργασίας"
#: extensions/workspace-indicator/prefs.js:34 #: extensions/workspace-indicator/prefs.js:62
msgid "Workspace Names"
msgstr "Ονόματα χώρων εργασίας:"
#: extensions/workspace-indicator/prefs.js:67
#, javascript-format #, javascript-format
msgid "Workspace %d" msgid "Workspace %d"
msgstr "Χώρος εργασίας %d" msgstr "Χώρος εργασίας %d"
#: extensions/workspace-indicator/prefs.js:218 #: extensions/workspace-indicator/prefs.js:129
msgid "Workspace Names"
msgstr "Ονόματα χώρων εργασίας"
#: extensions/workspace-indicator/prefs.js:255
msgid "Add Workspace" msgid "Add Workspace"
msgstr "Προσθήκη χώρου εργασίας" msgstr "Προσθήκη χώρου εργασίας"