Compare commits

..

137 Commits

Author SHA1 Message Date
Jakub Steiner
b58d702a2d theme: update system grey background
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/2174
2020-02-04 15:28:56 +01:00
Dušan Kazik
404ae0a897 Update Slovak translation 2020-02-04 10:02:46 +00:00
Florian Müllner
9e00e8a0fb extensionPrefs: Schedule updates check on activate
While gnome-shell will now check for extension updates, the checks
are performed infrequently. Opening the Extensions app implies that
the user's current focus is on extensions, so it is an appropriate
time to schedule another updates check.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:33:14 +01:00
Florian Müllner
529829a561 extensionSystem: Periodically check for extension updates
Now that we can download, apply and display extension updates, it is time
to actually check for updates. Schedule an update check right on startup,
then every 24 hours.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:33:14 +01:00
Florian Müllner
ed84541050 extensionSystem: Show notification when updates are available
Now that the extensions app has the ability to handle updates, we
can use it as source of updates notifications.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:33:14 +01:00
Florian Müllner
075f4a5efc extensionPrefs: Support extension updates
Now that we have support for extension updates in the shell, we
need some place to display the updates to the user.

As we are establishing the Extensions app as the primary way for
managing extensions, it's a natural place for that functionality.

Show which extensions have updates available, and offer a log out
button (so gnome-shell can apply the updates when logging back in).

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:33:12 +01:00
Florian Müllner
f1bd94a367 extensionPrefs: Split user and system extensions
Until now, it didn't matter whether an extension was installed in the
user's home or system-wide. However with support for uninstallation,
there is now a significant different, as that action is only available
for user extensions.

Account for that by separating extensions by type, so that users don't
have to second-guess which extensions can be fully-managed and which
appear as part of the system.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:13:44 +01:00
Florian Müllner
db69ad876a extensionPrefs: Support uninstalling user extensions
This is functionality currently provided by GNOME Software, and
which the new Extensions app should (and easily can) provide.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:11:21 +01:00
Florian Müllner
c6f297e4e5 extensionPrefs: Include more extension details in expander
The newly added expander gives us a place where we can display
more details without cluttering the interface.

Take advantage of that by including the extension website, version
and author.

(Author is in the mockups, but will not actually be shown until
the extensions website is changed to include it in its metadata;
however best to have UI and string in place for the freezes)

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:11:21 +01:00
Florian Müllner
1067642300 extensionPrefs: Move description into a expander
The description can be useful information, but also increases the
visual complexity of the extensions list. Move it into a hidden
details area that can be expanded, which unclutters the interface
while keeping the information readily available.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:11:21 +01:00
Florian Müllner
059524b007 extensionPrefs: Use actions for row controls
Actions are another mean to separate state and interactions from
the UI. Start using them for the existing controls before adding
more in follow-up commits.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:11:21 +01:00
Florian Müllner
1d72f28a1c extensionPrefs: Use template for rows
Rows are already complex enough to justify a template, and we are
about to add more.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:11:21 +01:00
Florian Müllner
5b92e3a9a8 extensionPrefs: Use a single line for description
The current fixed two-line label requires a custom widget, which
make moving to a widget template harder.

As the description will soon move elsewhere anyway, just go back
to a single line with a standard label for now.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:11:21 +01:00
Florian Müllner
8795668c41 extensionPrefs: Rename to Extensions
... and make the application user-visible.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
872c84a1c3 extensionPrefs: Add standard app elements
In order to turn the extensions-prefs tool into a proper GNOME app, it
should follow basic app patterns, so add a primary menu and about dialog.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
b47879d0a7 extensionPrefs: Add info popover to headerbar
Extensions can have a major impact on stability and performance. Now that
the tool will become the main way for users to manage their extensions, it
is an appropriate place to warn the user of that risk.

Add a small info popover to the headerbar to display that warning, together
with the previously removed hint of where to go for finding new extensions.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
679fc20765 extensionPrefs: Add application icon
We are about to make the tool a user-visible application, so we
need an icon. Add one (plus its symbolic variant).

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
db85e7084c extensionPrefs: Scroll with key focus
Currently when the extensions list is scrolled, it is possible to
keynav out of view, as the scrolling doesn't follow the key focus.

Hook up the adjustment to fix that.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
1afd2c6ad2 extensionPrefs: Don't fill view
Extension rows contain both name/description and controls to
open preferences and enable/disable the extension. Those
elements become disassociated when the row expands too much
horizontally, so instead of filling the entire view, switch
to the embedded list style[0].

[0] https://developer.gnome.org/hig/stable/lists.html.en

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
a74a9f6443 extensionPrefs: Use template for ExtensionsWindow
As the window will become more complex, it makes sense to let GtkBuilder
construct the UI and focus on the actual implementation.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
f49e20bbae extensionPrefs: Split out window class
Currently the main window is a plain Gtk.ApplicationWindow that is
built and managed from within the application.

As the application becomes more complex, it makes sense to decouple
the two and handle the window from a separate ExtensionsWindow class.

Not least this is a prerequisite of using a widget template for the
window.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
9916989272 extensionPrefs: Simplify empty placeholder
GNOME Software will remove its extension support, so we should stop
referencing it in addition to extensions.gnome.org.

In fact, the placeholder is not the best place to hint at where new
extensions can be found, as the user will never see it in case the
distribution includes pre-installed extensions.

So remove the hint altogether, we will add it back in a more prominent
place later.

With the whole placeholder now being much lighter, we can stop dimming
the remaining elements.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
2020-02-03 19:03:19 +01:00
Florian Müllner
1054f7533a theme: Tweak app folder style
- match dash border/radius
 - hide scrollbar
 - increase title padding

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/973
2020-02-03 14:24:23 +00:00
Goran Vidović
5f457f6ed2 Update Croatian translation 2020-02-03 14:03:08 +00:00
Daniel Mustieles
9df2edc87e Updated Spanish translation 2020-02-03 12:15:54 +01:00
Dušan Kazik
28eb94402e Update Slovak translation 2020-02-02 20:34:09 +00:00
Aurimas Černius
d2bf869c16 Updated Lithuanian translation 2020-02-02 22:10:30 +02:00
Anders Jonsson
05ea1bdac2 Update Swedish translation 2020-02-02 14:55:45 +00:00
Dušan Kazik
454e85f0a9 Update Slovak translation 2020-02-01 23:06:01 +00:00
Jonas Dreßler
45c5f21f6c dialogs: Hide caps lock warning if password entry is hidden
If all password entries in dialogs are hidden, there is either an entry
that has visible characters or no entry at all. That means we don't have
to show the caps lock warning at all, so hide it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
59bd2dd1e3 windowManager: Use shorter string for dialog headline
Since the headlines of the dialogs now use a much larger font, the
strings need to be shorter so they won't be ellipsized.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
3c47923953 networkAgent: Use shorter title strings
Since the headlines of the dialogs now use a much larger font, the
strings need to be shorter so they won't be ellipsized. So use a shorter
strings for those titles and also adjust the title-strings of the
notifications sent by the NetworkAgent to be consistent.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
dbaf5687dd networkAgent: Implement new dialog design
Use a completely vertical layout instead of the ClutterGridLayout based
layout to implement the new design for dialogs in the shell:

- Center-align all the elements of the dialog
- Remove the work-spinner
- Show the entry-labels as hint text of the entry

See https://gitlab.gnome.org/GNOME/gnome-shell/issues/1343

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
20895c7791 windowManager: Cleanup dialog a bit
This doesn't have to be a prompt-dialog, so remove the css class, also
the MessageDialogContent doesn't need the x and y_expand properties, so
remove those, too.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
ddeb2fa05d shellMountOperation: Use wiggle effect to inform about wrong password
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
7a1f4f9af3 shellMountOperation: Implement new dialog design
Update the layout of the ShellMountPasswordDialog dialog according to
the new dialog design:

- Center-align all the elements of the dialog
- Align the work-spinner to the right (or left with RTL layouts) of the
password entry
- Show the entry-labels as hint text of the entry

See https://gitlab.gnome.org/GNOME/gnome-shell/issues/1343

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:33 +01:00
Jonas Dreßler
dc578a9e79 keyring: Use wiggle effect to inform about new warning message
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:08:30 +01:00
Jonas Dreßler
040c1638ea keyring: Implement new dialog design
Replace the ClutterGridLayout of the keyring dialog with a vertical
StBoxLayout based layout according to the new dialog design:

- Center-align all the elements of the dialog
- Remove the work-spinner because requests usually finish fast enough
- Show the entry-labels as hint text of the entry

See https://gitlab.gnome.org/GNOME/gnome-shell/issues/1343

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:06:31 +01:00
Jonas Dreßler
ded8412a2a polkitAgent: Use wiggle effect to inform about wrong password or problem
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:06:31 +01:00
Jonas Dreßler
2f3738fae0 polkitAgent: Implement new design for polkit dialog
Implement the new design for the polkit according to the mockups in
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1343:

- Center-align all the parts of the dialog
- Use a larger user avatar
- Remove the work-spinner because requests usually finish fast enough
- Show the entry-labels as hint text of the entry

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:06:31 +01:00
Jonas Dreßler
a59da75830 theme/dialogs: Clean up css a bit
Remove some unused classes and "deduplicate" selectors.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:06:31 +01:00
Jonas Dreßler
2b184a10d6 util: Move wiggle parameters to a common place
Since the wiggle effect will be used by the redesigned prompt-dialogs
and we always want to use the same parameters, move those as defaults
for the wiggle function to the util.js file.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/942
2020-02-01 08:06:31 +01:00
Florian Müllner
fc36837606 st/theme-node: Support "auto" in lengths
This allows resetting a fixed size to the default in a more specific
selector.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/971
2020-02-01 00:22:24 +01:00
Florian Müllner
4871845d01 portalHelper: Require GTK 3.0
When multiple versions of a typelib are available, GI will pick the
highest one unless an explicit version is requested. So as GTK 4.0
is becoming a thing, it's time to do that.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/970
2020-01-31 17:39:18 +01:00
Florian Müllner
53ac00eabb js: Initialize some properties
Otherwise those can result in the (harmless) "reference to undefined
property" warnings.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/970
2020-01-31 17:39:18 +01:00
Jor Teron
75905ebd3c Update Karbi translation 2020-01-31 10:50:28 +00:00
Jor Teron
12f033ee0f Update Karbi translation
(cherry picked from commit a8bb7c0a2a)
2020-01-31 10:34:46 +00:00
Georges Basile Stavracas Neto
964106513e shellEntry: Use seat to retrieve keymap
The backend does not handle the keymap anymore; this is now
handled by ClutterSeat.

Use ClutterSeat to retrieve the default keymap.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/968
2020-01-30 15:57:12 -03:00
Carlos Garnacho
9aca26916c magnifier: Adapt to idle monitors API change
It takes Clutter input devices now, not device IDs.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
5a006d9e79 dnd: Use ClutterSeat to fetch devices
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
bd016c6b49 lookingGlass: Use ClutterSeat to fetch devices
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
484dd98448 padOsd: Use ClutterSeat to fetch devices
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
84d92bf65e ui: Use ClutterSeat for keyboard/pointer a11y
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
8d88a9b9c4 keyboard: Update to ::last-device-changed parameter change
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
b86ef8cde5 st: Use ClutterSeat to get pointer device
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Carlos Garnacho
bd48b0641f shell: Use ClutterSeat to get pointer device
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/760
2020-01-30 17:49:08 +00:00
Jonas Dreßler
0f4aeb2654 checkbox: Correctly align label
The label needs to be center-aligned vertically so it's positioned in
the middle of the surrounding box, not at the top.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/967
2020-01-30 15:48:26 +01:00
Jonas Dreßler
0b3fec22d7 shellEntry: Hide caps lock warning and use animation to show it
Since the caps-lock warning adds a lot of spacing to dialogs and the
lock screen, hide it by default and only show it when necessary. To make
the transition smooth instead of just showing the label, animate it in
using the height and opacity.

Also add some bottom padding to the label so we can show or hide that
padding, too.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
2020-01-30 14:35:26 +00:00
Jonas Dreßler
9009b50bd1 polkitAgent: Remove styleClass argument for caps lock warning
The caps lock warning now has its own css class that works for this
case, too. Remove the custom class parameter and just use the default
one.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
2020-01-30 14:35:26 +00:00
Jonas Dreßler
eee0657727 theme: Move caps-lock warning to entry widget stylesheet
The caps-lock warning is more related to entries than dialogs and is
also used in gdm, which is not realated to dialogs at all. Rename the
css class to caps-lock-warning-label and move it to the entry
stylesheet.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
2020-01-30 14:35:26 +00:00
Jonas Dreßler
056f5e5100 shellEntry: Make signal id variable private
Signal connection IDs should be private variables, so make this one
private.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
2020-01-30 14:35:26 +00:00
Daniel García Moreno
5b2c604fe4 animation: Scale animation actor for HiDPI
The Animation class inherits from St.Bin and manages the scale factor
in the image loading, but the widget size doesn't change and doesn't
depend on the scale factor so when the scale factor is different
from 1 the widget size doesn't match the image size.

This patch resizes the Animation widget using the scale factor so the
widget will match the animation images sizes.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1746
2020-01-30 14:28:45 +00:00
Florian Müllner
db9ef11f28 extensionSystem: Install pending updates on startup
Now that we have a way to check for updates and download them, we
should actually apply them as well. Do this on startup before any
extensions are initialized, to make sure we don't run into any
conflicts with a previously loaded version.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945
2020-01-30 13:37:47 +00:00
Florian Müllner
ea5732fe6f extensionDownloader: Include version validation in update check
The extensions website will consider the setting to find the best suitable
extension version, so we should transmit the parameter for better results.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945
2020-01-30 13:37:47 +00:00
Florian Müllner
b7e828fa3c extensionDownloader: Exclude extensions with pending updates from check
While it is possible that an extension has a newer version available
than the previously downloaded update, it's more likely that we end up
downloading the same archive again. That would be a bit silly despite
the usually small size, so we can either use the metadata from the
update, or exclude the extension from the check.

The latter is much easier, so let's go with that for now.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945
2020-01-30 13:37:47 +00:00
Florian Müllner
cbc9bc5fc6 extensionDownloader: Only check updates for user extensions
System extensions cannot be updated through the website, so don't
even try.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945
2020-01-30 13:37:47 +00:00
Florian Müllner
9c785ca6b6 extensionDownloader: Make checkForUpdates() check for updates
Currently the method installs updates instead of merely checking for
them (or it would do, if it actually worked).

This is not just surprising considering the method name, the whole idea
of live updates is problematic and will not work properly more often
than not:
 - imports are cached, so any local modules will stay at their
   original version until a shell restart
 - GTypes cannot be unregistered

So change the method to only download available updates, and set the
extensions' hasUpdate state accordingly.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945
2020-01-30 13:37:47 +00:00
Florian Müllner
375d1892bf extensionSystem: Add hasUpdate state
The current support for extension updates is half-baked at best.
We are about to change that, and implement offline updates similar
to gnome-software.

As a first step, add a hasUpdate property to the extension state
which will communicate available updates.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945
2020-01-30 13:37:47 +00:00
Dušan Kazik
2dae3f5656 Update Slovak translation 2020-01-29 13:15:58 +00:00
Daniel Mustieles
0a5d07871d Updated Spanish translation 2020-01-29 10:35:20 +01:00
Alexander Mikhaylenko
2490a2ffda workspacesView: Disable swipe tracker during window dragging
Since a11f417cd0, both drag and scroll
gestures are added to Main.layoutManager.overviewGroup actor, while
previously drag gesture was added to Main.overview._backgroundGroup
instead. Since we cannot use 2 different actors for dragging and scrolling
anymore. just disable the swipe tracker while dragging a window.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/2151
2020-01-28 22:08:48 +00:00
Rafael Fontenelle
3eaa19ab0f Update Brazilian Portuguese translation 2020-01-28 21:43:30 +00:00
Daniel van Vugt
4c4846e9bd overviewControls: Use ClutterActor's translation-x
Instead of reimplementing `translation-x` as a relayout. It still looks
the same but no longer incurs relayouts during the animation which
reduces render time significantly.

Related to: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1271

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/948
2020-01-28 18:09:49 +00:00
Jonas Dreßler
747ba97dbd endSessionDialog: Use a fixed width of 30em
Make sure we don't rely on the size of the largest part of the layout
when aligning the endSessionDialog and use a fixed width of 30em
instead.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/965
2020-01-28 15:55:00 +00:00
Jonas Dreßler
74393c700e theme: Move endSessionDialog style into dialogs stylesheet
Since the style information of the end session dialog is now only a few
lines anymore, we can move it into the general stylesheet for dialogs.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/965
2020-01-28 15:55:00 +00:00
Jonas Dreßler
3f21c21532 status/system: Update text of orientation lock menu entry
Since the orientation lock menu entry is a proper menu entry instead of
a icon-only button now, we also show a description-text for that entry,
so update this text depending on whether orientation is locked or not to
better reflect what clicking the menu entry will do.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/964
2020-01-28 15:49:01 +00:00
Daniel Mustieles
526c601512 Updated Spanish translation 2020-01-28 15:48:13 +01:00
Jonas Dreßler
6d2c834694 shellMountDialog: Close all dialogs when pressing Escape key
Since we don't really know what the buttons we're adding to the dialogs
are about, we can't configure a button to "be clicked" when the escape
key is pressed. So add a separate escape key handler to fix that, return
-1 and abort the request.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/961
2020-01-27 23:22:46 +00:00
Jonas Dreßler
0b51a52c9b shellMountDialog: Check for changes before creating new buttons
When updating the buttons of the mount dialogs, compare the new buttons
to the old ones and only create new buttons in case something changed.
This makes sure key focus isn't reset or lost unnecessarily while a
dialog is opened.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/961
2020-01-27 23:22:46 +00:00
Jonas Dreßler
7224afd32a shellMountDialog: Switch to new ListLayout for processes dialog
Since there is a generic layout for dialogs like that now, use it. Also
remove the functionality of focussing a window when clicking a list
item, it's not discoverable at all and pretty unexpected.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/961
2020-01-27 23:22:46 +00:00
Jonas Dreßler
d5dbc28f77 inhibitShortcutsDialog: Adapt to new dialog design
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/962
2020-01-27 23:40:04 +01:00
Jonas Dreßler
2996d9d977 location: Adapt geolocation dialog to new design
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/962
2020-01-27 23:40:04 +01:00
Jonas Dreßler
eec25367fc audioDeviceSelection: Adapt to new dialog design
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/962
2020-01-27 23:40:04 +01:00
Jonas Dreßler
7388e4006a kbdA11yDialog: Remove styleClass argument from DialogContent params
The MessageDialogContent class does not have a styleClass param, also
using the "access-dialog" css class doesn't make sense for this dialog,
so just remove that param.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/962
2020-01-27 23:40:04 +01:00
Jonas Dreßler
6c1cd1d8be extensionDownloader: Adapt install dialog to new design
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/962
2020-01-27 23:40:04 +01:00
Jonas Dreßler
5e08c80857 runDialog: Implement the new dialog design
Implement the new design according to the mockups in
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1343.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/960
2020-01-27 19:27:45 +01:00
Jonas Dreßler
26b78e7d77 runDialog: Use new indentation style
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/960
2020-01-27 19:27:45 +01:00
Daniel Korostil
b674cdbde2 Update Ukrainian translation 2020-01-27 16:34:36 +00:00
Olivier Fourdan
68598f7c0c perf-tool: Allow to run as a Wayland compositor
`gnome-shell-perf-tool` is initially designed to run on X11, using the
`--replace` option which does not work when gnome-shell is a Wayland
compositor.

A solution would be to run `gnome-shell-perf-tool` in place of just
`gnome-shell` to run the entire perf session under Wayland, but the
script `gnome-shell-perf-tool` does not spawn `gnome-shell` as a Wayladn
compositor, so that fails as well.

Add a `--wayland` option to `gnome-shell-perf-tool` so that it can
optionally spawn gnome-shell as a Wayland compositor so the whole perf
tool can be starred from a console with:

```
  $ dbus-run-session -- gnome-shell-perf-tool --wayland
```

Alternatively, for testing purposes, it can also be started nested with:

```
  $ dbus-run-session -- gnome-shell-perf-tool --nested
```

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2139
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/941
2020-01-27 13:43:06 +00:00
Olivier Fourdan
ee7e62c9c8 perf-tool: Spawn perf-tool-helper from gnome-shell
On Wayland, the display server is the Wayland compositor, i.e.
`gnome-shell` itself.

As a result, we cannot spawn `gnome-shell-perf-helper` before
`gnome-shell` is started, as `gnome-shell-perf-helper` needs to connect
to the display server.

So, instead of spawning `gnome-shell-perf-helper` from the perf tool,
start it from `gnome-shell` itself.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/941
2020-01-27 13:43:06 +00:00
Umarzuki Bin Mochlis Moktar
a750d04bdb Update Malay translation 2020-01-27 12:27:03 +00:00
Dušan Kazik
ef035c1b60 Update Slovak translation 2020-01-26 20:23:57 +00:00
Fabio Tomat
854bd93385 Update Friulian translation 2020-01-26 19:08:34 +00:00
Jiri Grönroos
9c589297d5 Update Finnish translation 2020-01-26 16:51:47 +00:00
Jordi Mas
aae59801f1 Update Catalan translation 2020-01-26 10:10:40 +01:00
nana-4
c95926aaed theme: Fix dash tooltip misalignment
margin-top is unnecessary here.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/2130
2020-01-25 08:51:12 +09:00
Björn Daase
c61685e617 Revert "recorder: Switch to vp9"
This reverts commit d183f13456.
Switching to the vp9 encoder seemed like a good idea at the time but
unfortunately it also has the major drawback, that it leaks a serious
amount of memory every time it is used. See
https://gitlab.gnome.org/GNOME/gnome-shell/issues/256#note_692743
for more details.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/256
2020-01-24 18:01:45 +00:00
Rafael Fontenelle
a0d49bad36 Update Brazilian Portuguese translation 2020-01-24 11:38:55 +00:00
Kukuh Syafaat
2b89efab4e Update Indonesian translation 2020-01-24 04:47:52 +00:00
Florian Müllner
eb8b82b62a style: Fix style class name
Whoops, this never worked: ShellApp sets a style class of .fallback-app-icon,
while the CSS used .fallback-window-icon.

Let's go with the former ...

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1779
2020-01-23 18:25:28 +00:00
Florian Müllner
d9b3d6745c app: Use better icon for wayland window-backed apps
For window-backed apps (read: windows we can't match to a .desktop
file), we use the window's icon property as icon. However there is
no such property on wayland (at least in the protocols we support),
so we end up with a blank actor in that case.

Do better than that, and pick a generic fallback icon instead.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1779
2020-01-23 18:25:28 +00:00
Jonas Dreßler
c2956e8bd2 st/entry: Notify "text" prop on every change in the ClutterText
Notifying the "text" property inside `st_entry_set_text()` misses all
the text changes done by ClutterText itself, including those that happen
on key-presses. Fix that by notifying that property inside the
"notify::text" handler connected to the ClutterText.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/951
2020-01-23 19:16:59 +01:00
Jonas Dreßler
397454d844 theme/entries: Adjust style of entries according to mockups
Add some more padding for the actual text inside the entry and add some
clearance between the left border of the text (where the cursor is) and
the hint-text.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/944
2020-01-23 17:30:46 +00:00
Jonas Dreßler
7638485f9e theme/entries: Set entry hint-text color
Set the color for hint-texts in entries to a more transparent value so
it's clear that this is a hint, not the actual text inside the entry.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/944
2020-01-23 17:30:46 +00:00
Jonas Dreßler
49170585b3 st/entry: Add css class name to hint-text label
Allow styling the hint text of the entry using css easily.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/944
2020-01-23 17:30:46 +00:00
Jonas Dreßler
88ac339774 st/entry: Show hint actor while entry is focused
Also show the hint actor of an StEntry while the entry is focused but
has no text inside it. This is part of the new dialog and lock-screen
design where there are no labels before entries anymore and labels are
instead shown as a hint-text of the entry.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/944
2020-01-23 17:30:46 +00:00
Yi-Jyun Pan
ed647f5937 Update Chinese (Taiwan) translation 2020-01-23 07:38:24 +00:00
Sebastian Keller
b49023c31c st/icon: Fix GIcon leak in set_fallback_icon_name
set_fallback_icon_name() leaks a GIcon by using the set_icon method
which adds a ref to the GIcon without removing its own ref after calling
the method.

Related to https://gitlab.gnome.org/GNOME/gnome-shell/issues/2146
2020-01-22 23:34:23 +01:00
Florian Müllner
9e9f3ff6b4 dateMenu: Indicate when do-not-disturb is on
When do-not-disturb is enabled, non-critical notifications will not
be shown as banners. It therefore makes sense to indicate that state
to the user, so they don't accidentally miss notifications.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/239
2020-01-22 21:55:28 +00:00
Florian Müllner
b4cf07d05f dateMenu: Add some spacing between date and indicator
While the existing dot doesn't necessarily need padding, we are about
to (sometimes) showing a "proper" icon there.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/239
2020-01-22 21:55:28 +00:00
Florian Müllner
aba3336b51 dateMenu: Bind pad visibility to indicator
Currently the indicator pad requests a size of 0x0 if the corresponding
indicator is hidden. Right now this is enough to balance out the indicator,
but it won't be when we add spacing to the parent container.

Properly hide the pad with the indicator to avoid that issue.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/239
2020-01-22 21:55:28 +00:00
Florian Müllner
2cabef97b6 calendar: Add "Do Not Disturb" switch
We've had the ability to temporarily disable notification banners
all the way back to 3.0, but we stopped exposing it in the UI with
the 3.16 notification redesign. With the message list being more
concise nowadays and the "Clear" button reduced to a single icon,
we now have space for a "Do Not Disturb" switch again.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/239
2020-01-22 21:55:28 +00:00
Florian Müllner
4e26e0e53c popupMenu: Turn Switch state into a GObject property
A property is often more convenient than a method, as it can be used
with bind_property() and friends.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/239
2020-01-22 21:55:28 +00:00
Sebastian Keller
6eacbeb203 st/icon: Fix GIcon leak in set_icon_name
set_icon_name() leaks a GIcon by using the set_icon method which adds a
ref to the GIcon without removing its own ref after calling the method.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/2146
2020-01-22 20:20:50 +01:00
sicklylife
84f490cceb Update Japanese translation 2020-01-22 17:35:52 +00:00
sicklylife
786aa8302d Update Japanese translation 2020-01-22 17:26:55 +00:00
Sebastian Keller
b4ed8a3d06 extensionDownloader: Use uuid lookup method in checkForUpdates()
The extensions variable the code was trying to access was made private
and turned into a map some time ago.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1958
2020-01-22 17:08:11 +01:00
Carlos Garnacho
9f0ef0044d keyboard: Avoid blank space in OSK panel on portrait layouts
We try to make the OSK 1/3rd as big as the monitor. On landscape
layouts we usually get away with it as there's plenty of horizontal
space to enlarge the OSK while keeping the OSK aspect ratio.

In portrait layout, the horizontal space is a lot more scarce so
it means we'll still have plenty of space after making the OSK as
wide as it can possibly be, which will look as odd blank space in
the OSK panel.

In order to fix this, let the OSK panel height be less than 1/3rd
the monitor size if we are dealing with portrait layouts.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2132
2020-01-21 16:58:17 +00:00
Carlos Garnacho
5f3f4c3301 keyboard: Do not reset to initial page on unmap
It will happen before next map anyway, and most notably at times
actor sizes produce correct results.

Fixes oddities in emoji pager visibility after showing the emoji
panel, moving to another page, and hiding the OSK with the downward
arrow button. The next time the emoji panel would be shown, panels
had a chance to remain invisible.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/943
2020-01-21 16:58:17 +00:00
Carlos Garnacho
1ef7306149 keyboard: Do not set the initial page on construction
It is already scheduled to be set on first map. Doing so here triggers
size and theme node checks the actor tree is not ready for, as the
toplevel actor is not yet attached to the stage.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/943
2020-01-21 16:58:17 +00:00
Carlos Garnacho
e15d8eeb17 keyboard: Tell emoji panel container to expand
Otherwise the EmojiSelection won't use up available space.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2131
2020-01-21 16:58:17 +00:00
Carlos Garnacho
1f7c99d9fb keyboard: Tell keyboard container to expand
Otherwise the KeyContainer won't use up available space.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2142
2020-01-21 16:58:17 +00:00
Georges Basile Stavracas Neto
f7620b385a appDisplay: Block search when showing app folder dialogs
Also following design guidance, make the search entry insensitive
when showing an app folder dialog.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 11:07:08 -03:00
Georges Basile Stavracas Neto
9746c00a22 appDisplay: Set minimum folder view rows to 1
This improves the usage of empty space in the dialog.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 11:07:08 -03:00
Georges Basile Stavracas Neto
dc6f36bf5e appDisplay: Remove rename popup
This functionality always suffered from discoveribility
problems, and now that the folder dialog can rename the
app folders, there's just no reason to keep it.

Remove the rename popup.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 11:07:08 -03:00
Georges Basile Stavracas Neto
973c920284 appDisplay: Add folder title and entry to dialog
This allows editing the folder name, and keeps the folder title visible
at all times.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 11:07:08 -03:00
Georges Basile Stavracas Neto
1dad5f3ffa iconGrid: Remove API to open space between icons
Since we moved to showing folders as dialogs now, there's no need
to keep this API. Remove it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 10:49:56 -03:00
Georges Basile Stavracas Neto
802c8d5844 appDisplay: Cleanup unnecessary code
Now that the folder dialog handles the adaptToSize workaround,
there is no need to propagate the call throughout the class
hierarchy.

Remove the propagating calls to adaptToSize, and all the satellite
code.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 10:48:44 -03:00
Georges Basile Stavracas Neto
7781f973f2 appDisplay: Rename popup API to dialog
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 10:48:41 -03:00
Georges Basile Stavracas Neto
53c12dc33e appDisplay: Add the folder popup to AllView itself
Now the the folder popup behaves like a dialog, it must be
above the app grid, and not be affected by the scroll view
translation.

Add the folder popup to the AllView itself, instead of the
internal Shell.Stack that is inside the scroll view.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 10:40:34 -03:00
Georges Basile Stavracas Neto
f46d10c4f9 appDisplay: Transform folder into a dialog
Make the AppFolderPopup behave much more like a dialog than a
popup itself. To do that, remove the BoxPointer and replace it
by a StBoxLayout. The dialog is is also bind-constrained to the
view selector.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
2020-01-21 10:40:34 -03:00
Daniel Mustieles
e573d739af Updated Spanish translation 2020-01-21 12:18:53 +01:00
Kukuh Syafaat
6c0c5f8ed4 Update Indonesian translation 2020-01-21 05:00:42 +00:00
sicklylife
4333820f8e Update Japanese translation 2020-01-20 22:21:05 +00:00
sicklylife
ad2d95d523 Update Japanese translation 2020-01-20 22:12:26 +00:00
Georges Basile Stavracas Neto
479c14c766 st/box-layout: Reimplement as a StViewport subclass
With StViewport doing most of the heavy-lifting, StBoxLayout
can be cleaned up as a StViewport subclass.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/929
2020-01-20 16:15:32 -03:00
Georges Basile Stavracas Neto
56805a4c85 Introduce StViewport
St has the regular abstractions to handle actors that are bigger
than their parent could handle: StScrollable, StScrollView, and
StAdjustment.

However, the only StScrollable implementation available currently
is StBoxLayout, which forces a ClutterBoxLayout as the layout
manager (and relies on it not being unset).

Introduce StViewport, which is a minimal StScrollable implementation
that doesn't rely on any specific layout manager.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/929
2020-01-20 16:15:22 -03:00
99 changed files with 13507 additions and 9444 deletions

View File

@@ -0,0 +1,15 @@
<node>
<interface name="org.freedesktop.impl.portal.Access">
<method name="AccessDialog">
<arg type="o" name="handle" direction="in"/>
<arg type="s" name="app_id" direction="in"/>
<arg type="s" name="parent_window" direction="in"/>
<arg type="s" name="title" direction="in"/>
<arg type="s" name="subtitle" direction="in"/>
<arg type="s" name="body" direction="in"/>
<arg type="a{sv}" name="options" direction="in"/>
<arg type="u" name="response" direction="out"/>
<arg type="a{sv}" name="results" direction="out"/>
</method>
</interface>
</node>

View File

@@ -9,6 +9,7 @@
<file preprocess="xml-stripblanks">org.freedesktop.DBus.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.GeoClue2.Agent.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.GeoClue2.Manager.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.impl.portal.Access.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.impl.portal.PermissionStore.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.impl.portal.Request.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.login1.Manager.xml</file>

View File

@@ -18,7 +18,6 @@
<file alias="icons/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file>
<file>no-events.svg</file>
<file>no-notifications.svg</file>
<file>noise-texture.png</file>
<file>pad-osd.css</file>
<file alias="icons/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file>
<file alias="icons/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file>

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

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

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128px" height="128px" viewBox="0 0 128 128" version="1.1">
<g id="surface43907">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,37.254903%,70.588237%);fill-opacity:1;" d="M 58.847656 15.683594 L 49.074219 30.632812 C 46.921875 33.84375 42.480469 36.65625 39.378906 35.300781 C 34.488281 33.164062 35.859375 28.144531 31.28125 25.292969 C 28.070312 23.292969 16.839844 20.449219 14.804688 27.644531 C 13.761719 31.339844 14.480469 37.410156 17.398438 41.019531 C 20.164062 44.441406 26.8125 43.355469 28.898438 47.230469 C 30.34375 49.925781 29.738281 51.628906 28.347656 54.351562 C 26.796875 57.375 22.839844 61.359375 19.265625 64.585938 C 17.480469 66.199219 13.273438 65.710938 12.03125 66.730469 C 11.753906 66.949219 12.511719 70.285156 12.511719 70.285156 C 12.511719 70.285156 19.90625 82.707031 25.539062 87.285156 C 27.773438 89.101562 30.089844 91.808594 32.742188 90.695312 C 36.035156 89.316406 35.304688 82.289062 37.644531 79.597656 C 41.976562 74.605469 50.292969 73.761719 55.582031 78.144531 C 61.277344 82.867188 60.882812 89.472656 57.941406 94.683594 C 55.175781 99.578125 49.472656 98.453125 47.484375 102.28125 C 46.730469 103.730469 47.578125 105.664062 48.765625 106.785156 C 54.628906 112.335938 71.210938 118.988281 71.210938 118.988281 L 81.605469 102.429688 C 83.757812 99.222656 86.707031 97.742188 90.011719 98.46875 C 94.605469 99.472656 95.160156 105.945312 98.914062 108.785156 C 103.195312 112.019531 110.546875 111.765625 114.351562 105.753906 C 117.128906 101.371094 116.761719 97.449219 113.765625 91.414062 C 111.808594 87.476562 103.253906 89.382812 101.171875 85.507812 C 99.722656 82.8125 99.992188 80.214844 101.859375 77.796875 C 106.332031 72 117.003906 62.699219 117.003906 62.699219 C 117.003906 62.699219 117.144531 60.824219 116.246094 59.363281 C 115.15625 57.589844 107.472656 49.273438 104.65625 46.984375 C 102.421875 45.167969 99.6875 41.921875 97.03125 43.035156 C 93.742188 44.414062 94.417969 51.058594 92.082031 53.753906 C 86.5 60.179688 78.4375 59.101562 73.914062 54.648438 C 68.644531 49.453125 68.511719 44.488281 71.453125 39.277344 C 74.222656 34.382812 79.921875 35.3125 81.910156 31.484375 C 82.664062 30.035156 81.484375 27.070312 80.597656 25.390625 C 79.277344 22.890625 65.976562 18.902344 58.847656 15.683594 Z M 58.847656 15.683594 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(20.784314%,51.764709%,89.411765%);fill-opacity:1;" d="M 58.089844 12.347656 L 48.316406 27.300781 C 46.164062 30.507812 41.726562 33.320312 38.625 31.964844 C 33.734375 29.828125 35.101562 24.808594 30.523438 21.960938 C 27.3125 19.957031 19.445312 19.160156 15.683594 25.625 C 13.730469 28.976562 13.722656 34.074219 16.644531 37.6875 C 19.410156 41.105469 26.058594 40.023438 28.140625 43.898438 C 29.589844 46.589844 28.984375 48.292969 27.589844 51.015625 C 24.492188 57.066406 11.753906 66.949219 11.753906 66.949219 C 11.753906 66.949219 19.148438 79.371094 24.785156 83.949219 C 27.019531 85.765625 29.332031 88.472656 31.988281 87.363281 C 35.277344 85.984375 34.550781 78.957031 36.886719 76.261719 C 41.21875 71.273438 49.535156 70.425781 54.824219 74.8125 C 60.519531 79.53125 60.125 86.140625 57.183594 91.347656 C 54.417969 96.242188 48.714844 95.117188 46.726562 98.949219 C 45.976562 100.398438 46.824219 102.328125 48.011719 103.449219 C 53.871094 109 70.457031 115.652344 70.457031 115.652344 L 80.847656 99.097656 C 83 95.886719 85.953125 94.40625 89.257812 95.132812 C 93.847656 96.140625 94.402344 102.609375 98.160156 105.449219 C 102.4375 108.683594 109.789062 108.433594 113.597656 102.421875 C 116.375 98.035156 116.152344 94.195312 112.175781 89.128906 C 109.460938 85.667969 102.496094 86.046875 100.414062 82.171875 C 98.96875 79.480469 99.234375 76.878906 101.101562 74.460938 C 105.578125 68.667969 116.246094 59.363281 116.246094 59.363281 C 116.246094 59.363281 109.535156 48.226562 103.898438 43.648438 C 101.664062 41.835938 98.929688 38.585938 96.277344 39.699219 C 92.988281 41.078125 93.660156 47.726562 91.324219 50.417969 C 85.746094 56.84375 77.679688 55.769531 73.15625 51.3125 C 67.886719 46.121094 67.757812 41.152344 70.699219 35.945312 C 73.464844 31.046875 79.164062 31.980469 81.152344 28.148438 C 81.90625 26.699219 80.066406 24.476562 78.878906 23.355469 C 73.015625 17.804688 58.089844 12.347656 58.089844 12.347656 Z M 58.089844 12.347656 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M6.5 1C5.669 1 5 1.669 5 2.5V4H2c-.554 0-1 .446-1 1v3h1.5C3.331 8 4 8.669 4 9.5S3.331 11 2.5 11H1v3c0 .554.446 1 1 1h3v-1.5c0-.831.669-1.5 1.5-1.5s1.5.669 1.5 1.5V15h3c.554 0 1-.446 1-1v-3h1.5c.831 0 1.5-.669 1.5-1.5S14.331 8 13.5 8H12V5c0-.554-.446-1-1-1H8V2.5C8 1.669 7.331 1 6.5 1z" style="isolation:auto;mix-blend-mode:normal;marker:none" color="#000" overflow="visible" fill="#474747"/></svg>

After

Width:  |  Height:  |  Size: 469 B

1
data/icons/meson.build Normal file
View File

@@ -0,0 +1 @@
install_subdir('hicolor', install_dir: icondir)

View File

@@ -1,6 +1,6 @@
desktop_files = [
'org.gnome.Shell.desktop',
'gnome-shell-extension-prefs.desktop'
'org.gnome.Extensions.desktop',
]
service_files = []
@@ -43,6 +43,7 @@ endforeach
subdir('dbus-interfaces')
subdir('icons')
subdir('theme')
data_resources = [
@@ -72,6 +73,7 @@ configure_file(
)
install_data('gnome-shell.portal', install_dir: portaldir)
install_data('50-gnome-shell-system.xml', install_dir: keysdir)

View File

@@ -1,8 +1,8 @@
[Desktop Entry]
Type=Application
Name=Shell Extensions
Name=Extensions
Icon=org.gnome.Extensions
Comment=Configure GNOME Shell Extensions
Exec=@bindir@/gnome-shell-extension-prefs %u
Categories=GNOME;GTK;
OnlyShowIn=GNOME;
NoDisplay=true

View File

@@ -13,7 +13,6 @@
@import 'widgets/corner-ripple';
@import 'widgets/dash';
@import 'widgets/dialogs';
@import 'widgets/end-session-dialog';
@import 'widgets/entries';
@import 'widgets/hotplug';
@import 'widgets/ibus-popup';
@@ -36,4 +35,4 @@
@import 'widgets/switches';
@import 'widgets/tiled-previews';
@import 'widgets/window-picker';
@import 'widgets/workspace-switcher';
@import 'widgets/workspace-switcher';

View File

@@ -86,14 +86,48 @@ $app_grid_fg_color: #fff;
}
// expanded folder
.app-folder-popup {
-arrow-border-radius: 8px;
-arrow-background-color: transparentize(darken($osd_bg_color,10%), 0.5);
-arrow-base: 24px;
-arrow-rise: 11px;
}
.app-folder-dialog {
border-radius: $modal_radius * 1.5;
border: 1px solid $osd_outer_borders_color;
spacing: 12px;
background-color: transparentize(darken($osd_bg_color,10%), 0.05);
.app-folder-popup-bin { padding: $base_padding - 1px; }
& .folder-name-container {
padding: 24px 36px 0;
spacing: 12px;
& .folder-name-label,
& .folder-name-entry {
font-size: 18pt;
font-weight: bold;
}
& .folder-name-entry { width: 300px }
/* FIXME: this is to keep the label in sync with the entry */
& .folder-name-label { padding: 5px 7px }
& .edit-folder-button {
@extend %button;
padding: 0;
width: 36px;
height: 36px;
border-radius: 18px;
& > StIcon { icon-size: 16px }
}
}
& StButton#vhandle,
& StButton#vhandle:hover,
& StButton#vhandle:active { background-color: transparent; }
}
.app-folder-dialog-container {
padding: 12px;
width: 800px;
height: 600px;
}
.app-folder-icon {
padding: $base_padding;
@@ -205,4 +239,4 @@ $app_grid_fg_color: #fff;
&:last-child {
border-radius: 0 $base_border_radius $base_border_radius 0;
}
}
}

View File

@@ -1,5 +1,7 @@
/* Date/Time Menu */
.clock-display-box { spacing: $base_spacing; }
// overall menu
#calendarArea {
padding:0;
@@ -263,4 +265,4 @@
font-feature-settings: "tnum";
@include fontsize($base_font_size - 1);
}
}
}

View File

@@ -42,7 +42,6 @@ $dash_border_radius: $modal_radius * 1.5;
border:none;
box-shadow:0 0 0 1px $osd_outer_borders_color;
color: $osd_fg_color;
margin-top: $base_margin + 4px;
padding: $base_padding $base_padding + 2px;
text-align: center;
-x-offset: $base_margin * 2; // distance from the dash edge

View File

@@ -19,6 +19,17 @@
@include fontsize($base_font_size + 3);
}
/* End Session Dialog */
.end-session-dialog {
width: 30em;
.end-session-dialog-battery-warning,
.dialog-list-title {
color: $warning_color;
}
}
/* Message Dialog */
.message-dialog-content {
spacing: 18px;
@@ -58,177 +69,79 @@
/* Run Dialog */
.run-dialog {
.run-dialog-entry { width: 20em; margin-bottom: 6px; }
.run-dialog-error-box {
padding-top: 16px;
spacing: 6px;
.modal-dialog-content-box {
margin-top: 24px;
margin-bottom: 14px;
}
.run-dialog-label {
@include fontsize($base_font_size + 1.1);
font-weight: normal;
color: $fg_color;
padding-bottom: .4em;
.run-dialog-entry { width: 20em; }
.run-dialog-description {
@include fontsize($base_font_size - 1);
text-align: center;
color: darken($fg_color, 20%);
}
}
/* ShellMountOperation Dialogs */
.shell-mount-operation-icon {
icon-size: $base_icon_size * 3;
}
.mount-dialog {
spacing: 24px;
.message-dialog-title {
padding-top: 10px;
padding-left: 17px;
padding-bottom: 6px;
max-width: 34em;
}
.message-dialog-title:rtl {
padding-left: 0px;
padding-right: 17px;
}
.message-dialog-description {
padding-left: 17px;
width: 28em;
}
.message-dialog-description:rtl {
padding-left: 0px;
padding-right: 17px;
}
}
.mount-dialog-app-list {
max-height: 200px;
padding-top: 24px;
padding-left: 49px;
padding-right: 32px;
}
.mount-dialog-app-list:rtl {
padding-right: 49px;
padding-left: 32px;
}
.mount-dialog-app-list-item {
color: lighten($fg_color,10%);
&:hover { color: $fg_color; }
&:ltr { padding-right: 1em; }
&:rtl { padding-left: 1em; }
}
.mount-dialog-app-list-item-icon {
&:ltr { padding-right: 17px; }
&:rtl { padding-left: 17px; }
}
.mount-dialog-app-list-item-name {
@include fontsize($base_font_size - 1);
}
/* Password or Authentication Dialog */
.prompt-dialog {
//this is the width of the entire modal popup
width: 34em;
width: 28em;
.message-dialog-content { spacing: $base_spacing * 4; }
.message-dialog-title { color: lighten($fg_color,15%); }
.modal-dialog-content-box {
margin-bottom: 24px;
}
}
.prompt-dialog-description:rtl {
text-align: right;
.prompt-dialog-password-grid {
spacing-rows: 8px;
spacing-columns: 4px;
.prompt-dialog-password-entry {
width: auto;
// 4px (spacing) + 16px (spinner-width)
&:ltr { margin-left: 20px; }
&:rtl { margin-right: 20px; }
}
}
.prompt-dialog-password-box {
spacing: 1em;
padding-bottom: 1em;
.prompt-dialog-password-layout {
spacing: 8px;
}
.prompt-dialog-password-entry {
width: 20em;
}
.prompt-dialog-error-label,
.prompt-dialog-info-label,
.prompt-dialog-null-label {
text-align: center;
@include fontsize($base_font_size - 1);
}
.prompt-dialog-error-label {
@include fontsize($base_font_size - 1);
color: $warning_color;
padding-bottom: 8px;
}
.prompt-dialog-info-label {
@include fontsize($base_font_size - 1);
padding-bottom: 8px;
}
.prompt-dialog-null-label {
@include fontsize($base_font_size - 1);
padding-bottom: 8px;
}
.prompt-dialog-pim-box {
spacing: 1em;
}
.prompt-dialog-grid {
spacing-rows: 15px;
spacing-columns: 1em;
}
.prompt-dialog-keyfiles-box {
spacing: 1em;
}
.prompt-dialog-button.button {
padding: 8px;
}
.prompt-dialog-caps-lock-warning {
@extend .prompt-dialog-error-label;
padding-left: 6.2em;
}
/* Polkit Dialog */
.polkit-dialog-user-layout {
padding-left: 10px;
spacing: 10px;
&:rtl {
padding-left: 0px;
padding-right: 10px;
text-align: center;
spacing: 8px;
margin-bottom: 6px;
.polkit-dialog-user-icon {
border-radius: 99px;
background-size: contain;
}
}
.polkit-dialog-user-root-label {
color: $warning_color;
}
.polkit-dialog-user-icon {
border-radius: 99px;
background-size: contain;
width: 48px;
height: 48px;
.polkit-dialog-user-root-label { color: $warning_color; }
}
/* Audio selection dialog */
.audio-device-selection-dialog {
spacing: 30px;
}
.audio-selection-content {
spacing: 20px;
padding: 24px;
}
.audio-selection-title {
font-weight: bold;
text-align: center;
}
.audio-selection-box {
spacing: 20px;
.modal-dialog-content-box { margin-bottom: 28px; }
.audio-selection-box { spacing: 20px; }
}
.audio-selection-device {
@@ -254,30 +167,3 @@
.access-dialog {
spacing: 30px;
}
/* Geolocation Dialog */
.geolocation-dialog {
spacing: 30px;
}
/* Extension Dialog */
.extension-dialog {
.message-dialog-title { font-weight: normal; color: $fg_color; }
}
/* Inhibit-Shortcuts Dialog */
.inhibit-shortcuts-dialog {
spacing: 30px;
}
/* Network Agent Dialog */
.network-dialog-secret-table {
spacing-rows: 15px;
spacing-columns: 1em;
}
.keyring-dialog-control-table {
spacing-rows: 15px;
spacing-columns: 1em;
}

View File

@@ -1,12 +0,0 @@
/* End Session Dialog */
$end_session_dialog_width: 28em;
.end-session-dialog-battery-warning {
width: $end_session_dialog_width;
color: $warning_color;
}
.end-session-dialog .dialog-list-title {
color: $warning_color;
}

View File

@@ -2,7 +2,7 @@
StEntry {
border-radius: $base_border_radius;
padding: 4px;
padding: 8px;
border-width: 1px;
color: $fg_color;
@include entry(normal);
@@ -20,4 +20,8 @@ StEntry {
icon-size: $base_icon_size;
padding: 0 4px;
}
}
StLabel.hint-text {
margin-left: 2px;
color: transparentize($fg_color, 0.3);
}
}

View File

@@ -24,9 +24,10 @@
&:rtl {padding:0;}
}
// clear button
.message-list-clear-button.button {
margin:$base_margin $base_margin*2;
// do-not-disturb + clear button
.message-list-controls {
margin: $base_margin $base_margin*2;
spacing: $base_spacing;
}
// message bubbles
@@ -83,7 +84,7 @@
}
// fallback
> .fallback-window-icon {
> .fallback-app-icon {
width: $base_icon_size;
height: $base_icon_size;
}

View File

@@ -56,4 +56,12 @@
// Hidden
.hidden { color: rgba(0,0,0,0);}
.hidden { color: rgba(0,0,0,0);}
// Caps-lock warning
.caps-lock-warning-label {
text-align: center;
padding-bottom: 8px;
@include fontsize($base_font_size - 1);
color: $warning_color;
}

View File

@@ -70,8 +70,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
}
#lockDialogGroup {
background: lighten(#2e3436, 8%) url(resource:///org/gnome/shell/theme/noise-texture.png);
background-repeat: repeat;
background-color: lighten(#2e3436, 8%);
}
#screenShieldNotifications {
@@ -80,4 +79,4 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
&:hover, &:focus { background-color: transparentize($bg_color,0.5); }
&:active { background-color: transparentize($selected_bg_color,0.5); }
}
}
}

View File

@@ -14,7 +14,6 @@ theme_sources = files([
'gnome-shell-sass/widgets/_corner-ripple.scss',
'gnome-shell-sass/widgets/_dash.scss',
'gnome-shell-sass/widgets/_dialogs.scss',
'gnome-shell-sass/widgets/_end-session-dialog.scss',
'gnome-shell-sass/widgets/_entries.scss',
'gnome-shell-sass/widgets/_hotplug.scss',
'gnome-shell-sass/widgets/_ibus-popup.scss',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -0,0 +1,11 @@
.details-button image {
transition: 250ms;
}
.details-button.expanded:dir(ltr) image {
-gtk-icon-transform: rotate(0.25turn);
}
.details-button.expanded:dir(rtl) image {
-gtk-icon-transform: rotate(-0.25turn);
}
image.warning { color: @warning_color; }

View File

@@ -3,15 +3,16 @@ imports.gi.versions.Gdk = '3.0';
imports.gi.versions.Gtk = '3.0';
const Gettext = imports.gettext;
const { Gdk, GLib, Gio, GObject, Gtk, Pango } = imports.gi;
const { Gdk, GLib, Gio, GObject, Gtk } = imports.gi;
const Format = imports.format;
const _ = Gettext.gettext;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const { loadInterfaceXML } = imports.misc.fileUtils;
const { ExtensionState } = ExtensionUtils;
const { ExtensionState, ExtensionType } = ExtensionUtils;
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
@@ -27,26 +28,144 @@ class Application extends Gtk.Application {
_init() {
GLib.set_prgname('gnome-shell-extension-prefs');
super._init({
application_id: 'org.gnome.shell.ExtensionPrefs',
application_id: 'org.gnome.Extensions',
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
});
this._startupUuid = null;
this._loaded = false;
this._skipMainWindow = false;
this._shellProxy = null;
}
get shellProxy() {
return this._shellProxy;
}
_showPrefs(uuid) {
let row = this._extensionSelector.get_children().find(c => {
return c.uuid === uuid && c.hasPrefs;
vfunc_activate() {
this._shellProxy.CheckForUpdatesRemote();
this._window.present();
}
vfunc_startup() {
super.vfunc_startup();
let provider = new Gtk.CssProvider();
let uri = 'resource:///org/gnome/shell/css/application.css';
try {
provider.load_from_file(Gio.File.new_for_uri(uri));
} catch (e) {
logError(e, 'Failed to add application style');
}
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
this._window = new ExtensionsWindow({ application: this });
}
vfunc_command_line(commandLine) {
let args = commandLine.get_arguments();
if (args.length) {
let uuid = args[0];
// Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix(uuid, 'extension:///');
this._window.openPrefs(uuid);
} else {
this.activate();
}
return 0;
}
});
var ExtensionsWindow = GObject.registerClass({
GTypeName: 'ExtensionsWindow',
Template: 'resource:///org/gnome/shell/ui/extensions-window.ui',
InternalChildren: [
'userList',
'systemList',
'killSwitch',
'mainBox',
'mainStack',
'scrolledWindow',
'updatesBar',
'updatesLabel',
],
}, class ExtensionsWindow extends Gtk.ApplicationWindow {
_init(params) {
super._init(params);
this._startupUuid = null;
this._loaded = false;
this._prefsDialog = null;
this._updatesCheckId = 0;
this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
let action;
action = new Gio.SimpleAction({ name: 'show-about' });
action.connect('activate', this._showAbout.bind(this));
this.add_action(action);
action = new Gio.SimpleAction({ name: 'logout' });
action.connect('activate', this._logout.bind(this));
this.add_action(action);
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._settings.bind('disable-user-extensions',
this._killSwitch, 'active',
Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._userList.set_sort_func(this._sortList.bind(this));
this._userList.set_header_func(this._updateHeader.bind(this));
this._systemList.set_sort_func(this._sortList.bind(this));
this._systemList.set_header_func(this._updateHeader.bind(this));
this._shellProxy.connectSignal('ExtensionStateChanged',
this._onExtensionStateChanged.bind(this));
this._scanExtensions();
}
get _shellProxy() {
return this.application.shellProxy;
}
uninstall(uuid) {
let row = this._findExtensionRow(uuid);
let dialog = new Gtk.MessageDialog({
transient_for: this,
modal: true,
text: _('Remove “%s”?').format(row.name),
secondary_text: _('If you remove the extension, you need to return to download it if you want to enable it again'),
});
if (!row)
dialog.add_button(_('Cancel'), Gtk.ResponseType.CANCEL);
dialog.add_button(_('Remove'), Gtk.ResponseType.ACCEPT)
.get_style_context().add_class('destructive-action');
dialog.connect('response', (dlg, response) => {
if (response === Gtk.ResponseType.ACCEPT)
this._shellProxy.UninstallExtensionRemote(uuid);
dialog.destroy();
});
dialog.present();
}
openPrefs(uuid) {
if (!this._loaded)
this._startupUuid = uuid;
else if (!this._showPrefs(uuid))
this.present();
}
_showPrefs(uuid) {
if (this._prefsDialog)
return false;
let row = this._findExtensionRow(uuid);
if (!row || !row.hasPrefs)
return false;
let widget;
@@ -57,33 +176,73 @@ class Application extends Gtk.Application {
widget = this._buildErrorUI(row, e);
}
let dialog = new Gtk.Window({
modal: !this._skipMainWindow,
this._prefsDialog = new Gtk.Window({
application: this.application,
default_width: 600,
default_height: 400,
modal: this.visible,
type_hint: Gdk.WindowTypeHint.DIALOG,
window_position: Gtk.WindowPosition.CENTER,
});
dialog.set_titlebar(new Gtk.HeaderBar({
this._prefsDialog.set_titlebar(new Gtk.HeaderBar({
show_close_button: true,
title: row.name,
visible: true,
}));
if (this._skipMainWindow) {
this.add_window(dialog);
if (this._window)
this._window.destroy();
this._window = dialog;
this._window.window_position = Gtk.WindowPosition.CENTER;
} else {
dialog.transient_for = this._window;
}
if (this.visible)
this._prefsDialog.transient_for = this;
dialog.set_default_size(600, 400);
dialog.add(widget);
dialog.show();
this._prefsDialog.connect('destroy', () => {
this._prefsDialog = null;
if (!this.visible)
this.destroy();
});
this._prefsDialog.add(widget);
this._prefsDialog.show();
return true;
}
_showAbout() {
let aboutDialog = new Gtk.AboutDialog({
authors: [
'Florian Müllner <fmuellner@gnome.org>',
'Jasper St. Pierre <jstpierre@mecheye.net>',
'Didier Roche <didrocks@ubuntu.com>',
],
translator_credits: _('translator-credits'),
program_name: _('Extensions'),
comments: _('Manage your GNOME Extensions'),
license_type: Gtk.License.GPL_2_0,
logo_icon_name: 'org.gnome.Extensions',
version: Config.PACKAGE_VERSION,
transient_for: this,
modal: true,
});
aboutDialog.present();
}
_logout() {
this.application.get_dbus_connection().call(
'org.gnome.SessionManager',
'/org/gnome/SessionManager',
'org.gnome.SessionManager',
'Logout',
new GLib.Variant('(u)', [0]),
null,
Gio.DBusCallFlags.NONE,
-1,
null,
(o, res) => {
o.call_finish(res);
});
}
_buildErrorUI(row, exc) {
let scroll = new Gtk.ScrolledWindow({
hscrollbar_policy: Gtk.PolicyType.NEVER,
@@ -178,7 +337,7 @@ class Application extends Gtk.Application {
label: _("Homepage"),
tooltip_text: _("Visit extension homepage"),
no_show_all: true,
visible: row.url != null,
visible: row.url !== '',
});
toolbar.add(urlButton);
@@ -199,47 +358,6 @@ class Application extends Gtk.Application {
return scroll;
}
_buildUI() {
this._window = new Gtk.ApplicationWindow({ application: this,
window_position: Gtk.WindowPosition.CENTER });
this._window.set_default_size(800, 500);
this._titlebar = new Gtk.HeaderBar({ show_close_button: true,
title: _("Shell Extensions") });
this._window.set_titlebar(this._titlebar);
let killSwitch = new Gtk.Switch({ valign: Gtk.Align.CENTER });
this._titlebar.pack_end(killSwitch);
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._settings.bind('disable-user-extensions', killSwitch, 'active',
Gio.SettingsBindFlags.DEFAULT |
Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._mainStack = new Gtk.Stack({
transition_type: Gtk.StackTransitionType.CROSSFADE,
});
this._window.add(this._mainStack);
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER });
this._extensionSelector = new Gtk.ListBox({ selection_mode: Gtk.SelectionMode.NONE });
this._extensionSelector.set_sort_func(this._sortList.bind(this));
this._extensionSelector.set_header_func(this._updateHeader.bind(this));
scroll.add(this._extensionSelector);
this._mainStack.add_named(scroll, 'listing');
this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder');
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
this._shellProxy.connectSignal('ExtensionStateChanged',
this._onExtensionStateChanged.bind(this));
this._window.show_all();
}
_sortList(row1, row2) {
return row1.name.localeCompare(row2.name);
}
@@ -253,13 +371,26 @@ class Application extends Gtk.Application {
}
_findExtensionRow(uuid) {
return this._extensionSelector.get_children().find(c => c.uuid === uuid);
return [
...this._userList.get_children(),
...this._systemList.get_children(),
].find(c => c.uuid === uuid);
}
_onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
let extension = ExtensionUtils.deserializeExtension(newState);
let row = this._findExtensionRow(uuid);
this._queueUpdatesCheck();
// the extension's type changed; remove the corresponding row
// and reset the variable to null so that we create a new row
// below and add it to the appropriate list
if (row && row.type !== extension.type) {
row.destroy();
row = null;
}
if (row) {
if (extension.state === ExtensionState.UNINSTALLED)
row.destroy();
@@ -273,7 +404,6 @@ class Application extends Gtk.Application {
if (e) {
if (e instanceof Gio.DBusError) {
log(`Failed to connect to shell proxy: ${e}`);
this._mainStack.add_named(new NoShellPlaceholder(), 'noshell');
this._mainStack.visible_child_name = 'noshell';
} else {
throw e;
@@ -291,58 +421,53 @@ class Application extends Gtk.Application {
_addExtensionRow(extension) {
let row = new ExtensionRow(extension);
row.prefsButton.connect('clicked', () => {
this._showPrefs(row.uuid);
});
row.show_all();
this._extensionSelector.add(row);
if (row.type === ExtensionType.PER_USER)
this._userList.add(row);
else
this._systemList.add(row);
}
_queueUpdatesCheck() {
if (this._updatesCheckId)
return;
this._updatesCheckId = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT, 1, () => {
this._checkUpdates();
this._updatesCheckId = 0;
return GLib.SOURCE_REMOVE;
});
}
_checkUpdates() {
let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length;
this._updatesLabel.label = Gettext.ngettext(
'%d extension will be updated on next login.',
'%d extensions will be updated on next login.e',
nUpdates).format(nUpdates);
this._updatesBar.visible = nUpdates > 0;
}
_extensionsLoaded() {
if (this._extensionSelector.get_children().length > 0)
this._mainStack.visible_child_name = 'listing';
this._userList.visible = this._userList.get_children().length > 0;
this._systemList.visible = this._systemList.get_children().length > 0;
if (this._userList.visible || this._systemList.visible)
this._mainStack.visible_child_name = 'main';
else
this._mainStack.visible_child_name = 'placeholder';
this._checkUpdates();
if (this._startupUuid)
this._showPrefs(this._startupUuid);
this._startupUuid = null;
this._skipMainWindow = false;
this._loaded = true;
}
vfunc_activate() {
this._window.present();
}
vfunc_startup() {
super.vfunc_startup();
this._buildUI();
this._scanExtensions();
}
vfunc_command_line(commandLine) {
this.activate();
let args = commandLine.get_arguments();
if (args.length) {
let uuid = args[0];
this._skipMainWindow = true;
// Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix(uuid, "extension:///");
if (!this._loaded)
this._startupUuid = uuid;
else if (!this._showPrefs(uuid))
this._skipMainWindow = false;
}
return 0;
}
});
var Expander = GObject.registerClass({
@@ -444,113 +569,19 @@ var Expander = GObject.registerClass({
}
});
var EmptyPlaceholder = GObject.registerClass(
class EmptyPlaceholder extends Gtk.Box {
_init() {
super._init({
orientation: Gtk.Orientation.VERTICAL,
spacing: 6,
margin: 32,
});
let image = new Gtk.Image({
icon_name: 'application-x-addon-symbolic',
pixel_size: 96,
visible: true,
vexpand: true,
valign: Gtk.Align.END,
});
image.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
this.add(image);
let label = new Gtk.Label({
label: `<b><span size="x-large">${_("No Extensions Installed")}</span></b>`,
use_markup: true,
visible: true,
});
label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
this.add(label);
let appInfo = Gio.DesktopAppInfo.new('org.gnome.Software.desktop');
let desc = new Gtk.Label({
label: _("Extensions can be installed through Software or <a href=\"https://extensions.gnome.org\">extensions.gnome.org</a>."),
use_markup: true,
wrap: true,
justify: Gtk.Justification.CENTER,
visible: true,
max_width_chars: 50,
hexpand: true,
vexpand: appInfo == null,
halign: Gtk.Align.CENTER,
valign: Gtk.Align.START,
});
this.add(desc);
if (appInfo) {
let button = new Gtk.Button({
label: _("Browse in Software"),
image: new Gtk.Image({
icon_name: "org.gnome.Software-symbolic",
}),
always_show_image: true,
margin_top: 12,
visible: true,
halign: Gtk.Align.CENTER,
valign: Gtk.Align.START,
vexpand: true,
});
this.add(button);
button.connect('clicked', w => {
let context = w.get_display().get_app_launch_context();
appInfo.launch([], context);
});
}
}
});
var NoShellPlaceholder = GObject.registerClass(
class NoShellPlaceholder extends Gtk.Box {
_init() {
super._init({
orientation: Gtk.Orientation.VERTICAL,
spacing: 12,
margin: 100,
margin_bottom: 60,
});
let label = new Gtk.Label({
label: '<span size="x-large">%s</span>'.format(
_("Somethings gone wrong")),
use_markup: true,
});
label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
this.add(label);
label = new Gtk.Label({
label: _("Were very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again."),
justify: Gtk.Justification.CENTER,
wrap: true,
});
this.add(label);
this.show_all();
}
});
var DescriptionLabel = GObject.registerClass(
class DescriptionLabel extends Gtk.Label {
vfunc_get_preferred_height_for_width(width) {
// Hack: Request the maximum height allowed by the line limit
if (this.lines > 0)
return super.vfunc_get_preferred_height_for_width(0);
return super.vfunc_get_preferred_height_for_width(width);
}
});
var ExtensionRow = GObject.registerClass(
class ExtensionRow extends Gtk.ListBoxRow {
var ExtensionRow = GObject.registerClass({
GTypeName: 'ExtensionRow',
Template: 'resource:///org/gnome/shell/ui/extension-row.ui',
InternalChildren: [
'nameLabel',
'descriptionLabel',
'versionLabel',
'authorLabel',
'updatesIcon',
'revealButton',
'revealer',
],
}, class ExtensionRow extends Gtk.ListBoxRow {
_init(extension) {
super._init();
@@ -558,9 +589,67 @@ class ExtensionRow extends Gtk.ListBoxRow {
this._extension = extension;
this._prefsModule = null;
this.connect('destroy', this._onDestroy.bind(this));
this._actionGroup = new Gio.SimpleActionGroup();
this.insert_action_group('row', this._actionGroup);
this._buildUI();
let action;
action = new Gio.SimpleAction({
name: 'show-prefs',
enabled: this.hasPrefs,
});
action.connect('activate', () => this.get_toplevel().openPrefs(this.uuid));
this._actionGroup.add_action(action);
action = new Gio.SimpleAction({
name: 'show-url',
enabled: this.url !== '',
});
action.connect('activate', () => {
Gio.AppInfo.launch_default_for_uri(
this.url, this.get_display().get_app_launch_context());
});
this._actionGroup.add_action(action);
action = new Gio.SimpleAction({
name: 'uninstall',
enabled: this.type === ExtensionType.PER_USER,
});
action.connect('activate', () => this.get_toplevel().uninstall(this.uuid));
this._actionGroup.add_action(action);
action = new Gio.SimpleAction({
name: 'enabled',
state: new GLib.Variant('b', false),
});
action.connect('activate', () => {
let state = action.get_state();
action.change_state(new GLib.Variant('b', !state.get_boolean()));
});
action.connect('change-state', (a, state) => {
if (state.get_boolean())
this._app.shellProxy.EnableExtensionRemote(this.uuid);
else
this._app.shellProxy.DisableExtensionRemote(this.uuid);
});
this._actionGroup.add_action(action);
let name = GLib.markup_escape_text(this.name, -1);
this._nameLabel.label = name;
let desc = this._extension.metadata.description.split('\n')[0];
this._descriptionLabel.label = desc;
this._revealButton.connect('clicked', () => {
this._revealer.reveal_child = !this._revealer.reveal_child;
});
this._revealer.connect('notify::reveal-child', () => {
if (this._revealer.reveal_child)
this._revealButton.get_style_context().add_class('expanded');
else
this._revealButton.get_style_context().remove_class('expanded');
});
this.connect('destroy', this._onDestroy.bind(this));
this._extensionStateChangedId = this._app.shellProxy.connectSignal(
'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
@@ -568,14 +657,9 @@ class ExtensionRow extends Gtk.ListBoxRow {
return;
this._extension = ExtensionUtils.deserializeExtension(newState);
let state = this._extension.state == ExtensionState.ENABLED;
this._switch.block_signal_handler(this._notifyActiveId);
this._switch.state = state;
this._switch.unblock_signal_handler(this._notifyActiveId);
this._switch.sensitive = this._canToggle();
this._updateState();
});
this._updateState();
}
get uuid() {
@@ -590,8 +674,40 @@ class ExtensionRow extends Gtk.ListBoxRow {
return this._extension.hasPrefs;
}
get hasUpdate() {
return this._extension.hasUpdate || false;
}
get type() {
return this._extension.type;
}
get creator() {
return this._extension.metadata.creator || '';
}
get url() {
return this._extension.metadata.url;
return this._extension.metadata.url || '';
}
get version() {
return this._extension.metadata.version || '';
}
_updateState() {
let state = this._extension.state === ExtensionState.ENABLED;
let action = this._actionGroup.lookup('enabled');
action.set_state(new GLib.Variant('b', state));
action.enabled = this._canToggle();
this._updatesIcon.visible = this.hasUpdate;
this._versionLabel.label = `${this.version}`;
this._versionLabel.visible = this.version !== '';
this._authorLabel.label = `${this.creator}`;
this._authorLabel.visible = this.creator !== '';
}
_onDestroy() {
@@ -603,54 +719,6 @@ class ExtensionRow extends Gtk.ListBoxRow {
this._extensionStateChangedId = 0;
}
_buildUI() {
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
hexpand: true, margin_end: 24, spacing: 24,
margin: 12 });
this.add(hbox);
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
spacing: 6, hexpand: true });
hbox.add(vbox);
let name = GLib.markup_escape_text(this.name, -1);
let label = new Gtk.Label({ label: '<b>' + name + '</b>',
use_markup: true,
halign: Gtk.Align.START });
vbox.add(label);
let desc = this._extension.metadata.description.split('\n')[0];
label = new DescriptionLabel({ label: desc, wrap: true, lines: 2,
ellipsize: Pango.EllipsizeMode.END,
xalign: 0, yalign: 0 });
vbox.add(label);
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
visible: this.hasPrefs,
no_show_all: true });
button.set_image(new Gtk.Image({ icon_name: 'emblem-system-symbolic',
icon_size: Gtk.IconSize.BUTTON,
visible: true }));
button.get_style_context().add_class('circular');
hbox.add(button);
this.prefsButton = button;
this._switch = new Gtk.Switch({
valign: Gtk.Align.CENTER,
sensitive: this._canToggle(),
state: this._extension.state === ExtensionState.ENABLED,
});
this._notifyActiveId = this._switch.connect('notify::active', () => {
if (this._switch.active)
this._app.shellProxy.EnableExtensionRemote(this.uuid);
else
this._app.shellProxy.DisableExtensionRemote(this.uuid);
});
this._switch.connect('state-set', () => true);
hbox.add(this._switch);
}
_canToggle() {
return this._extension.canChange;
}

View File

@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="ExtensionRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="activatable">False</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="margin">12</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="nameLabel">
<property name="visible">True</property>
</object>
</child>
<child>
<object class="GtkImage" id="updatesIcon">
<property name="no_show_all">True</property>
<property name="icon_name">software-update-available-symbolic</property>
<style>
<class name="warning"/>>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="hexpand">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="prefsButton">
<property name="no_show_all">True</property>
<property name="visible"
bind-source="prefsButton"
bind-property="sensitive"
bind-flags="sync-create"/>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<property name="action-name">row.show-prefs</property>
<style>
<class name="circular"/>>
<class name="image-button"/>>
</style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">emblem-system-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSwitch">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="valign">center</property>
<property name="action-name">row.enabled</property>
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="revealButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<style>
<class name="details-button"/>
<class name="image-button"/>
<class name="flat"/>
</style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">pan-end-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkRevealer" id="revealer">
<property name="visible">True</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="margin_top">12</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Description</property>
<property name="xalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="descriptionLabel">
<property name="visible">True</property>
<property name="ellipsize">end</property>
<property name="max_width_chars">60</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible"
bind-source="versionLabel"
bind-property="visible"
bind-flags="sync-create"/>
<property name="no_show_all">True</property>
<property name="label" translatable="yes">Version</property>
<property name="xalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="versionLabel">
<property name="no_show_all">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible"
bind-source="authorLabel"
bind-property="visible"
bind-flags="sync-create"/>
<property name="no_show_all">True</property>
<property name="label" translatable="yes">Author</property>
<property name="xalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="authorLabel">
<property name="no_show_all">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="label" translatable="yes">Website</property>
<property name="action_name">row.show-url</property>
<property name="valign">end</property>
<property name="margin-top">12</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="removeButton">
<property name="visible"
bind-source="removeButton"
bind-property="sensitive"
bind-flags="sync-create"/>
<property name="no_show_all">True</property>
<property name="label" translatable="yes">Remove…</property>
<property name="action_name">row.uninstall</property>
<property name="hexpand">True</property>
<property name="halign">end</property>
<property name="valign">end</property>
<style>
<class name="destructive-action"/>
</style>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">7</property>
</packing>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,305 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<menu id="primary-menu">
<section>
<item>
<attribute name="label" translatable="yes">Help</attribute>
<attribute name="action">win.show-help</attribute>
</item>
<item>
<attribute name="label" translatable="yes">About Extensions</attribute>
<attribute name="action">win.show-about</attribute>
</item>
</section>
</menu>
<object class="GtkPopover" id="infoPopover">
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin">12</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">To find and add extensions, visit &lt;a href="https://extensions.gnome.org"&gt;extensions.gnome.org&lt;/a&gt;.</property>
<property name="use_markup">True</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Warning</property>
<property name="xalign">0</property>
<property name="margin_top">6</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Extensions can cause system issues, including performance problems. If you encounter problems with your system, it is recommended to disable all extensions.</property>
<property name="wrap">True</property>
<property name="max_width_chars">40</property>
<property name="xalign">0</property>
</object>
</child>
</object>
</child>
</object>
<template class="ExtensionsWindow" parent="GtkApplicationWindow">
<property name="default_width">800</property>
<property name="default_height">500</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="title" translatable="yes">Extensions</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="popover">infoPopover</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">dialog-information-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton" id="menuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="menu_model">primary-menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="killSwitch">
<property name="visible">True</property>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkStack" id="mainStack">
<property name="visible">True</property>
<property name="transition_type">crossfade</property>
<property name="vexpand">True</property>
<child>
<object class="GtkScrolledWindow" id="scrolledWindow">
<property name="visible">True</property>
<property name="hscrollbar_policy">never</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<child>
<object class="GtkBox" id="mainBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="halign">center</property>
<property name="margin">36</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible"
bind-source="userList"
bind-property="visible"
bind-flags="sync-create"/>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Manually Installed</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkListBox" id="userList">
<property name="visible">True</property>
<property name="selection_mode">none</property>
<property name="margin_bottom">24</property>
<style>
<class name="frame"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible"
bind-source="systemList"
bind-property="visible"
bind-flags="sync-create"/>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Built-In</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkListBox" id="systemList">
<property name="visible">True</property>
<property name="selection_mode">none</property>
<style>
<class name="frame"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">main</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin">32</property>
<property name="spacing">6</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="pixel_size">96</property>
<property name="icon_name">org.gnome.Extensions-symbolic</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">No Installed Extensions</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="name">placeholder</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="margin_left">100</property>
<property name="margin_right">100</property>
<property name="margin_top">100</property>
<property name="margin_bottom">60</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Somethings gone wrong</property>
<attributes>
<attribute name="scale" value="1.44"/>
</attributes>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Were very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
<packing>
<property name="name">noshell</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkActionBar" id="updatesBar">
<property name="no_show_all">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="pixel-size">24</property>
<property name="margin">6</property>
<property name="icon_name">software-update-available-symbolic</property>
<style>
<class name="warning"/>>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="halign">start</property>
<property name="label">Extension Updates Ready</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel" id="updatesLabel">
<property name="visible">True</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Logout…</property>
<property name="visible">True</property>
<property name="valign">center</property>
<property name="action-name">win.logout</property>
<property name="receives_default">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -17,10 +17,6 @@ var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300;
var MESSAGE_FADE_OUT_ANIMATION_TIME = 500;
const WIGGLE_OFFSET = 6;
const WIGGLE_DURATION = 65;
const N_WIGGLES = 3;
var AuthPromptMode = {
UNLOCK_ONLY: 0,
UNLOCK_OR_LOG_IN: 1,
@@ -282,11 +278,7 @@ var AuthPrompt = GObject.registerClass({
this.setActorInDefaultButtonWell(null);
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
Util.wiggle(this._entry, {
offset: WIGGLE_OFFSET,
duration: WIGGLE_DURATION,
wiggleCount: N_WIGGLES,
});
Util.wiggle(this._entry);
}
_onVerificationComplete() {

View File

@@ -32,6 +32,7 @@
<file>perf/core.js</file>
<file>perf/hwtest.js</file>
<file>ui/accessDialog.js</file>
<file>ui/altTab.js</file>
<file>ui/animation.js</file>
<file>ui/appDisplay.js</file>

View File

@@ -31,7 +31,15 @@ var ExtensionState = {
UNINSTALLED: 99,
};
const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange'];
const SERIALIZED_PROPERTIES = [
'type',
'state',
'path',
'error',
'hasPrefs',
'hasUpdate',
'canChange',
];
/**
* getCurrentExtension:

View File

@@ -125,11 +125,10 @@ const SystemActions = GObject.registerClass({
available: false,
});
this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
// Translators: The name of the lock orientation action in search
name: C_("search-result", "Lock Orientation"),
name: '',
iconName: '',
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
keywords: _("lock orientation;screen;rotation").split(/[; ]/),
keywords: _("lock orientation;unlock orientation;screen;rotation").split(/[; ]/),
available: false,
});
@@ -167,11 +166,10 @@ const SystemActions = GObject.registerClass({
this.forceUpdate();
this._orientationSettings.connect('changed::orientation-lock',
() => {
this._updateOrientationLock();
this._updateOrientationLockIcon();
});
this._orientationSettings.connect('changed::orientation-lock', () => {
this._updateOrientationLock();
this._updateOrientationLockStatus();
});
Main.layoutManager.connect('monitors-changed',
() => this._updateOrientationLock());
this._sensorProxy = new SensorProxy(Gio.DBus.system,
@@ -190,7 +188,7 @@ const SystemActions = GObject.registerClass({
this._updateOrientationLock();
});
this._updateOrientationLock();
this._updateOrientationLockIcon();
this._updateOrientationLockStatus();
Main.sessionMode.connect('updated', () => this._sessionUpdated());
this._sessionUpdated();
@@ -243,12 +241,21 @@ const SystemActions = GObject.registerClass({
this.notify('can-lock-orientation');
}
_updateOrientationLockIcon() {
_updateOrientationLockStatus() {
let locked = this._orientationSettings.get_boolean('orientation-lock');
let action = this._actions.get(LOCK_ORIENTATION_ACTION_ID);
// Translators: The name of the lock orientation action in search
// and in the system status menu
let name = locked
? C_('search-result', 'Unlock Screen Rotation')
: C_('search-result', 'Lock Screen Rotation');
let iconName = locked
? 'rotation-locked-symbolic'
: 'rotation-allowed-symbolic';
this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName = iconName;
action.name = name;
action.iconName = iconName;
this.notify('orientation-lock-icon');
}

View File

@@ -11,6 +11,10 @@ const Params = imports.misc.params;
var SCROLL_TIME = 100;
const WIGGLE_OFFSET = 6;
const WIGGLE_DURATION = 65;
const N_WIGGLES = 3;
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
const _balancedParens = '\\([^\\s()<>]+\\)';
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
@@ -442,9 +446,9 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
function wiggle(actor, params) {
params = Params.parse(params, {
offset: 0,
duration: 0,
wiggleCount: 0,
offset: WIGGLE_OFFSET,
duration: WIGGLE_DURATION,
wiggleCount: N_WIGGLES,
});
actor.translation_x = 0;

View File

@@ -1,4 +1,6 @@
/* exported main */
imports.gi.versions.Gtk = '3.0';
const Format = imports.format;
const Gettext = imports.gettext;
const { Gio, GLib, GObject, Gtk, Pango, Soup, WebKit2: WebKit } = imports.gi;

View File

@@ -7,5 +7,10 @@
<file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file>
<file>misc/params.js</file>
<file alias="css/application.css">extensionPrefs/css/application.css</file>
<file alias="ui/extension-row.ui">extensionPrefs/ui/extension-row.ui</file>
<file alias="ui/extensions-window.ui">extensionPrefs/ui/extensions-window.ui</file>
</gresource>
</gresources>

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

@@ -0,0 +1,156 @@
/* exported AccessDialogDBus */
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
const CheckBox = imports.ui.checkBox;
const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
const { loadInterfaceXML } = imports.misc.fileUtils;
const RequestIface = loadInterfaceXML('org.freedesktop.impl.portal.Request');
const AccessIface = loadInterfaceXML('org.freedesktop.impl.portal.Access');
var DialogResponse = {
OK: 0,
CANCEL: 1,
CLOSED: 2,
};
var AccessDialog = GObject.registerClass(
class AccessDialog extends ModalDialog.ModalDialog {
_init(invocation, handle, title, description, body, options) {
super._init({ styleClass: 'access-dialog' });
this._invocation = invocation;
this._handle = handle;
this._requestExported = false;
this._request = Gio.DBusExportedObject.wrapJSObject(RequestIface, this);
for (let option in options)
options[option] = options[option].deep_unpack();
this._buildLayout(title, description, body, options);
}
_buildLayout(title, description, body, options) {
// No support for non-modal system dialogs, so ignore the option
// let modal = options['modal'] || true;
let denyLabel = options['deny_label'] || _("Deny Access");
let grantLabel = options['grant_label'] || _("Grant Access");
let choices = options['choices'] || [];
let content = new Dialog.MessageDialogContent({ title, description });
this.contentLayout.add_actor(content);
this._choices = new Map();
for (let i = 0; i < choices.length; i++) {
let [id, name, opts, selected] = choices[i];
if (opts.length > 0)
continue; // radio buttons, not implemented
let check = new CheckBox.CheckBox();
check.getLabelActor().text = name;
check.checked = selected == "true";
content.add_child(check);
this._choices.set(id, check);
}
let bodyLabel = new St.Label({
text: body,
x_align: Clutter.ActorAlign.CENTER,
});
content.add_child(bodyLabel);
this.addButton({ label: denyLabel,
action: () => {
this._sendResponse(DialogResponse.CANCEL);
},
key: Clutter.KEY_Escape });
this.addButton({ label: grantLabel,
action: () => {
this._sendResponse(DialogResponse.OK);
} });
}
open() {
super.open();
let connection = this._invocation.get_connection();
this._requestExported = this._request.export(connection, this._handle);
}
CloseAsync(invocation, _params) {
if (this._invocation.get_sender() != invocation.get_sender()) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'');
return;
}
this._sendResponse(DialogResponse.CLOSED);
}
_sendResponse(response) {
if (this._requestExported)
this._request.unexport();
this._requestExported = false;
let results = {};
if (response == DialogResponse.OK) {
for (let [id, check] of this._choices) {
let checked = check.checked ? 'true' : 'false';
results[id] = new GLib.Variant('s', checked);
}
}
// Delay actual response until the end of the close animation (if any)
this.connect('closed', () => {
this._invocation.return_value(new GLib.Variant('(ua{sv})',
[response, results]));
});
this.close();
}
});
var AccessDialogDBus = class {
constructor() {
this._accessDialog = null;
this._windowTracker = Shell.WindowTracker.get_default();
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(AccessIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/portal/desktop');
Gio.DBus.session.own_name('org.freedesktop.impl.portal.desktop.gnome', Gio.BusNameOwnerFlags.REPLACE, null, null);
}
AccessDialogAsync(params, invocation) {
if (this._accessDialog) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.LIMITS_EXCEEDED,
'Already showing a system access dialog');
return;
}
let [handle, appId, parentWindow_, title, description, body, options] = params;
// We probably want to use parentWindow and global.display.focus_window
// for this check in the future
if (appId && `${appId}.desktop` != this._windowTracker.focus_app.id) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'Only the focused app is allowed to show a system access dialog');
return;
}
let dialog = new AccessDialog(
invocation, handle, title, description, body, options);
dialog.open();
dialog.connect('closed', () => (this._accessDialog = null));
this._accessDialog = dialog;
}
};

View File

@@ -12,14 +12,22 @@ var SPINNER_ANIMATION_DELAY = 1000;
var Animation = GObject.registerClass(
class Animation extends St.Bin {
_init(file, width, height, speed) {
super._init({ width, height });
const themeContext = St.ThemeContext.get_for_stage(global.stage);
super._init({
width: width * themeContext.scale_factor,
height: height * themeContext.scale_factor,
});
this.connect('destroy', this._onDestroy.bind(this));
this.connect('resource-scale-changed',
this._loadFile.bind(this, file, width, height));
let themeContext = St.ThemeContext.get_for_stage(global.stage);
this._scaleChangedId = themeContext.connect('notify::scale-factor',
this._loadFile.bind(this, file, width, height));
() => {
this._loadFile(file, width, height);
this.set_size(width * themeContext.scale_factor, height * themeContext.scale_factor);
});
this._speed = speed;

View File

@@ -5,7 +5,6 @@ const { Clutter, Gio, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi;
const Signals = imports.signals;
const AppFavorites = imports.ui.appFavorites;
const BoxPointer = imports.ui.boxpointer;
const DND = imports.ui.dnd;
const GrabHelper = imports.ui.grabHelper;
const IconGrid = imports.ui.iconGrid;
@@ -41,6 +40,8 @@ var PAGE_SWITCH_TIME = 250;
var APP_ICON_SCALE_IN_TIME = 500;
var APP_ICON_SCALE_IN_DELAY = 700;
const FOLDER_DIALOG_ANIMATION_TIME = 200;
const OVERSHOOT_THRESHOLD = 20;
const OVERSHOOT_TIMEOUT = 1000;
@@ -297,7 +298,6 @@ var BaseAppView = GObject.registerClass({
});
var AllView = GObject.registerClass({
Signals: { 'space-ready': {} },
}, class AllView extends BaseAppView {
_init() {
super._init({
@@ -364,19 +364,19 @@ var AllView = GObject.registerClass({
this._clickAction = new Clutter.ClickAction();
this._clickAction.connect('clicked', () => {
if (!this._currentPopup)
if (!this._currentDialog)
return;
let [x, y] = this._clickAction.get_coords();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
if (!this._currentPopup.contains(actor))
this._currentPopup.popdown();
if (!this._currentDialog.contains(actor))
this._currentDialog.popdown();
});
this._eventBlocker.add_action(this._clickAction);
this._currentPopup = null;
this._displayingPopup = false;
this._currentPopupDestroyId = 0;
this._currentDialog = null;
this._displayingDialog = false;
this._currentDialogDestroyId = 0;
this._canScroll = true; // limiting scrolling speed
this._scrollTimeoutId = 0;
@@ -388,16 +388,6 @@ var AllView = GObject.registerClass({
this._lastOvershootTimeoutId = 0;
Main.overview.connect('hidden', () => this.goToPage(0));
this._grid.connect('space-opened', () => {
let fadeEffect = this._scrollView.get_effect('fade');
if (fadeEffect)
fadeEffect.enabled = false;
this.emit('space-ready');
});
this._grid.connect('space-closed', () => {
this._displayingPopup = false;
});
this._redisplayWorkId = Main.initializeDeferredWork(this, this._redisplay.bind(this));
@@ -547,8 +537,8 @@ var AllView = GObject.registerClass({
};
if (animationDirection == IconGrid.AnimationDirection.OUT &&
this._displayingPopup && this._currentPopup) {
this._currentPopup.popdown();
this._displayingDialog && this._currentDialog) {
this._currentDialog.popdown();
let spaceClosedId = this._grid.connect('space-closed', () => {
this._grid.disconnect(spaceClosedId);
super.animate(animationDirection, completionFunc);
@@ -563,9 +553,9 @@ var AllView = GObject.registerClass({
animateSwitch(animationDirection) {
super.animateSwitch(animationDirection);
if (this._currentPopup && this._displayingPopup &&
if (this._currentDialog && this._displayingDialog &&
animationDirection == IconGrid.AnimationDirection.OUT) {
this._currentPopup.ease({
this._currentDialog.ease({
opacity: 0,
duration: VIEWS_SWITCH_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
@@ -577,17 +567,15 @@ var AllView = GObject.registerClass({
this._pageIndicators.animateIndicators(animationDirection);
}
getCurrentPageY() {
return this._grid.getPageY(this._grid.currentPage);
}
goToPage(pageNumber, animate = true) {
pageNumber = clamp(pageNumber, 0, this._grid.nPages() - 1);
if (this._grid.currentPage == pageNumber && this._displayingPopup && this._currentPopup)
if (this._grid.currentPage === pageNumber &&
this._displayingDialog &&
this._currentDialog)
return;
if (this._displayingPopup && this._currentPopup)
this._currentPopup.popdown();
if (this._displayingDialog && this._currentDialog)
this._currentDialog.popdown();
if (!this.mapped) {
this._adjustment.value = this._grid.getPageY(pageNumber);
@@ -608,24 +596,8 @@ var AllView = GObject.registerClass({
});
}
openSpaceForPopup(item, side, nRows) {
this._updateIconOpacities(true);
this._displayingPopup = true;
this._grid.openExtraSpace(item, side, nRows);
}
_closeSpaceForPopup() {
this._updateIconOpacities(false);
let fadeEffect = this._scrollView.get_effect('fade');
if (fadeEffect)
fadeEffect.enabled = true;
this._grid.closeExtraSpace();
}
_onScroll(actor, event) {
if (this._displayingPopup || !this._scrollView.reactive)
if (this._displayingDialog || !this._scrollView.reactive)
return Clutter.EVENT_STOP;
if (this._swipeTracker.canHandleScrollEvent(event))
@@ -687,7 +659,7 @@ var AllView = GObject.registerClass({
}
_onKeyPressEvent(actor, event) {
if (this._displayingPopup)
if (this._displayingDialog)
return Clutter.EVENT_STOP;
if (event.get_key_symbol() === Clutter.KEY_Page_Up) {
@@ -701,29 +673,34 @@ var AllView = GObject.registerClass({
return Clutter.EVENT_PROPAGATE;
}
addFolderPopup(popup) {
this._stack.add_actor(popup);
popup.connect('open-state-changed', (o, isOpen) => {
addFolderDialog(dialog) {
this.add_child(dialog);
dialog.connect('open-state-changed', (o, isOpen) => {
this._eventBlocker.visible = isOpen;
if (this._currentPopup) {
this._currentPopup.disconnect(this._currentPopupDestroyId);
this._currentPopupDestroyId = 0;
if (this._currentDialog) {
this._currentDialog.disconnect(this._currentDialogDestroyId);
this._currentDialogDestroyId = 0;
}
this._currentPopup = null;
this._currentDialog = null;
if (isOpen) {
this._currentPopup = popup;
this._currentPopupDestroyId = popup.connect('destroy', () => {
this._currentPopup = null;
this._currentPopupDestroyId = 0;
this._currentDialog = dialog;
this._currentDialogDestroyId = dialog.connect('destroy', () => {
this._currentDialog = null;
this._currentDialogDestroyId = 0;
this._eventBlocker.visible = false;
});
}
this._updateIconOpacities(isOpen);
if (!isOpen)
this._closeSpaceForPopup();
// Toggle search entry
Main.overview.searchEntry.reactive = !isOpen;
Main.overview.searchEntry.clutter_text.reactive = !isOpen;
Main.overview.searchEntry.clutter_text.editable = !isOpen;
this._displayingPopup = isOpen;
});
}
@@ -782,9 +759,6 @@ var AllView = GObject.registerClass({
this._availWidth = availWidth;
this._availHeight = availHeight;
// Update folder views
for (let i = 0; i < this._folderIcons.length; i++)
this._folderIcons[i].adaptToSize(availWidth, availHeight);
}
_resetOvershoot() {
@@ -871,7 +845,7 @@ var AllView = GObject.registerClass({
this._dragMonitor = null;
}
this._eventBlocker.visible = this._currentPopup !== null;
this._eventBlocker.visible = this._currentDialog !== null;
this._resetOvershoot();
}
@@ -900,8 +874,8 @@ var AllView = GObject.registerClass({
let view = _getViewFromIcon(source);
view.removeApp(source.app);
if (this._currentPopup)
this._currentPopup.popdown();
if (this._currentDialog)
this._currentDialog.popdown();
return true;
}
@@ -1315,6 +1289,8 @@ class FolderView extends BaseAppView {
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
}, {
minRows: 1,
});
// If it not expand, the parent doesn't take into account its preferred_width when allocating
@@ -1404,44 +1380,10 @@ class FolderView extends BaseAppView {
this._scrollView.update_fade_effect(fadeOffset, 0);
// Set extra padding to avoid popup or close button being cut off
this._grid.topPadding = Math.max(this._grid.topPadding - this._offsetForEachSide, 0);
this._grid.bottomPadding = Math.max(this._grid.bottomPadding - this._offsetForEachSide, 0);
this._grid.leftPadding = Math.max(this._grid.leftPadding - this._offsetForEachSide, 0);
this._grid.rightPadding = Math.max(this._grid.rightPadding - this._offsetForEachSide, 0);
this.set_width(this.usedWidth());
this.set_height(this.usedHeight());
}
_getPageAvailableSize() {
let pageBox = new Clutter.ActorBox();
pageBox.x1 = pageBox.y1 = 0;
pageBox.x2 = this._parentAvailableWidth;
pageBox.y2 = this._parentAvailableHeight;
let contentBox = this.get_theme_node().get_content_box(pageBox);
// We only can show icons inside the collection view boxPointer
// so we have to subtract the required padding etc of the boxpointer
return [(contentBox.x2 - contentBox.x1) - 2 * this._offsetForEachSide, (contentBox.y2 - contentBox.y1) - 2 * this._offsetForEachSide];
}
usedWidth() {
let [availWidthPerPage] = this._getPageAvailableSize();
return this._grid.usedWidth(availWidthPerPage);
}
usedHeight() {
return this._grid.usedHeightForNRows(this.nRowsDisplayedAtOnce());
}
nRowsDisplayedAtOnce() {
let [availWidthPerPage, availHeightPerPage] = this._getPageAvailableSize();
let maxRows = this._grid.rowsForHeight(availHeightPerPage) - 1;
return Math.min(this._grid.nRows(availWidthPerPage), maxRows);
}
setPaddingOffsets(offset) {
this._offsetForEachSide = offset;
this._grid.topPadding = Math.max(this._grid.topPadding, 0);
this._grid.bottomPadding = Math.max(this._grid.bottomPadding, 0);
this._grid.leftPadding = Math.max(this._grid.leftPadding, 0);
this._grid.rightPadding = Math.max(this._grid.rightPadding, 0);
}
_loadApps() {
@@ -1540,8 +1482,6 @@ var FolderIcon = GObject.registerClass({
this._folder = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders.folder',
path });
this._delegate = this;
// whether we need to update arrow side, position etc.
this._popupInvalidated = false;
this.icon = new IconGrid.BaseIcon('', {
createIcon: this._createIcon.bind(this),
@@ -1557,10 +1497,6 @@ var FolderIcon = GObject.registerClass({
this._itemDragEndId = Main.overview.connect(
'item-drag-end', this._onDragEnd.bind(this));
this._popupTimeoutId = 0;
this.connect('popup-menu', this._popupRenamePopup.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
this._folder.connect('changed', this._redisplay.bind(this));
@@ -1578,10 +1514,8 @@ var FolderIcon = GObject.registerClass({
this._spaceReadySignalId = 0;
}
if (this._popup)
this._popup.destroy();
this._removeMenuTimeout();
if (this._dialog)
this._dialog.destroy();
}
vfunc_clicked() {
@@ -1591,15 +1525,14 @@ var FolderIcon = GObject.registerClass({
vfunc_unmap() {
super.vfunc_unmap();
if (this._popup)
this._popup.popdown();
if (this._dialog)
this._dialog.popdown();
}
open() {
this._removeMenuTimeout();
this._ensurePopup();
this._ensureFolderDialog();
this.view._scrollView.vscroll.adjustment.value = 0;
this._openSpaceForPopup();
this._dialog.popup();
}
getAppIds() {
@@ -1693,293 +1626,59 @@ var FolderIcon = GObject.registerClass({
return this.view.createFolderIcon(iconSize, this);
}
_popupHeight() {
let usedHeight = this.view.usedHeight() + this._popup.getOffset(St.Side.TOP) + this._popup.getOffset(St.Side.BOTTOM);
return usedHeight;
}
_openSpaceForPopup() {
this._spaceReadySignalId = this._parentView.connect('space-ready', () => {
this._parentView.disconnect(this._spaceReadySignalId);
this._spaceReadySignalId = 0;
this._popup.popup();
this._updatePopupPosition();
});
this._parentView.openSpaceForPopup(this, this._boxPointerArrowside, this.view.nRowsDisplayedAtOnce());
}
_calculateBoxPointerArrowSide() {
let spaceTop = this.y - this._parentView.getCurrentPageY();
let spaceBottom = this._parentView.height - (spaceTop + this.height);
return spaceTop > spaceBottom ? St.Side.BOTTOM : St.Side.TOP;
}
_updatePopupSize() {
// StWidget delays style calculation until needed, make sure we use the correct values
this.view._grid.ensure_style();
let offsetForEachSide = Math.ceil((this._popup.getOffset(St.Side.TOP) +
this._popup.getOffset(St.Side.BOTTOM) -
this._popup.getCloseButtonOverlap()) / 2);
// Add extra padding to prevent boxpointer decorations and close button being cut off
this.view.setPaddingOffsets(offsetForEachSide);
this.view.adaptToSize(this._parentAvailableWidth, this._parentAvailableHeight);
}
_updatePopupPosition() {
if (!this._popup)
_ensureFolderDialog() {
if (this._dialog)
return;
if (this._boxPointerArrowside == St.Side.BOTTOM)
this._popup.y = this.allocation.y1 + this.translation_y - this._popupHeight();
else
this._popup.y = this.allocation.y1 + this.translation_y + this.height;
}
_ensurePopup() {
if (this._popup && !this._popupInvalidated)
return;
this._boxPointerArrowside = this._calculateBoxPointerArrowSide();
if (!this._popup) {
this._popup = new AppFolderPopup(this, this._boxPointerArrowside);
this._parentView.addFolderPopup(this._popup);
this._popup.connect('open-state-changed', (popup, isOpen) => {
if (!this._dialog) {
this._dialog = new AppFolderDialog(this, this._folder);
this._parentView.addFolderDialog(this._dialog);
this._dialog.connect('open-state-changed', (popup, isOpen) => {
if (!isOpen)
this.checked = false;
});
} else {
this._popup.updateArrowSide(this._boxPointerArrowside);
}
this._updatePopupSize();
this._updatePopupPosition();
this._popupInvalidated = false;
}
_removeMenuTimeout() {
if (this._popupTimeoutId > 0) {
GLib.source_remove(this._popupTimeoutId);
this._popupTimeoutId = 0;
}
}
_setPopupTimeout() {
this._removeMenuTimeout();
this._popupTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, MENU_POPUP_TIMEOUT, () => {
this._popupTimeoutId = 0;
this._popupRenamePopup();
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._popupTimeoutId,
'[gnome-shell] this._popupRenamePopup');
}
vfunc_leave_event(crossingEvent) {
let ret = super.vfunc_leave_event(crossingEvent);
this.fake_release();
this._removeMenuTimeout();
return ret;
}
vfunc_button_press_event(buttonEvent) {
super.vfunc_button_press_event(buttonEvent);
if (buttonEvent.button == 1) {
this._setPopupTimeout();
} else if (buttonEvent.button == 3) {
this._popupRenamePopup();
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}
vfunc_touch_event(touchEvent) {
super.vfunc_touch_event(touchEvent);
if (touchEvent.type == Clutter.EventType.TOUCH_BEGIN)
this._setPopupTimeout();
return Clutter.EVENT_PROPAGATE;
}
_popupRenamePopup() {
this._removeMenuTimeout();
this.fake_release();
if (!this._menu) {
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._menu = new RenameFolderMenu(this, this._folder);
this._menuManager.addMenu(this._menu);
this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
if (!isPoppedUp)
this.sync_hover();
});
let id = Main.overview.connect('hiding', () => {
this._menu.close();
});
this.connect('destroy', () => {
Main.overview.disconnect(id);
});
}
this.set_hover(true);
this._menu.open();
this._menuManager.ignoreRelease();
}
adaptToSize(width, height) {
this._parentAvailableWidth = width;
this._parentAvailableHeight = height;
if (this._popup)
this.view.adaptToSize(width, height);
this._popupInvalidated = true;
}
});
var RenameFolderMenuItem = GObject.registerClass(
class RenameFolderMenuItem extends PopupMenu.PopupBaseMenuItem {
_init(folder) {
super._init({
style_class: 'rename-folder-popup-item',
reactive: false,
});
this.setOrnament(PopupMenu.Ornament.HIDDEN);
this._folder = folder;
// Entry
this._entry = new St.Entry({
x_expand: true,
width: 200,
});
this.add_child(this._entry);
this._entry.clutter_text.connect(
'notify::text', this._validate.bind(this));
this._entry.clutter_text.connect(
'activate', this._updateFolderName.bind(this));
// Rename button
this._button = new St.Button({
style_class: 'button',
reactive: true,
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
can_focus: true,
label: _('Rename'),
});
this.add_child(this._button);
this._button.connect('clicked', this._updateFolderName.bind(this));
}
vfunc_map() {
this._entry.text = _getFolderName(this._folder);
this._entry.clutter_text.set_selection(0, -1);
super.vfunc_map();
}
vfunc_key_focus_in() {
super.vfunc_key_focus_in();
this._entry.clutter_text.grab_key_focus();
}
_isValidFolderName() {
let folderName = _getFolderName(this._folder);
let newFolderName = this._entry.text.trim();
return newFolderName.length > 0 && newFolderName != folderName;
}
_validate() {
let isValid = this._isValidFolderName();
this._button.reactive = isValid;
}
_updateFolderName() {
if (!this._isValidFolderName())
return;
let newFolderName = this._entry.text.trim();
this._folder.set_string('name', newFolderName);
this._folder.set_boolean('translate', false);
this.activate(Clutter.get_current_event());
}
});
var RenameFolderMenu = class RenameFolderMenu extends PopupMenu.PopupMenu {
constructor(source, folder) {
super(source, 0.5, St.Side.BOTTOM);
this.actor.add_style_class_name('rename-folder-popup');
// We want to keep the item hovered while the menu is up
this.blockSourceEvents = true;
let menuItem = new RenameFolderMenuItem(folder);
this.addMenuItem(menuItem);
// Focus the text entry on menu pop-up
this.focusActor = menuItem;
// Chain our visibility and lifecycle to that of the source
this._sourceMappedId = source.connect('notify::mapped', () => {
if (!source.mapped)
this.close();
});
source.connect('destroy', () => {
source.disconnect(this._sourceMappedId);
this.destroy();
});
Main.uiGroup.add_actor(this.actor);
}
};
Signals.addSignalMethods(RenameFolderMenu.prototype);
var AppFolderPopup = GObject.registerClass({
var AppFolderDialog = GObject.registerClass({
Signals: {
'open-state-changed': { param_types: [GObject.TYPE_BOOLEAN] },
},
}, class AppFolderPopup extends St.Widget {
_init(source, side) {
}, class AppFolderDialog extends St.Widget {
_init(source, folder) {
super._init({
layout_manager: new Clutter.BinLayout(),
style_class: 'app-folder-dialog-container',
visible: false,
// We don't want to expand really, but look
// at the layout manager of our parent...
//
// DOUBLE HACK: if you set one, you automatically
// get the effect for the other direction too, so
// we need to set the y_align
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER,
});
this.add_constraint(new Clutter.BindConstraint({
source: Main.overview.viewSelector,
coordinate: Clutter.BindCoordinate.ALL,
}));
this._source = source;
this._folder = folder;
this._view = source.view;
this._arrowSide = side;
this._isOpen = false;
this.parentOffset = 0;
this._boxPointer = new BoxPointer.BoxPointer(this._arrowSide, {
style_class: 'app-folder-popup-bin',
this._viewBox = new St.BoxLayout({
style_class: 'app-folder-dialog',
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.FILL,
y_align: Clutter.ActorAlign.FILL,
vertical: true,
});
this.add_child(this._viewBox);
this._boxPointer.style_class = 'app-folder-popup';
this.add_actor(this._boxPointer);
this._boxPointer.bin.set_child(this._view);
this.closeButton = Util.makeCloseButton(this._boxPointer);
this.closeButton.connect('clicked', this.popdown.bind(this));
this.add_actor(this.closeButton);
this._boxPointer.bind_property('opacity', this.closeButton, 'opacity',
GObject.BindingFlags.SYNC_CREATE);
this._addFolderNameEntry();
this._viewBox.add_child(this._view);
global.focus_manager.add_group(this);
@@ -1988,6 +1687,206 @@ var AppFolderPopup = GObject.registerClass({
});
this._grabHelper.addActor(Main.layoutManager.overviewGroup);
this.connect('destroy', this._onDestroy.bind(this));
this._sourceMappedId = 0;
this._needsZoomAndFade = false;
}
_addFolderNameEntry() {
this._entryBox = new St.BoxLayout({
style_class: 'folder-name-container',
});
this._viewBox.add_child(this._entryBox);
// Empty actor to center the title
let ghostButton = new Clutter.Actor();
this._entryBox.add_child(ghostButton);
let stack = new Shell.Stack({
x_expand: true,
x_align: Clutter.ActorAlign.CENTER,
});
this._entryBox.add_child(stack);
// Folder name label
this._folderNameLabel = new St.Label({
style_class: 'folder-name-label',
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
});
stack.add_child(this._folderNameLabel);
// Folder name entry
this._entry = new St.Entry({
style_class: 'folder-name-entry',
opacity: 0,
reactive: false,
});
this._entry.clutter_text.set({
x_expand: true,
x_align: Clutter.ActorAlign.CENTER,
});
this._entry.clutter_text.connect('activate', () => {
this._showFolderLabel();
});
stack.add_child(this._entry);
// Edit button
this._editButton = new St.Button({
style_class: 'edit-folder-button',
button_mask: St.ButtonMask.ONE,
toggle_mode: true,
reactive: true,
can_focus: true,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER,
child: new St.Icon({
icon_name: 'document-edit-symbolic',
icon_size: 16,
}),
});
this._editButton.connect('notify::checked', () => {
if (this._editButton.checked)
this._showFolderEntry();
else
this._showFolderLabel();
});
this._entryBox.add_child(this._editButton);
ghostButton.add_constraint(new Clutter.BindConstraint({
source: this._editButton,
coordinate: Clutter.BindCoordinate.SIZE,
}));
this._folder.connect('changed::name', () => this._syncFolderName());
this._syncFolderName();
}
_syncFolderName() {
let newName = _getFolderName(this._folder);
this._folderNameLabel.text = newName;
this._entry.text = newName;
}
_switchActor(from, to) {
to.reactive = true;
to.ease({
opacity: 255,
duration: 300,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
from.ease({
opacity: 0,
duration: 300,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
from.reactive = false;
},
});
}
_showFolderLabel() {
if (this._editButton.checked)
this._editButton.checked = false;
this._maybeUpdateFolderName();
this._switchActor(this._entry, this._folderNameLabel);
}
_showFolderEntry() {
this._switchActor(this._folderNameLabel, this._entry);
this._entry.clutter_text.set_selection(0, -1);
this._entry.clutter_text.grab_key_focus();
}
_maybeUpdateFolderName() {
let folderName = _getFolderName(this._folder);
let newFolderName = this._entry.text.trim();
if (newFolderName.length === 0 || newFolderName === folderName)
return;
this._folder.set_string('name', newFolderName);
this._folder.set_boolean('translate', false);
}
_zoomAndFadeIn() {
let [sourceX, sourceY] =
this._source.get_transformed_position();
let [dialogX, dialogY] =
this.get_transformed_position();
this.set({
translation_x: sourceX - dialogX,
translation_y: sourceY - dialogY,
scale_x: this._source.width / this.width,
scale_y: this._source.height / this.height,
opacity: 0,
});
this.ease({
translation_x: 0,
translation_y: 0,
scale_x: 1,
scale_y: 1,
opacity: 255,
duration: FOLDER_DIALOG_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
this._needsZoomAndFade = false;
if (this._sourceMappedId === 0) {
this._sourceMappedId = this._source.connect(
'notify::mapped', this._zoomAndFadeOut.bind(this));
}
}
_zoomAndFadeOut() {
if (!this._isOpen)
return;
if (!this._source.mapped) {
this.hide();
return;
}
let [sourceX, sourceY] =
this._source.get_transformed_position();
let [dialogX, dialogY] =
this.get_transformed_position();
this.ease({
translation_x: sourceX - dialogX,
translation_y: sourceY - dialogY,
scale_x: this._source.width / this.width,
scale_y: this._source.height / this.height,
opacity: 0,
duration: FOLDER_DIALOG_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this.set({
translation_x: 0,
translation_y: 0,
scale_x: 1,
scale_y: 1,
opacity: 255,
});
this.hide();
},
});
this._needsZoomAndFade = false;
}
_onDestroy() {
@@ -1996,6 +1895,28 @@ var AppFolderPopup = GObject.registerClass({
this._grabHelper.ungrab({ actor: this });
this._grabHelper = null;
}
if (this._sourceMappedId) {
this._source.disconnect(this._sourceMappedId);
this._sourceMappedId = 0;
}
}
vfunc_allocate(box, flags) {
let contentBox = this.get_theme_node().get_content_box(box);
let [, entryBoxHeight] = this._entryBox.get_size();
let spacing = this._viewBox.layout_manager.spacing;
this._view.adaptToSize(
contentBox.get_width(),
contentBox.get_height() - entryBoxHeight - spacing);
super.vfunc_allocate(box, flags);
// We can only start zooming after receiving an allocation
if (this._needsZoomAndFade)
this._zoomAndFadeIn();
}
vfunc_key_press_event(keyEvent) {
@@ -2061,20 +1982,9 @@ var AppFolderPopup = GObject.registerClass({
if (!this._isOpen)
return;
this._needsZoomAndFade = true;
this.show();
this._boxPointer.setArrowActor(this._source);
// We need to hide the icons of the view until the boxpointer animation
// is completed so we can animate the icons after as we like without
// showing them while boxpointer is animating.
this._view.opacity = 0;
this._boxPointer.open(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE,
() => {
this._view.opacity = 255;
this._view.animate(IconGrid.AnimationDirection.IN);
});
this.emit('open-state-changed', true);
}
@@ -2082,29 +1992,13 @@ var AppFolderPopup = GObject.registerClass({
if (!this._isOpen)
return;
this._grabHelper.ungrab({ actor: this });
this._zoomAndFadeOut();
this._showFolderLabel();
this._boxPointer.close(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE);
this._grabHelper.ungrab({ actor: this });
this._isOpen = false;
this.emit('open-state-changed', false);
}
getCloseButtonOverlap() {
return this.closeButton.get_theme_node().get_length('-shell-close-overlap-y');
}
getOffset(side) {
let offset = this._boxPointer.getPadding(side);
if (this._arrowSide == side)
offset += this._boxPointer.getArrowHeight();
return offset;
}
updateArrowSide(side) {
this._arrowSide = side;
this._boxPointer.updateArrowSide(side);
}
});
var AppIcon = GObject.registerClass({

View File

@@ -1,6 +1,7 @@
/* exported AudioDeviceSelectionDBus */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Dialog = imports.ui.dialog;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
@@ -36,18 +37,17 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
}
_buildLayout() {
let title = new St.Label({ style_class: 'audio-selection-title',
text: _("Select Audio Device"),
x_align: Clutter.ActorAlign.CENTER });
this.contentLayout.style_class = 'audio-selection-content';
this.contentLayout.add(title);
let content = new Dialog.MessageDialogContent({
title: _('Select Audio Device'),
});
this._selectionBox = new St.BoxLayout({
style_class: 'audio-selection-box',
x_expand: true,
});
this.contentLayout.add_child(this._selectionBox);
content.add_child(this._selectionBox);
this.contentLayout.add_child(content);
if (Main.sessionMode.allowSettings) {
this.addButton({ action: this._openSettings.bind(this),

View File

@@ -504,12 +504,10 @@ var SystemBackground = GObject.registerClass({
Signals: { 'loaded': {} },
}, class SystemBackground extends Meta.BackgroundActor {
_init() {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/noise-texture.png');
if (_systemBackground == null) {
_systemBackground = new Meta.Background({ meta_display: global.display });
_systemBackground.set_color(DEFAULT_BACKGROUND_COLOR);
_systemBackground.set_file(file, GDesktopEnums.BackgroundStyle.WALLPAPER);
}
super._init({

View File

@@ -7,6 +7,7 @@ const Main = imports.ui.main;
const MessageList = imports.ui.messageList;
const MessageTray = imports.ui.messageTray;
const Mpris = imports.ui.mpris;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const { loadInterfaceXML } = imports.misc.fileUtils;
@@ -1100,6 +1101,26 @@ class Placeholder extends St.BoxLayout {
}
});
const DoNotDisturbSwitch = GObject.registerClass(
class DoNotDisturbSwitch extends PopupMenu.Switch {
_init() {
this._settings = new Gio.Settings({
schema_id: 'org.gnome.desktop.notifications',
});
super._init(this._settings.get_boolean('show-banners'));
this._settings.bind('show-banners',
this, 'state',
Gio.SettingsBindFlags.INVERT_BOOLEAN);
this.connect('destroy', () => {
this._settings.run_dispose();
this._settings = null;
});
}
});
var CalendarMessageList = GObject.registerClass(
class CalendarMessageList extends St.Widget {
_init() {
@@ -1125,16 +1146,33 @@ class CalendarMessageList extends St.Widget {
this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC);
box.add_actor(this._scrollView);
let hbox = new St.BoxLayout({ style_class: 'message-list-controls' });
box.add_child(hbox);
hbox.add_child(new St.Label({
text: _('Do Not Disturb'),
y_align: Clutter.ActorAlign.CENTER,
}));
this._dndSwitch = new DoNotDisturbSwitch();
this._dndButton = new St.Button({
can_focus: true,
child: this._dndSwitch,
});
this._dndButton.connect('clicked', () => this._dndSwitch.toggle());
hbox.add_child(this._dndButton);
this._clearButton = new St.Button({
style_class: 'message-list-clear-button button',
label: _('Clear'),
can_focus: true,
x_expand: true,
x_align: Clutter.ActorAlign.END,
});
this._clearButton.connect('clicked', () => {
this._sectionList.get_children().forEach(s => s.clear());
});
box.add_actor(this._clearButton);
hbox.add_actor(this._clearButton);
this._placeholder.bind_property('visible',
this._clearButton, 'visible',

View File

@@ -19,7 +19,7 @@ class CheckBox extends St.Button {
this._box = new St.Bin({ y_align: Clutter.ActorAlign.START });
container.add_actor(this._box);
this._label = new St.Label();
this._label = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
this._label.clutter_text.set_line_wrap(true);
this._label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
container.add_actor(this._label);

View File

@@ -3,13 +3,11 @@
const { Clutter, Gcr, Gio, GObject, Pango, Shell, St } = imports.gi;
const Animation = imports.ui.animation;
const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const CheckBox = imports.ui.checkBox;
var WORK_SPINNER_ICON_SIZE = 16;
const Util = imports.misc.util;
var KeyringDialog = GObject.registerClass(
class KeyringDialog extends ModalDialog.ModalDialog {
@@ -21,141 +19,97 @@ class KeyringDialog extends ModalDialog.ModalDialog {
this.prompt.connect('show-confirm', this._onShowConfirm.bind(this));
this.prompt.connect('prompt-close', this._onHidePrompt.bind(this));
this._content = new Dialog.MessageDialogContent();
this.contentLayout.add(this._content);
let content = new Dialog.MessageDialogContent();
this.prompt.bind_property('message', this._content, 'title', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('description', this._content, 'description', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('message',
content, 'title', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('description',
content, 'description', GObject.BindingFlags.SYNC_CREATE);
this._workSpinner = null;
this._controlTable = null;
let passwordBox = new St.BoxLayout({
style_class: 'prompt-dialog-password-layout',
vertical: true,
});
this._cancelButton = this.addButton({ label: '',
action: this._onCancelButton.bind(this),
key: Clutter.KEY_Escape });
this._continueButton = this.addButton({ label: '',
action: this._onContinueButton.bind(this),
default: true });
this._passwordEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
can_focus: true,
x_align: Clutter.ActorAlign.CENTER,
});
ShellEntry.addContextMenu(this._passwordEntry);
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
this.prompt.bind_property('password-visible',
this._passwordEntry, 'visible', GObject.BindingFlags.SYNC_CREATE);
passwordBox.add_child(this._passwordEntry);
this._confirmEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
can_focus: true,
x_align: Clutter.ActorAlign.CENTER,
});
ShellEntry.addContextMenu(this._confirmEntry);
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
this.prompt.bind_property('confirm-visible',
this._confirmEntry, 'visible', GObject.BindingFlags.SYNC_CREATE);
passwordBox.add_child(this._confirmEntry);
this.prompt.set_password_actor(this._passwordEntry.clutter_text);
this.prompt.set_confirm_actor(this._confirmEntry.clutter_text);
let warningBox = new St.BoxLayout({ vertical: true });
let capsLockWarning = new ShellEntry.CapsLockWarning();
let syncCapsLockWarningVisibility = () => {
capsLockWarning.visible =
this.prompt.password_visible || this.prompt.confirm_visible;
};
this.prompt.connect('notify::password-visible', syncCapsLockWarningVisibility);
this.prompt.connect('notify::confirm-visible', syncCapsLockWarningVisibility);
warningBox.add_child(capsLockWarning);
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
warning.clutter_text.line_wrap = true;
this.prompt.bind_property('warning',
warning, 'text', GObject.BindingFlags.SYNC_CREATE);
this.prompt.connect('notify::warning-visible', () => {
warning.opacity = this.prompt.warning_visible ? 255 : 0;
});
this.prompt.connect('notify::warning', () => {
if (this._passwordEntry && warning !== '')
Util.wiggle(this._passwordEntry);
});
warningBox.add_child(warning);
passwordBox.add_child(warningBox);
content.add_child(passwordBox);
this._choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', this._choice.getLabelActor(),
'text', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('choice-chosen', this._choice,
'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
this.prompt.bind_property('choice-visible', this._choice,
'visible', GObject.BindingFlags.SYNC_CREATE);
content.add_child(this._choice);
this.contentLayout.add_child(content);
this._cancelButton = this.addButton({
label: '',
action: this._onCancelButton.bind(this),
key: Clutter.KEY_Escape,
});
this._continueButton = this.addButton({
label: '',
action: this._onContinueButton.bind(this),
default: true,
});
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
}
_setWorking(working) {
if (!this._workSpinner)
return;
if (working)
this._workSpinner.play();
else
this._workSpinner.stop();
}
_buildControlTable() {
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
let table = new St.Widget({
style_class: 'keyring-dialog-control-table',
layout_manager: layout,
x_expand: true,
y_expand: true,
});
layout.hookup_style(table);
let rtl = table.get_text_direction() == Clutter.TextDirection.RTL;
let row = 0;
if (this.prompt.password_visible) {
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER });
label.set_text(_("Password:"));
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._passwordEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true,
x_expand: true,
});
ShellEntry.addContextMenu(this._passwordEntry);
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
animate: true,
});
if (rtl) {
layout.attach(this._workSpinner, 0, row, 1, 1);
layout.attach(this._passwordEntry, 1, row, 1, 1);
layout.attach(label, 2, row, 1, 1);
} else {
layout.attach(label, 0, row, 1, 1);
layout.attach(this._passwordEntry, 1, row, 1, 1);
layout.attach(this._workSpinner, 2, row, 1, 1);
}
row++;
} else {
this._workSpinner = null;
this._passwordEntry = null;
}
if (this.prompt.confirm_visible) {
var label = new St.Label({ style_class: 'prompt-dialog-password-label',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER });
label.set_text(_("Type again:"));
this._confirmEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true,
x_expand: true,
});
ShellEntry.addContextMenu(this._confirmEntry);
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
if (rtl) {
layout.attach(this._confirmEntry, 0, row, 1, 1);
layout.attach(label, 1, row, 1, 1);
} else {
layout.attach(label, 0, row, 1, 1);
layout.attach(this._confirmEntry, 1, row, 1, 1);
}
row++;
} else {
this._confirmEntry = null;
}
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
if (this._passwordEntry || this._confirmEntry) {
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
layout.attach(this._capsLockWarningLabel, 1, row, 1, 1);
row++;
}
if (this.prompt.choice_visible) {
let choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('choice-chosen', choice, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
layout.attach(choice, rtl ? 0 : 1, row, 1, 1);
row++;
}
let warning = new St.Label({ style_class: 'prompt-dialog-error-label',
x_align: Clutter.ActorAlign.START });
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
warning.clutter_text.line_wrap = true;
layout.attach(warning, rtl ? 0 : 1, row, 1, 1);
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
if (this._controlTable) {
this._controlTable.destroy_all_children();
this._controlTable.destroy();
}
this._controlTable = table;
this._content.add_child(table);
}
_updateSensitivity(sensitive) {
if (this._passwordEntry) {
this._passwordEntry.reactive = sensitive;
@@ -169,7 +123,6 @@ class KeyringDialog extends ModalDialog.ModalDialog {
this._continueButton.can_focus = sensitive;
this._continueButton.reactive = sensitive;
this._setWorking(!sensitive);
}
_ensureOpen() {
@@ -191,16 +144,16 @@ class KeyringDialog extends ModalDialog.ModalDialog {
}
_onShowPassword() {
this._buildControlTable();
this._ensureOpen();
this._updateSensitivity(true);
this._passwordEntry.text = '';
this._passwordEntry.grab_key_focus();
}
_onShowConfirm() {
this._buildControlTable();
this._ensureOpen();
this._updateSensitivity(true);
this._confirmEntry.text = '';
this._continueButton.grab_key_focus();
}

View File

@@ -33,38 +33,26 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
title: this._content.title,
description: this._content.message,
});
this.contentLayout.add_actor(contentBox);
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
let secretTable = new St.Widget({ style_class: 'network-dialog-secret-table',
layout_manager: layout });
layout.hookup_style(secretTable);
let rtl = secretTable.get_text_direction() == Clutter.TextDirection.RTL;
let initialFocusSet = false;
let pos = 0;
for (let i = 0; i < this._content.secrets.length; i++) {
let secret = this._content.secrets[i];
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
text: secret.label,
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER });
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
let reactive = secret.key != null;
let entryParams = {
style_class: 'prompt-dialog-password-entry',
hint_text: secret.label,
text: secret.value,
can_focus: reactive,
reactive,
x_expand: true,
x_align: Clutter.ActorAlign.CENTER,
};
if (secret.password)
secret.entry = new St.PasswordEntry(entryParams);
else
secret.entry = new St.Entry(entryParams);
ShellEntry.addContextMenu(secret.entry);
contentBox.add_child(secret.entry);
if (secret.validate)
secret.valid = secret.validate(secret);
@@ -89,36 +77,26 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
} else {
secret.valid = true;
}
if (rtl) {
layout.attach(secret.entry, 0, pos, 1, 1);
layout.attach(label, 1, pos, 1, 1);
} else {
layout.attach(label, 0, pos, 1, 1);
layout.attach(secret.entry, 1, pos, 1, 1);
}
pos++;
}
if (this._content.secrets.some(s => s.password)) {
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
if (rtl)
layout.attach(this._capsLockWarningLabel, 0, pos, 1, 1);
else
layout.attach(this._capsLockWarningLabel, 1, pos, 1, 1);
let capsLockWarning = new ShellEntry.CapsLockWarning();
contentBox.add_child(capsLockWarning);
}
contentBox.add_child(secretTable);
if (flags & NM.SecretAgentGetSecretsFlags.WPS_PBC_ACTIVE) {
let descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
text: _("Alternatively you can connect by pushing the “WPS” button on your router.") });
let descriptionLabel = new St.Label({
text: _('Alternatively you can connect by pushing the “WPS” button on your router.'),
style_class: 'message-dialog-description',
});
descriptionLabel.clutter_text.line_wrap = true;
descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
contentBox.add_child(descriptionLabel);
}
this.contentLayout.add_child(contentBox);
this._okButton = {
label: _("Connect"),
action: this._onOk.bind(this),
@@ -325,7 +303,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
case '802-11-wireless':
wirelessSetting = this._connection.get_setting_wireless();
ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
content.title = _("Authentication required by wireless network");
content.title = _('Authentication required');
content.message = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
this._getWirelessSecrets(content.secrets, wirelessSetting);
break;
@@ -353,7 +331,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
// fall through
case 'cdma':
case 'bluetooth':
content.title = _("Mobile broadband network password");
content.title = _('Authentication required');
content.message = _("A password is required to connect to “%s”.").format(connectionSetting.get_id());
this._getMobileSecrets(content.secrets, connectionType);
break;
@@ -700,7 +678,7 @@ var NetworkAgent = class {
case '802-11-wireless': {
let wirelessSetting = connection.get_setting_wireless();
let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
title = _("Authentication required by wireless network");
title = _('Authentication required');
body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
break;
}
@@ -721,7 +699,7 @@ var NetworkAgent = class {
// fall through
case 'cdma':
case 'bluetooth':
title = _("Mobile broadband network password");
title = _('Authentication required');
body = _("A password is required to connect to “%s”.").format(connectionSetting.get_id());
break;
case 'vpn':

View File

@@ -4,21 +4,19 @@
const { AccountsService, Clutter, GLib,
GObject, Pango, PolkitAgent, Polkit, Shell, St } = imports.gi;
const Animation = imports.ui.animation;
const Dialog = imports.ui.dialog;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const UserWidget = imports.ui.userWidget;
const Util = imports.misc.util;
const DialogMode = {
AUTH: 0,
CONFIRM: 1,
};
var DIALOG_ICON_SIZE = 48;
var WORK_SPINNER_ICON_SIZE = 16;
const DIALOG_ICON_SIZE = 64;
const DELAYED_RESET_TIMEOUT = 200;
@@ -40,8 +38,10 @@ var AuthenticationDialog = GObject.registerClass({
let title = _("Authentication Required");
let content = new Dialog.MessageDialogContent({ title, description });
this.contentLayout.add_actor(content);
let headerContent = new Dialog.MessageDialogContent({ title, description });
this.contentLayout.add_child(headerContent);
let bodyContent = new Dialog.MessageDialogContent();
if (userNames.length > 1) {
log(`polkitAuthenticationAgent: Received ${userNames.length} ` +
@@ -59,22 +59,21 @@ var AuthenticationDialog = GObject.registerClass({
let userBox = new St.BoxLayout({
style_class: 'polkit-dialog-user-layout',
vertical: false,
vertical: true,
});
content.add_child(userBox);
bodyContent.add_child(userBox);
this._userAvatar = new UserWidget.Avatar(this._user, {
iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon',
});
this._userAvatar.x_align = Clutter.ActorAlign.CENTER;
userBox.add_child(this._userAvatar);
this._userLabel = new St.Label({
style_class: userName === 'root'
? 'polkit-dialog-user-root-label'
: 'polkit-dialog-user-label',
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
});
if (userName === 'root')
@@ -82,58 +81,60 @@ var AuthenticationDialog = GObject.registerClass({
userBox.add_child(this._userLabel);
this._passwordBox = new St.BoxLayout({ vertical: false, style_class: 'prompt-dialog-password-box' });
content.add_child(this._passwordBox);
this._passwordLabel = new St.Label({
style_class: 'prompt-dialog-password-label',
y_align: Clutter.ActorAlign.CENTER,
let passwordBox = new St.BoxLayout({
style_class: 'prompt-dialog-password-layout',
vertical: true,
});
this._passwordBox.add_child(this._passwordLabel);
this._passwordEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
text: "",
can_focus: true,
x_expand: true,
visible: false,
x_align: Clutter.ActorAlign.CENTER,
});
ShellEntry.addContextMenu(this._passwordEntry);
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
this._passwordEntry.bind_property('reactive',
this._passwordEntry.clutter_text, 'editable',
GObject.BindingFlags.SYNC_CREATE);
this._passwordBox.add_child(this._passwordEntry);
passwordBox.add_child(this._passwordEntry);
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
animate: true,
let warningBox = new St.BoxLayout({ vertical: true });
let capsLockWarning = new ShellEntry.CapsLockWarning();
this._passwordEntry.bind_property('visible',
capsLockWarning, 'visible',
GObject.BindingFlags.SYNC_CREATE);
warningBox.add_child(capsLockWarning);
this._errorMessageLabel = new St.Label({
style_class: 'prompt-dialog-error-label',
visible: false,
});
this._passwordBox.add(this._workSpinner);
this._passwordBox.hide();
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning({ style_class: 'prompt-dialog-caps-lock-warning' });
content.add_child(this._capsLockWarningLabel);
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._errorMessageLabel.clutter_text.line_wrap = true;
content.add_child(this._errorMessageLabel);
this._errorMessageLabel.hide();
warningBox.add_child(this._errorMessageLabel);
this._infoMessageLabel = new St.Label({ style_class: 'prompt-dialog-info-label' });
this._infoMessageLabel = new St.Label({
style_class: 'prompt-dialog-info-label',
visible: false,
});
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._infoMessageLabel.clutter_text.line_wrap = true;
content.add_child(this._infoMessageLabel);
this._infoMessageLabel.hide();
warningBox.add_child(this._infoMessageLabel);
/* text is intentionally non-blank otherwise the height is not the same as for
* infoMessage and errorMessageLabel - but it is still invisible because
* gnome-shell.css sets the color to be transparent
*/
this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label',
text: 'abc' });
this._nullMessageLabel.add_style_class_name('hidden');
this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label' });
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._nullMessageLabel.clutter_text.line_wrap = true;
content.add_child(this._nullMessageLabel);
this._nullMessageLabel.show();
warningBox.add_child(this._nullMessageLabel);
passwordBox.add_child(warningBox);
bodyContent.add_child(passwordBox);
this._cancelButton = this.addButton({ label: _("Cancel"),
action: this.cancel.bind(this),
@@ -149,6 +150,8 @@ var AuthenticationDialog = GObject.registerClass({
this._okButton.reactive = text.get_text().length > 0;
});
this.contentLayout.add_child(bodyContent);
this._doneEmitted = false;
this._mode = -1;
@@ -163,13 +166,6 @@ var AuthenticationDialog = GObject.registerClass({
this._onUserChanged();
}
_setWorking(working) {
if (working)
this._workSpinner.play();
else
this._workSpinner.stop();
}
_initiateSession() {
this._destroySession(DELAYED_RESET_TIMEOUT);
@@ -218,7 +214,6 @@ var AuthenticationDialog = GObject.registerClass({
this._passwordEntry.reactive = false;
this._okButton.reactive = false;
this._setWorking(true);
this._session.response(response);
// When the user responds, dismiss already shown info and
@@ -260,6 +255,8 @@ var AuthenticationDialog = GObject.registerClass({
this._errorMessageLabel.show();
this._infoMessageLabel.hide();
this._nullMessageLabel.hide();
Util.wiggle(this._passwordEntry);
}
/* Try and authenticate again */
@@ -273,19 +270,20 @@ var AuthenticationDialog = GObject.registerClass({
this._sessionRequestTimeoutId = 0;
}
// Cheap localization trick
if (request == 'Password:' || request == 'Password: ')
this._passwordLabel.set_text(_("Password:"));
// Hack: The request string comes directly from PAM, if it's "Password:"
// we replace it with our own, if it's something else we replace the
// last colon and any trailing spaces with a "…".
if (request === 'Password:' || request === 'Password: ')
this._passwordEntry.hint_text = _('Enter Password…');
else
this._passwordLabel.set_text(request);
this._passwordEntry.hint_text = request.replace(/: *$/, '…');
this._passwordEntry.password_visible = echoOn;
this._passwordBox.show();
this._passwordEntry.show();
this._passwordEntry.set_text('');
this._passwordEntry.reactive = true;
this._okButton.reactive = false;
this._setWorking(false);
this._ensureOpen();
this._passwordEntry.grab_key_focus();
@@ -332,7 +330,7 @@ var AuthenticationDialog = GObject.registerClass({
if (this.state != ModalDialog.State.OPENED)
return;
this._passwordBox.hide();
this._passwordEntry.hide();
this._cancelButton.grab_key_focus();
this._okButton.reactive = false;
};

View File

@@ -432,7 +432,6 @@ var MessagesIndicator = GObject.registerClass(
class MessagesIndicator extends St.Icon {
_init() {
super._init({
icon_name: 'message-indicator-symbolic',
icon_size: 16,
visible: false,
y_expand: true,
@@ -440,6 +439,13 @@ class MessagesIndicator extends St.Icon {
});
this._sources = [];
this._count = 0;
this._doNotDisturb = false;
this._settings = new Gio.Settings({
schema_id: 'org.gnome.desktop.notifications',
});
this._settings.connect('changed::show-banners', this._sync.bind(this));
Main.messageTray.connect('source-added', this._onSourceAdded.bind(this));
Main.messageTray.connect('source-removed', this._onSourceRemoved.bind(this));
@@ -447,6 +453,11 @@ class MessagesIndicator extends St.Icon {
let sources = Main.messageTray.getSources();
sources.forEach(source => this._onSourceAdded(null, source));
this.connect('destroy', () => {
this._settings.run_dispose();
this._settings = null;
});
}
_onSourceAdded(tray, source) {
@@ -463,9 +474,17 @@ class MessagesIndicator extends St.Icon {
_updateCount() {
let count = 0;
this._sources.forEach(source => (count += source.unseenCount));
count -= Main.messageTray.queueCount;
this._count = count - Main.messageTray.queueCount;
this.visible = count > 0;
this._sync();
}
_sync() {
let doNotDisturb = !this._settings.get_boolean('show-banners');
this.icon_name = doNotDisturb
? 'notifications-disabled-symbolic'
: 'message-indicator-symbolic';
this.visible = doNotDisturb || this._count > 0;
}
});
@@ -473,21 +492,19 @@ var IndicatorPad = GObject.registerClass(
class IndicatorPad extends St.Widget {
_init(actor) {
this._source = actor;
this._source.connect('notify::visible', () => this.queue_relayout());
this._source.connect('notify::size', () => this.queue_relayout());
super._init();
this._source.bind_property('visible',
this, 'visible',
GObject.BindingFlags.SYNC_CREATE);
}
vfunc_get_preferred_width(forHeight) {
if (this._source.visible)
return this._source.get_preferred_width(forHeight);
return [0, 0];
return this._source.get_preferred_width(forHeight);
}
vfunc_get_preferred_height(forWidth) {
if (this._source.visible)
return this._source.get_preferred_height(forWidth);
return [0, 0];
return this._source.get_preferred_height(forWidth);
}
});
@@ -559,7 +576,7 @@ class DateMenuButton extends PanelMenu.Button {
this._clockDisplay = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
this._indicator = new MessagesIndicator();
let box = new St.BoxLayout();
let box = new St.BoxLayout({ style_class: 'clock-display-box' });
box.add_actor(new IndicatorPad(this._indicator));
box.add_actor(this._clockDisplay);
box.add_actor(this._indicator);

View File

@@ -313,8 +313,8 @@ var _Draggable = class _Draggable {
device = event.get_device();
if (device == undefined) {
let manager = Clutter.DeviceManager.get_default();
device = manager.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE);
let seat = Clutter.get_default_backend().get_default_seat();
device = seat.get_pointer();
}
}

View File

@@ -1,6 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported init, installExtension, uninstallExtension,
checkForUpdates, updateExtension */
/* exported init, installExtension, uninstallExtension, checkForUpdates */
const { Clutter, Gio, GLib, GObject, Soup } = imports.gi;
@@ -100,13 +99,9 @@ function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
});
}
function updateExtension(uuid) {
// This gets a bit tricky. We want the update to be seamless -
// if we have any error during downloading or extracting, we
// want to not unload the current version.
let oldExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
let newExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
function downloadExtensionUpdate(uuid) {
let dir = Gio.File.new_for_path(
GLib.build_filenamev([global.userdatadir, 'extension-updates', uuid]));
let params = { shell_version: Config.PACKAGE_VERSION };
@@ -114,39 +109,10 @@ function updateExtension(uuid) {
let message = Soup.form_request_new_from_hash('GET', url, params);
_httpSession.queue_message(message, session => {
gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => {
let oldExtension = Main.extensionManager.lookup(uuid);
let extensionDir = oldExtension.dir;
if (!Main.extensionManager.unloadExtension(oldExtension))
return;
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
FileUtils.recursivelyMoveDir(newExtensionTmpDir, extensionDir);
let extension = null;
try {
extension = Main.extensionManager.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
Main.extensionManager.loadExtension(extension);
} catch (e) {
if (extension)
Main.extensionManager.unloadExtension(extension);
logError(e, 'Error loading extension %s'.format(uuid));
FileUtils.recursivelyDeleteDir(extensionDir, false);
FileUtils.recursivelyMoveDir(oldExtensionTmpDir, extensionDir);
// Restore what was there before. We can't do much if we
// fail here.
Main.extensionManager.loadExtension(oldExtension);
return;
}
FileUtils.recursivelyDeleteDir(oldExtensionTmpDir, true);
gotExtensionZipFile(session, message, uuid, dir, () => {
Main.extensionManager.notifyExtensionUpdate(uuid);
}, (code, msg) => {
log(`Error while updating extension ${uuid}: ${code} (${msg})`);
log(`Error while downloading update for extension ${uuid}: ${code} (${msg})`);
});
});
}
@@ -154,11 +120,21 @@ function updateExtension(uuid) {
function checkForUpdates() {
let metadatas = {};
Main.extensionManager.getUuids().forEach(uuid => {
metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata;
let extension = Main.extensionManager.lookup(uuid);
if (extension.type !== ExtensionUtils.ExtensionType.PER_USER)
return;
if (extension.hasUpdate)
return;
metadatas[uuid] = extension.metadata;
});
let params = { shell_version: Config.PACKAGE_VERSION,
installed: JSON.stringify(metadatas) };
let versionCheck = global.settings.get_boolean(
'disable-extension-version-validation');
let params = {
shell_version: Config.PACKAGE_VERSION,
installed: JSON.stringify(metadatas),
disable_version_validation: `${versionCheck}`,
};
let url = REPOSITORY_URL_UPDATE;
let message = Soup.form_request_new_from_hash('GET', url, params);
@@ -172,7 +148,7 @@ function checkForUpdates() {
if (operation == 'blacklist')
uninstallExtension(uuid);
else if (operation == 'upgrade' || operation == 'downgrade')
updateExtension(uuid);
downloadExtensionUpdate(uuid);
}
});
}
@@ -197,7 +173,8 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
}]);
let content = new Dialog.MessageDialogContent({
title: _("Download and install “%s” from extensions.gnome.org?").format(info.name),
title: _('Install Extension'),
description: _('Download and install “%s” from extensions.gnome.org?').format(info.name),
});
this.contentLayout.add(content);

View File

@@ -1,12 +1,14 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported init connect disconnect */
const { GLib, Gio, St } = imports.gi;
const { GLib, Gio, GObject, Shell, St } = imports.gi;
const Signals = imports.signals;
const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const { ExtensionState, ExtensionType } = ExtensionUtils;
@@ -15,10 +17,13 @@ const DISABLED_EXTENSIONS_KEY = 'disabled-extensions';
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
const UPDATE_CHECK_TIMEOUT = 24 * 60 * 60; // 1 day in seconds
var ExtensionManager = class {
constructor() {
this._initialized = false;
this._enabled = false;
this._updateNotified = false;
this._extensions = new Map();
this._enabledExtensions = [];
@@ -45,7 +50,14 @@ var ExtensionManager = class {
return GLib.SOURCE_REMOVE;
});
this._installExtensionUpdates();
this._sessionUpdated();
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
ExtensionDownloader.checkForUpdates();
return GLib.SOURCE_CONTINUE;
});
ExtensionDownloader.checkForUpdates();
}
lookup(uuid) {
@@ -198,6 +210,27 @@ var ExtensionManager = class {
return true;
}
notifyExtensionUpdate(uuid) {
let extension = this.lookup(uuid);
if (!extension)
return;
extension.hasUpdate = true;
this.emit('extension-state-changed', extension);
if (!this._updateNotified) {
this._updateNotified = true;
let source = new ExtensionUpdateSource();
Main.messageTray.add(source);
let notification = new MessageTray.Notification(source,
_('Extension Updates Available'),
_('Extension updates are ready to be installed.'));
source.showNotification(notification);
}
}
logExtensionError(uuid, error) {
let extension = this.lookup(uuid);
if (!extension)
@@ -253,6 +286,7 @@ var ExtensionManager = class {
path: dir.get_path(),
error: '',
hasPrefs: dir.get_child('prefs.js').query_exists(null),
hasUpdate: false,
canChange: false,
};
this._extensions.set(uuid, extension);
@@ -446,6 +480,21 @@ var ExtensionManager = class {
}).forEach(extension => this.reloadExtension(extension));
}
_installExtensionUpdates() {
FileUtils.collectFromDatadirs('extension-updates', true, (dir, info) => {
let fileType = info.get_file_type();
if (fileType !== Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let extensionDir = Gio.File.new_for_path(
GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
FileUtils.recursivelyDeleteDir(extensionDir, false);
FileUtils.recursivelyMoveDir(dir, extensionDir);
FileUtils.recursivelyDeleteDir(dir, true);
});
}
_loadExtensions() {
global.settings.connect(`changed::${ENABLED_EXTENSIONS_KEY}`,
this._onEnabledExtensionsChanged.bind(this));
@@ -531,3 +580,27 @@ var ExtensionManager = class {
}
};
Signals.addSignalMethods(ExtensionManager.prototype);
const ExtensionUpdateSource = GObject.registerClass(
class ExtensionUpdateSource extends MessageTray.Source {
_init() {
let appSys = Shell.AppSystem.get_default();
this._app = appSys.lookup_app('org.gnome.Extensions.desktop');
super._init(this._app.get_name());
}
getIcon() {
return this._app.app_info.get_icon();
}
_createPolicy() {
return new MessageTray.NotificationApplicationPolicy(this._app.id);
}
open() {
this._app.activate();
Main.overview.hide();
Main.panel.closeCalendar();
}
});

View File

@@ -9,8 +9,6 @@ const Main = imports.ui.main;
var ICON_SIZE = 96;
var MIN_ICON_SIZE = 16;
var EXTRA_SPACE_ANIMATION_TIME = 250;
var ANIMATION_TIME_IN = 350;
var ANIMATION_TIME_OUT = 1 / 2 * ANIMATION_TIME_IN;
var ANIMATION_MAX_DELAY_FOR_ITEM = 2 / 3 * ANIMATION_TIME_IN;
@@ -846,10 +844,8 @@ var IconGrid = GObject.registerClass({
}
});
var PaginatedIconGrid = GObject.registerClass({
Signals: { 'space-opened': {},
'space-closed': {} },
}, class PaginatedIconGrid extends IconGrid {
var PaginatedIconGrid = GObject.registerClass(
class PaginatedIconGrid extends IconGrid {
_init(params) {
super._init(params);
this._nPages = 0;
@@ -981,94 +977,4 @@ var PaginatedIconGrid = GObject.registerClass({
throw new Error('Item not found.');
return Math.floor(index / this._childrenPerPage);
}
/**
* openExtraSpace:
* @param {Clutter.Actor} sourceItem: item for which to create extra space
* @param {St.Side} side: where @sourceItem should be located relative to
* the created space
* @param {number} nRows: the amount of space to create
*
* Pan view to create extra space for @nRows above or below @sourceItem.
*/
openExtraSpace(sourceItem, side, nRows) {
let children = this._getVisibleChildren();
let index = children.indexOf(sourceItem);
if (index == -1)
throw new Error('Item not found.');
let pageIndex = Math.floor(index / this._childrenPerPage);
let pageOffset = pageIndex * this._childrenPerPage;
let childrenPerRow = this._childrenPerPage / this._rowsPerPage;
let sourceRow = Math.floor((index - pageOffset) / childrenPerRow);
let nRowsAbove = side == St.Side.TOP ? sourceRow + 1 : sourceRow;
let nRowsBelow = this._rowsPerPage - nRowsAbove;
let nRowsUp, nRowsDown;
if (side == St.Side.TOP) {
nRowsDown = Math.min(nRowsBelow, nRows);
nRowsUp = nRows - nRowsDown;
} else {
nRowsUp = Math.min(nRowsAbove, nRows);
nRowsDown = nRows - nRowsUp;
}
let childrenDown = children.splice(pageOffset +
nRowsAbove * childrenPerRow,
nRowsBelow * childrenPerRow);
let childrenUp = children.splice(pageOffset,
nRowsAbove * childrenPerRow);
// Special case: On the last row with no rows below the icon,
// there's no need to move any rows either up or down
if (childrenDown.length == 0 && nRowsUp == 0) {
this._translatedChildren = [];
this.emit('space-opened');
} else {
this._translateChildren(childrenUp, St.DirectionType.UP, nRowsUp);
this._translateChildren(childrenDown, St.DirectionType.DOWN, nRowsDown);
this._translatedChildren = childrenUp.concat(childrenDown);
}
}
_translateChildren(children, direction, nRows) {
let translationY = nRows * (this._getVItemSize() + this._getSpacing());
if (translationY == 0)
return;
if (direction == St.DirectionType.UP)
translationY *= -1;
for (let i = 0; i < children.length; i++) {
children[i].translation_y = 0;
let params = {
translation_y: translationY,
duration: EXTRA_SPACE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
};
if (i == (children.length - 1))
params.onComplete = () => this.emit('space-opened');
children[i].ease(params);
}
}
closeExtraSpace() {
if (!this._translatedChildren || !this._translatedChildren.length) {
this.emit('space-closed');
return;
}
for (let i = 0; i < this._translatedChildren.length; i++) {
if (!this._translatedChildren[i].translation_y)
continue;
this._translatedChildren[i].ease({
translation_y: 0,
duration: EXTRA_SPACE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
onComplete: () => this.emit('space-closed'),
});
}
}
});

View File

@@ -1,5 +1,5 @@
/* exported InhibitShortcutsDialog */
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell } = imports.gi;
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi;
const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
@@ -75,22 +75,25 @@ var InhibitShortcutsDialog = GObject.registerClass({
_buildLayout() {
let name = this._app ? this._app.get_name() : this._window.title;
/* Translators: %s is an application name like "Settings" */
let title = name
? _("%s wants to inhibit shortcuts").format(name)
: _("Application wants to inhibit shortcuts");
let contentParams = { title };
let content = new Dialog.MessageDialogContent({
title: _('Allow inhibiting shortcuts'),
description: name
/* Translators: %s is an application name like "Settings" */
? _('The application %s wants to inhibit shortcuts').format(name)
: _('An application wants to inhibit shortcuts'),
});
let restoreAccel = this._getRestoreAccel();
if (restoreAccel) {
contentParams.description =
let restoreLabel = new St.Label({
/* Translators: %s is a keyboard shortcut like "Super+x" */
_("You can restore shortcuts by pressing %s.").format(restoreAccel);
text: _('You can restore shortcuts by pressing %s.').format(restoreAccel),
style_class: 'message-dialog-description',
});
content.add_child(restoreLabel);
}
let content = new Dialog.MessageDialogContent(contentParams);
this._dialog.contentLayout.add_actor(content);
this._dialog.contentLayout.add_child(content);
this._dialog.addButton({ label: _("Deny"),
action: () => {

View File

@@ -15,12 +15,12 @@ class KbdA11yDialog extends GObject.Object {
this._a11ySettings = new Gio.Settings({ schema_id: KEYBOARD_A11Y_SCHEMA });
let deviceManager = Clutter.DeviceManager.get_default();
deviceManager.connect('kbd-a11y-flags-changed',
this._showKbdA11yDialog.bind(this));
let seat = Clutter.get_default_backend().get_default_seat();
seat.connect('kbd-a11y-flags-changed',
this._showKbdA11yDialog.bind(this));
}
_showKbdA11yDialog(deviceManager, newFlags, whatChanged) {
_showKbdA11yDialog(seat, newFlags, whatChanged) {
let dialog = new ModalDialog.ModalDialog();
let title, description;
let key, enabled;
@@ -49,10 +49,8 @@ class KbdA11yDialog extends GObject.Object {
return;
}
let contentParams = { title, description, styleClass: 'access-dialog' };
let content = new Dialog.MessageDialogContent(contentParams);
dialog.contentLayout.add_actor(content);
let content = new Dialog.MessageDialogContent({ title, description });
dialog.contentLayout.add_child(content);
dialog.addButton({ label: enabled ? _("Leave On") : _("Turn On"),
action: () => {

View File

@@ -614,6 +614,7 @@ var EmojiPager = GObject.registerClass({
layout_manager: new Clutter.BinLayout(),
reactive: true,
clip_to_allocation: true,
y_expand: true,
});
this._sections = sections;
this._nCols = nCols;
@@ -934,7 +935,6 @@ var EmojiSelection = GObject.registerClass({
this.add_child(bottomRow);
this._curPage = 0;
this._emojiPager.setCurrentPage(0);
}
vfunc_map() {
@@ -942,11 +942,6 @@ var EmojiSelection = GObject.registerClass({
super.vfunc_map();
}
vfunc_unmap() {
super.vfunc_unmap();
this._emojiPager.setCurrentPage(0);
}
_onPageChanged(sectionLabel, page, nPages) {
this._curPage = page;
this._pageIndicator.setNPages(nPages);
@@ -1107,13 +1102,10 @@ var KeyboardManager = class KeyBoardManager {
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
this._a11yApplicationsSettings.connect('changed', this._syncEnabled.bind(this));
this._lastDeviceId = null;
Meta.get_backend().connect('last-device-changed', (backend, deviceId) => {
let manager = Clutter.DeviceManager.get_default();
let device = manager.get_device(deviceId);
this._lastDevice = null;
Meta.get_backend().connect('last-device-changed', (backend, device) => {
if (device.get_device_name().indexOf('XTEST') < 0) {
this._lastDeviceId = deviceId;
this._lastDevice = device;
this._syncEnabled();
}
});
@@ -1121,16 +1113,11 @@ var KeyboardManager = class KeyBoardManager {
}
_lastDeviceIsTouchscreen() {
if (!this._lastDeviceId)
if (!this._lastDevice)
return false;
let manager = Clutter.DeviceManager.get_default();
let device = manager.get_device(this._lastDeviceId);
if (!device)
return false;
return device.get_device_type() == Clutter.InputDeviceType.TOUCHSCREEN_DEVICE;
let deviceType = this._lastDevice.get_device_type();
return deviceType == Clutter.InputDeviceType.TOUCHSCREEN_DEVICE;
}
_syncEnabled() {
@@ -1290,7 +1277,10 @@ class Keyboard extends St.BoxLayout {
this._suggestions = new Suggestions();
this.add_child(this._suggestions);
this._aspectContainer = new AspectContainer({ layout_manager: new Clutter.BinLayout() });
this._aspectContainer = new AspectContainer({
layout_manager: new Clutter.BinLayout(),
y_expand: true,
});
this.add_child(this._aspectContainer);
this._emojiSelection = new EmojiSelection();
@@ -1590,7 +1580,17 @@ class Keyboard extends St.BoxLayout {
let maxHeight = monitor.height / 3;
this.width = monitor.width;
this.height = maxHeight;
if (monitor.width > monitor.height) {
this.height = maxHeight;
} else {
/* In portrait mode, lack of horizontal space means we won't be
* able to make the OSK that big while keeping size ratio, so
* we allow the OSK being smaller than 1/3rd of the monitor height
* there.
*/
this.height = Math.min(maxHeight, this.get_preferred_height(monitor.width));
}
}
_onGroupChanged() {
@@ -1829,8 +1829,8 @@ class Keyboard extends St.BoxLayout {
var KeyboardController = class {
constructor() {
let deviceManager = Clutter.DeviceManager.get_default();
this._virtualDevice = deviceManager.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
let seat = Clutter.get_default_backend().get_default_seat();
this._virtualDevice = seat.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
this._inputSourceManager = InputSourceManager.getInputSourceManager();
this._sourceChangedId = this._inputSourceManager.connect('current-source-changed',

View File

@@ -531,9 +531,9 @@ var Inspector = GObject.registerClass({
eventHandler.connect('scroll-event', this._onScrollEvent.bind(this));
eventHandler.connect('motion-event', this._onMotionEvent.bind(this));
let dm = Clutter.DeviceManager.get_default();
this._pointerDevice = dm.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE);
this._keyboardDevice = dm.get_core_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
let seat = Clutter.get_default_backend().get_default_seat();
this._pointerDevice = seat.get_pointer();
this._keyboardDevice = seat.get_keyboard();
this._pointerDevice.grab(eventHandler);
this._keyboardDevice.grab(eventHandler);

View File

@@ -745,7 +745,8 @@ var ZoomRegion = class ZoomRegion {
this._xCaret = 0;
this._yCaret = 0;
this._pointerIdleMonitor = Meta.IdleMonitor.get_for_device(Meta.VIRTUAL_CORE_POINTER_ID);
let seat = Clutter.get_default_backend().get_default_seat();
this._pointerIdleMonitor = Meta.IdleMonitor.get_for_device(seat.get_pointer());
this._scrollContentsTimerId = 0;
}

View File

@@ -2,7 +2,7 @@
/* exported componentManager, notificationDaemon, windowAttentionHandler,
ctrlAltTabManager, padOsdService, osdWindowManager,
osdMonitorLabeler, shellMountOpDBusService, shellDBusService,
shellAudioSelectionDBusService,
shellAccessDialogDBusService, shellAudioSelectionDBusService,
screenSaverDBus, screencastService, uiGroup, magnifier,
xdndHandler, keyboard, kbdA11yDialog, introspectService,
start, pushModal, popModal, activateWindow, createLookingGlass,
@@ -10,6 +10,7 @@
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const AccessDialog = imports.ui.accessDialog;
const AudioDeviceSelection = imports.ui.audioDeviceSelection;
const Components = imports.ui.components;
const CtrlAltTab = imports.ui.ctrlAltTab;
@@ -67,6 +68,7 @@ var padOsdService = null;
var osdWindowManager = null;
var osdMonitorLabeler = null;
var sessionMode = null;
var shellAccessDialogDBusService = null;
var shellAudioSelectionDBusService = null;
var shellDBusService = null;
var shellMountOpDBusService = null;
@@ -135,6 +137,7 @@ function start() {
St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
_initializeUI();
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
shellAudioSelectionDBusService = new AudioDeviceSelection.AudioDeviceSelectionDBus();
shellDBusService = new ShellDBus.GnomeShell();
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();

View File

@@ -137,6 +137,7 @@ class OverviewActor extends St.BoxLayout {
var Overview = class {
constructor() {
this._initCalled = false;
this._visible = false;
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
this._sessionUpdated();
@@ -689,5 +690,9 @@ var Overview = class {
return this.dash.showAppsButton;
}
get searchEntry() {
return this._overview.searchEntry;
}
};
Signals.addSignalMethods(Overview.prototype);

View File

@@ -31,15 +31,10 @@ var SlideLayout = GObject.registerClass({
'slide-x', 'slide-x', 'slide-x',
GObject.ParamFlags.READWRITE,
0, 1, 1),
'translation-x': GObject.ParamSpec.double(
'translation-x', 'translation-x', 'translation-x',
GObject.ParamFlags.READWRITE,
-Infinity, Infinity, 0),
},
}, class SlideLayout extends Clutter.FixedLayout {
_init(params) {
this._slideX = 1;
this._translationX = 0;
this._direction = SlideDirection.LEFT;
super._init(params);
@@ -72,7 +67,7 @@ var SlideLayout = GObject.registerClass({
: availWidth - natWidth * this._slideX;
let actorBox = new Clutter.ActorBox();
actorBox.x1 = box.x1 + alignX + this._translationX;
actorBox.x1 = box.x1 + alignX;
actorBox.x2 = actorBox.x1 + (child.x_expand ? availWidth : natWidth);
actorBox.y1 = box.y1;
actorBox.y2 = actorBox.y1 + availHeight;
@@ -102,20 +97,6 @@ var SlideLayout = GObject.registerClass({
get slideDirection() {
return this._direction;
}
// eslint-disable-next-line camelcase
set translation_x(value) {
if (this._translationX == value)
return;
this._translationX = value;
this.notify('translation-x');
this.layout_changed();
}
// eslint-disable-next-line camelcase
get translation_x() {
return this._translationX;
}
});
var SlidingControl = GObject.registerClass(
@@ -184,11 +165,12 @@ class SlidingControl extends St.Widget {
else
translationEnd = translation;
if (this.layout.translation_x == translationEnd)
if (this.translation_x === translationEnd)
return;
this.layout.translation_x = translationStart;
this.ease_property('@layout.translation-x', translationEnd, {
this.translation_x = translationStart;
this.ease({
translation_x: translationEnd,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: SIDE_CONTROLS_ANIMATION_TIME,
});

View File

@@ -648,15 +648,15 @@ var PadOsd = GObject.registerClass({
this._capturedEventId = global.stage.connect('captured-event', this._onCapturedEvent.bind(this));
this._padChooser = null;
let deviceManager = Clutter.DeviceManager.get_default();
this._deviceAddedId = deviceManager.connect('device-added', (manager, device) => {
let seat = Clutter.get_default_backend().get_default_seat();
this._deviceAddedId = seat.connect('device-added', (_seat, device) => {
if (device.get_device_type() == Clutter.InputDeviceType.PAD_DEVICE &&
this.padDevice.is_grouped(device)) {
this._groupPads.push(device);
this._updatePadChooser();
}
});
this._deviceRemovedId = deviceManager.connect('device-removed', (manager, device) => {
this._deviceRemovedId = seat.connect('device-removed', (_seat, device) => {
// If the device is being removed, destroy the padOsd.
if (device == this.padDevice) {
this.destroy();
@@ -669,7 +669,7 @@ var PadOsd = GObject.registerClass({
}
});
deviceManager.list_devices().forEach(device => {
seat.list_devices().forEach(device => {
if (device != this.padDevice &&
device.get_device_type() == Clutter.InputDeviceType.PAD_DEVICE &&
this.padDevice.is_grouped(device))
@@ -960,13 +960,13 @@ var PadOsd = GObject.registerClass({
Main.popModal(this);
this._actionEditor.close();
let deviceManager = Clutter.DeviceManager.get_default();
let seat = Clutter.get_default_backend().get_default_seat();
if (this._deviceRemovedId != 0) {
deviceManager.disconnect(this._deviceRemovedId);
seat.disconnect(this._deviceRemovedId);
this._deviceRemovedId = 0;
}
if (this._deviceAddedId != 0) {
deviceManager.disconnect(this._deviceAddedId);
seat.disconnect(this._deviceAddedId);
this._deviceAddedId = 0;
}
@@ -990,8 +990,8 @@ var PadOsdService = class {
ShowAsync(params, invocation) {
let [deviceNode, editionMode] = params;
let deviceManager = Clutter.DeviceManager.get_default();
let devices = deviceManager.list_devices();
let seat = Clutter.get_default_backend().get_default_seat();
let devices = seat.list_devices();
let padDevice = null;
devices.forEach(device => {

View File

@@ -108,9 +108,9 @@ var PieTimer = GObject.registerClass({
var PointerA11yTimeout = class PointerA11yTimeout {
constructor() {
let manager = Clutter.DeviceManager.get_default();
let seat = Clutter.get_default_backend().get_default_seat();
manager.connect('ptr-a11y-timeout-started', (o, device, type, timeout) => {
seat.connect('ptr-a11y-timeout-started', (o, device, type, timeout) => {
let [x, y] = global.get_pointer();
this._pieTimer = new PieTimer();
@@ -123,7 +123,7 @@ var PointerA11yTimeout = class PointerA11yTimeout {
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
});
manager.connect('ptr-a11y-timeout-stopped', (o, device, type, clicked) => {
seat.connect('ptr-a11y-timeout-stopped', (o, device, type, clicked) => {
if (!clicked)
this._pieTimer.destroy();

View File

@@ -305,25 +305,44 @@ class PopupSeparatorMenuItem extends PopupBaseMenuItem {
}
});
var Switch = GObject.registerClass(
class Switch extends St.Bin {
var Switch = GObject.registerClass({
Properties: {
'state': GObject.ParamSpec.boolean(
'state', 'state', 'state',
GObject.ParamFlags.READWRITE,
false),
},
}, class Switch extends St.Bin {
_init(state) {
super._init({ style_class: 'toggle-switch',
accessible_role: Atk.Role.CHECK_BOX,
can_focus: true });
this.setToggleState(state);
this._state = false;
super._init({
style_class: 'toggle-switch',
accessible_role: Atk.Role.CHECK_BOX,
can_focus: true,
state,
});
}
setToggleState(state) {
get state() {
return this._state;
}
set state(state) {
if (this._state === state)
return;
if (state)
this.add_style_pseudo_class('checked');
else
this.remove_style_pseudo_class('checked');
this.state = state;
this._state = state;
this.notify('state');
}
toggle() {
this.setToggleState(!this.state);
this.state = !this.state;
}
});
@@ -393,7 +412,7 @@ var PopupSwitchMenuItem = GObject.registerClass({
}
setToggleState(state) {
this._switch.setToggleState(state);
this._switch.state = state;
this.checkAccessibleState();
}

View File

@@ -3,6 +3,7 @@
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Dialog = imports.ui.dialog;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
@@ -18,13 +19,13 @@ const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
const EXEC_KEY = 'exec';
const EXEC_ARG_KEY = 'exec-arg';
var DIALOG_GROW_TIME = 100;
var RunDialog = GObject.registerClass(
class RunDialog extends ModalDialog.ModalDialog {
_init() {
super._init({ styleClass: 'run-dialog',
destroyOnClose: false });
super._init({
styleClass: 'run-dialog',
destroyOnClose: false,
});
this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
this._terminalSettings = new Gio.Settings({ schema_id: TERMINAL_SCHEMA });
@@ -54,58 +55,41 @@ class RunDialog extends ModalDialog.ModalDialog {
},
};
let label = new St.Label({ style_class: 'run-dialog-label',
text: _("Enter a Command") });
let title = _('Run a Command');
this.contentLayout.add_child(label);
let content = new Dialog.MessageDialogContent({ title });
this.contentLayout.add_actor(content);
let entry = new St.Entry({ style_class: 'run-dialog-entry',
can_focus: true });
let entry = new St.Entry({
style_class: 'run-dialog-entry',
can_focus: true,
});
ShellEntry.addContextMenu(entry);
entry.label_actor = label;
this._entryText = entry.clutter_text;
this.contentLayout.add_child(entry);
content.add_child(entry);
this.setInitialKeyFocus(this._entryText);
this._errorBox = new St.BoxLayout({ style_class: 'run-dialog-error-box' });
let defaultDescriptionText = _('Press ESC to close');
this.contentLayout.add_child(this._errorBox);
let errorIcon = new St.Icon({ icon_name: 'dialog-error-symbolic',
icon_size: 24,
style_class: 'run-dialog-error-icon',
y_align: Clutter.ActorAlign.CENTER });
this._errorBox.add_child(errorIcon);
this._descriptionLabel = new St.Label({
style_class: 'run-dialog-description',
text: defaultDescriptionText,
});
content.add_child(this._descriptionLabel);
this._commandError = false;
this._errorMessage = new St.Label({
style_class: 'run-dialog-error-label',
y_align: Clutter.ActorAlign.CENTER,
});
this._errorMessage.clutter_text.line_wrap = true;
this._errorBox.add_child(this._errorMessage);
this._errorBox.hide();
this.setButtons([{
action: this.close.bind(this),
label: _("Close"),
key: Clutter.KEY_Escape,
}]);
this._pathCompleter = new Gio.FilenameCompleter();
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entryText });
this._history = new History.HistoryManager({
gsettingsKey: HISTORY_KEY,
entry: this._entryText,
});
this._entryText.connect('activate', o => {
this.popModal();
this._run(o.get_text(),
Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK);
Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK);
if (!this._commandError ||
!this.pushModal())
this.close();
@@ -128,6 +112,18 @@ class RunDialog extends ModalDialog.ModalDialog {
}
return Clutter.EVENT_PROPAGATE;
});
this._entryText.connect('text-changed', () => {
this._descriptionLabel.set_text(defaultDescriptionText);
});
}
vfunc_key_release_event(event) {
if (event.keyval === Clutter.KEY_Escape) {
this.close();
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}
_getCommandCompletion(text) {
@@ -216,7 +212,7 @@ class RunDialog extends ModalDialog.ModalDialog {
let file = Gio.file_new_for_path(path);
try {
Gio.app_info_launch_default_for_uri(file.get_uri(),
global.create_app_launch_context(0, -1));
global.create_app_launch_context(0, -1));
} catch (err) {
// The exception from gjs contains an error string like:
// Error invoking Gio.app_info_launch_default_for_uri: No application
@@ -234,24 +230,7 @@ class RunDialog extends ModalDialog.ModalDialog {
_showError(message) {
this._commandError = true;
this._errorMessage.set_text(message);
if (!this._errorBox.visible) {
let [, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
let parentActor = this._errorBox.get_parent();
let height = parentActor.height + errorBoxNaturalHeight;
parentActor.ease({
height,
duration: DIALOG_GROW_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
parentActor.set_height(-1);
this._errorBox.show();
},
});
}
this._descriptionLabel.set_text(message);
}
_restart() {
@@ -266,7 +245,6 @@ class RunDialog extends ModalDialog.ModalDialog {
open() {
this._history.lastItem();
this._errorBox.hide();
this._entryText.set_text('');
this._commandError = false;

View File

@@ -5,8 +5,10 @@
const { Gio, GLib, Meta, Shell } = imports.gi;
const Config = imports.misc.config;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Util = imports.misc.util;
const { loadInterfaceXML } = imports.misc.fileUtils;
@@ -77,6 +79,12 @@ function _getPerfHelper() {
return _perfHelper;
}
function _spawnPerfHelper() {
let path = Config.LIBEXECDIR;
let command = `${path}/gnome-shell-perf-helper`;
Util.trySpawnCommandLine(command);
}
function _callRemote(obj, method, ...args) {
return new Promise((resolve, reject) => {
args.push((result, excp) => {
@@ -276,6 +284,25 @@ function _collect(scriptModule, outputFile) {
}
}
async function _runPerfScript(scriptModule, outputFile) {
for (let step of scriptModule.run()) {
try {
await step; // eslint-disable-line no-await-in-loop
} catch (err) {
log(`Script failed: ${err}\n${err.stack}`);
Meta.exit(Meta.ExitCode.ERROR);
}
}
try {
_collect(scriptModule, outputFile);
} catch (err) {
log(`Script failed: ${err}\n${err.stack}`);
Meta.exit(Meta.ExitCode.ERROR);
}
Meta.exit(Meta.ExitCode.SUCCESS);
}
/**
* runPerfScript
* @param {Object} scriptModule: module object with run and finish
@@ -317,23 +344,13 @@ function _collect(scriptModule, outputFile) {
* After running the script and collecting statistics from the
* event log, GNOME Shell will exit.
**/
async function runPerfScript(scriptModule, outputFile) {
function runPerfScript(scriptModule, outputFile) {
Shell.PerfLog.get_default().set_enabled(true);
_spawnPerfHelper();
for (let step of scriptModule.run()) {
try {
await step; // eslint-disable-line no-await-in-loop
} catch (err) {
log(`Script failed: ${err}\n${err.stack}`);
Meta.exit(Meta.ExitCode.ERROR);
}
}
try {
_collect(scriptModule, outputFile);
} catch (err) {
log(`Script failed: ${err}\n${err.stack}`);
Meta.exit(Meta.ExitCode.ERROR);
}
Meta.exit(Meta.ExitCode.SUCCESS);
Gio.bus_watch_name(Gio.BusType.SESSION,
'org.gnome.Shell.PerfHelper',
Gio.BusNameWatcherFlags.NONE,
() => _runPerfScript(scriptModule, outputFile),
null);
}

View File

@@ -302,7 +302,7 @@ var GnomeShellExtensions = class {
LaunchExtensionPrefs(uuid) {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
let app = appSys.lookup_app('org.gnome.Extensions.desktop');
let info = app.get_app_info();
let timestamp = global.display.get_current_time_roundtrip();
info.launch_uris([`extension:///${uuid}`],

View File

@@ -156,36 +156,53 @@ function addContextMenu(entry, params) {
var CapsLockWarning = GObject.registerClass(
class CapsLockWarning extends St.Label {
_init(params) {
let defaultParams = { style_class: 'prompt-dialog-error-label' };
let defaultParams = { style_class: 'caps-lock-warning-label' };
super._init(Object.assign(defaultParams, params));
this.text = _('Caps lock is on.');
this._keymap = Clutter.get_default_backend().get_keymap();
this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.clutter_text.line_wrap = true;
let seat = Clutter.get_default_backend().get_default_seat();
this._keymap = seat.get_keymap();
this._stateChangedId = 0;
this.connect('notify::mapped', () => {
if (this.is_mapped()) {
this.stateChangedId = this._keymap.connect('state-changed',
this._updateCapsLockWarningOpacity.bind(this));
this._stateChangedId = this._keymap.connect('state-changed',
() => this._sync(true));
} else {
this._keymap.disconnect(this.stateChangedId);
this.stateChangedId = 0;
this._keymap.disconnect(this._stateChangedId);
this._stateChangedId = 0;
}
this._updateCapsLockWarningOpacity();
this._sync(false);
});
this.connect('destroy', () => {
if (this.stateChangedId > 0)
this._keymap.disconnect(this.stateChangedId);
if (this._stateChangedId)
this._keymap.disconnect(this._stateChangedId);
});
this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.clutter_text.line_wrap = true;
}
_updateCapsLockWarningOpacity() {
_sync(animate) {
let capsLockOn = this._keymap.get_caps_lock_state();
this.opacity = capsLockOn ? 255 : 0;
this.remove_all_transitions();
this.natural_height_set = false;
let [, height] = this.get_preferred_height(-1);
this.natural_height_set = true;
this.ease({
height: capsLockOn ? height : 0,
opacity: capsLockOn ? 255 : 0,
duration: animate ? 200 : 0,
onComplete: () => {
if (capsLockOn)
this.height = -1;
},
});
}
});

View File

@@ -13,6 +13,7 @@ const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const { loadInterfaceXML } = imports.misc.fileUtils;
const Util = imports.misc.util;
var LIST_ITEM_ICON_SIZE = 48;
var WORK_SPINNER_ICON_SIZE = 16;
@@ -20,18 +21,23 @@ var WORK_SPINNER_ICON_SIZE = 16;
const REMEMBER_MOUNT_PASSWORD_KEY = 'remember-mount-password';
/* ------ Common Utils ------- */
function _setButtonsForChoices(dialog, choices) {
function _setButtonsForChoices(dialog, oldChoices, choices) {
let buttons = [];
let buttonsChanged = oldChoices.length !== choices.length;
for (let idx = 0; idx < choices.length; idx++) {
let button = idx;
buttonsChanged = buttonsChanged || oldChoices[idx] !== choices[idx];
buttons.unshift({
label: choices[idx],
action: () => dialog.emit('response', button),
});
}
dialog.setButtons(buttons);
if (buttonsChanged)
dialog.setButtons(buttons);
}
function _setLabelsForMessage(content, message) {
@@ -43,41 +49,6 @@ function _setLabelsForMessage(content, message) {
/* -------------------------------------------------------- */
var ListItem = GObject.registerClass({
Signals: { 'activate': {} },
}, class ListItem extends St.Button {
_init(app) {
let layout = new St.BoxLayout({ vertical: false });
super._init({
style_class: 'mount-dialog-app-list-item',
can_focus: true,
child: layout,
reactive: true,
});
this._app = app;
this._icon = this._app.create_icon_texture(LIST_ITEM_ICON_SIZE);
let iconBin = new St.Bin({ style_class: 'mount-dialog-app-list-item-icon',
child: this._icon });
layout.add(iconBin);
this._nameLabel = new St.Label({
text: this._app.get_name(),
style_class: 'mount-dialog-app-list-item-name',
y_align: Clutter.ActorAlign.CENTER,
});
let labelBin = new St.Bin({ child: this._nameLabel });
layout.add(labelBin);
}
vfunc_clicked() {
this.emit('activate');
this._app.activate();
}
});
var ShellMountOperation = class {
constructor(source, params) {
params = Params.parse(params, { existingDialog: null });
@@ -258,15 +229,27 @@ var ShellMountQuestionDialog = GObject.registerClass({
Signals: { 'response': { param_types: [GObject.TYPE_INT] } },
}, class ShellMountQuestionDialog extends ModalDialog.ModalDialog {
_init() {
super._init({ styleClass: 'mount-dialog' });
super._init({ styleClass: 'mount-question-dialog' });
this._oldChoices = [];
this._content = new Dialog.MessageDialogContent();
this.contentLayout.add_child(this._content);
}
vfunc_key_release_event(event) {
if (event.keyval === Clutter.KEY_Escape) {
this.emit('response', -1);
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}
update(message, choices) {
_setLabelsForMessage(this._content, message);
_setButtonsForChoices(this, choices);
_setButtonsForChoices(this, this._oldChoices, choices);
this._oldChoices = choices;
}
});
@@ -287,21 +270,18 @@ var ShellMountPasswordDialog = GObject.registerClass({
let disksApp = Shell.AppSystem.get_default().lookup_app('org.gnome.DiskUtility.desktop');
let content = new Dialog.MessageDialogContent({ title, description });
this.contentLayout.add_actor(content);
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
let grid = new St.Widget({ style_class: 'prompt-dialog-grid',
layout_manager: layout });
layout.hookup_style(grid);
let rtl = grid.get_text_direction() === Clutter.TextDirection.RTL;
let passwordGridLayout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
let passwordGrid = new St.Widget({
style_class: 'prompt-dialog-password-grid',
layout_manager: passwordGridLayout,
});
passwordGridLayout.hookup_style(passwordGrid);
let rtl = passwordGrid.get_text_direction() === Clutter.TextDirection.RTL;
let curGridRow = 0;
if (flags & Gio.AskPasswordFlags.TCRYPT) {
this._keyfilesLabel = new St.Label({
style_class: 'prompt-dialog-keyfiles-label',
visible: false,
y_align: Clutter.ActorAlign.CENTER,
});
this._hiddenVolume = new CheckBox.CheckBox(_("Hidden Volume"));
content.add_child(this._hiddenVolume);
@@ -312,6 +292,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._keyfilesCheckbox.connect("clicked", this._onKeyfilesCheckboxClicked.bind(this));
content.add_child(this._keyfilesCheckbox);
this._keyfilesLabel = new St.Label({ visible: false });
this._keyfilesLabel.clutter_text.set_markup(
/* Translators: %s is the Disks application */
_("To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead.").format(disksApp.get_name())
@@ -320,71 +301,65 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._keyfilesLabel.clutter_text.line_wrap = true;
content.add_child(this._keyfilesLabel);
this._pimLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
text: _("PIM Number"),
y_align: Clutter.ActorAlign.CENTER });
this._pimEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
hint_text: _('Enter PIM Number…'),
can_focus: true,
x_expand: true,
});
this._pimEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
ShellEntry.addContextMenu(this._pimEntry);
if (rtl) {
layout.attach(this._pimEntry, 0, 0, 1, 1);
layout.attach(this._pimLabel, 1, 0, 1, 1);
} else {
layout.attach(this._pimLabel, 0, 0, 1, 1);
layout.attach(this._pimEntry, 1, 0, 1, 1);
}
this._pimErrorMessageLabel = new St.Label({ style_class: 'prompt-dialog-password-entry',
text: _("The PIM must be a number or empty."),
visible: false });
layout.attach(this._pimErrorMessageLabel, 0, 2, 2, 1);
if (rtl)
passwordGridLayout.attach(this._pimEntry, 1, curGridRow, 1, 1);
else
passwordGridLayout.attach(this._pimEntry, 0, curGridRow, 1, 1);
curGridRow += 1;
} else {
this._hiddenVolume = null;
this._systemVolume = null;
this._pimEntry = null;
this._pimErrorMessageLabel = null;
}
this._passwordLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
text: _("Password"),
y_align: Clutter.ActorAlign.CENTER });
this._passwordEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
hint_text: _('Enter Password…'),
can_focus: true,
x_expand: true,
});
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
ShellEntry.addContextMenu(this._passwordEntry);
this.setInitialKeyFocus(this._passwordEntry);
ShellEntry.addContextMenu(this._passwordEntry);
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
animate: true,
});
this._passwordEntry.secondary_icon = this._workSpinner;
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
if (rtl) {
layout.attach(this._passwordEntry, 0, 1, 1, 1);
layout.attach(this._passwordLabel, 1, 1, 1, 1);
layout.attach(this._capsLockWarningLabel, 0, 2, 1, 1);
passwordGridLayout.attach(this._workSpinner, 0, curGridRow, 1, 1);
passwordGridLayout.attach(this._passwordEntry, 1, curGridRow, 1, 1);
} else {
layout.attach(this._passwordLabel, 0, 1, 1, 1);
layout.attach(this._passwordEntry, 1, 1, 1, 1);
layout.attach(this._capsLockWarningLabel, 1, 2, 1, 1);
passwordGridLayout.attach(this._passwordEntry, 0, curGridRow, 1, 1);
passwordGridLayout.attach(this._workSpinner, 1, curGridRow, 1, 1);
}
curGridRow += 1;
content.add_child(grid);
let warningBox = new St.BoxLayout({ vertical: true });
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
text: _("Sorry, that didnt work. Please try again.") });
let capsLockWarning = new ShellEntry.CapsLockWarning();
warningBox.add_child(capsLockWarning);
this._errorMessageLabel = new St.Label({
style_class: 'prompt-dialog-error-label',
opacity: 0,
});
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._errorMessageLabel.clutter_text.line_wrap = true;
this._errorMessageLabel.hide();
content.add_child(this._errorMessageLabel);
warningBox.add_child(this._errorMessageLabel);
passwordGridLayout.attach(warningBox, 0, curGridRow, 2, 1);
content.add_child(passwordGrid);
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
this._rememberChoice = new CheckBox.CheckBox(_("Remember Password"));
@@ -395,6 +370,8 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._rememberChoice = null;
}
this.contentLayout.add_child(content);
this._defaultButtons = [{
label: _("Cancel"),
action: this._onCancelButton.bind(this),
@@ -420,9 +397,12 @@ var ShellMountPasswordDialog = GObject.registerClass({
}
reaskPassword() {
this._passwordEntry.set_text('');
this._errorMessageLabel.show();
this._workSpinner.stop();
this._passwordEntry.set_text('');
this._errorMessageLabel.text = _('Sorry, that didnt work. Please try again.');
this._errorMessageLabel.opacity = 255;
Util.wiggle(this._passwordEntry);
}
_onCancelButton() {
@@ -435,14 +415,17 @@ var ShellMountPasswordDialog = GObject.registerClass({
_onEntryActivate() {
let pim = 0;
if (this._pimEntry !== null)
if (this._pimEntry !== null) {
pim = this._pimEntry.get_text();
if (isNaN(pim)) {
this._pimEntry.set_text('');
this._pimErrorMessageLabel.show();
return;
} else if (this._pimErrorMessageLabel !== null) {
this._pimErrorMessageLabel.hide();
if (isNaN(pim)) {
this._pimEntry.set_text('');
this._errorMessageLabel.text = _('The PIM must be a number or empty.');
this._errorMessageLabel.opacity = 255;
return;
}
this._errorMessageLabel.opacity = 0;
}
global.settings.set_boolean(REMEMBER_MOUNT_PASSWORD_KEY,
@@ -496,38 +479,30 @@ var ShellProcessesDialog = GObject.registerClass({
Signals: { 'response': { param_types: [GObject.TYPE_INT] } },
}, class ShellProcessesDialog extends ModalDialog.ModalDialog {
_init() {
super._init({ styleClass: 'mount-dialog' });
super._init({ styleClass: 'processes-dialog' });
this._oldChoices = [];
this._content = new Dialog.MessageDialogContent();
this.contentLayout.add_child(this._content);
let scrollView = new St.ScrollView({
style_class: 'mount-dialog-app-list',
x_expand: true,
y_expand: true,
});
scrollView.set_policy(St.PolicyType.NEVER,
St.PolicyType.AUTOMATIC);
this.contentLayout.add_child(scrollView);
scrollView.hide();
this._applicationSection = new Dialog.ListSection();
this._applicationSection.hide();
this.contentLayout.add_child(this._applicationSection);
}
this._applicationList = new St.BoxLayout({ vertical: true });
scrollView.add_actor(this._applicationList);
vfunc_key_release_event(event) {
if (event.keyval === Clutter.KEY_Escape) {
this.emit('response', -1);
return Clutter.EVENT_STOP;
}
this._applicationList.connect('actor-added', () => {
if (this._applicationList.get_n_children() == 1)
scrollView.show();
});
this._applicationList.connect('actor-removed', () => {
if (this._applicationList.get_n_children() == 0)
scrollView.hide();
});
return Clutter.EVENT_PROPAGATE;
}
_setAppsForPids(pids) {
// remove all the items
this._applicationList.destroy_all_children();
this._applicationSection.list.destroy_all_children();
pids.forEach(pid => {
let tracker = Shell.WindowTracker.get_default();
@@ -536,20 +511,22 @@ var ShellProcessesDialog = GObject.registerClass({
if (!app)
return;
let item = new ListItem(app);
this._applicationList.add_child(item);
item.connect('activate', () => {
// use -1 to indicate Cancel
this.emit('response', -1);
let listItem = new Dialog.ListSectionItem({
icon_actor: app.create_icon_texture(LIST_ITEM_ICON_SIZE),
title: app.get_name(),
});
this._applicationSection.list.add_child(listItem);
});
this._applicationSection.visible =
this._applicationSection.list.get_n_children() > 0;
}
update(message, processes, choices) {
this._setAppsForPids(processes);
_setLabelsForMessage(this._content, message);
_setButtonsForChoices(this, choices);
_setButtonsForChoices(this, this._oldChoices, choices);
this._oldChoices = choices;
}
});
@@ -701,8 +678,17 @@ var GnomeShellMountOpHandler = class {
this._dialog = new ShellMountQuestionDialog(message);
this._dialog.connect('response', (object, choice) => {
this._clearCurrentRequest(Gio.MountOperationResult.HANDLED,
{ choice: GLib.Variant.new('i', choice) });
let response;
let details = {};
if (choice == -1) {
response = Gio.MountOperationResult.ABORTED;
} else {
response = Gio.MountOperationResult.HANDLED;
details['choice'] = GLib.Variant.new('i', choice);
}
this._clearCurrentRequest(response, details);
});
this._dialog.update(message, choices);

View File

@@ -48,8 +48,8 @@ class DwellClickIndicator extends PanelMenu.Button {
this._a11ySettings.connect(`changed::${KEY_DWELL_CLICK_ENABLED}`, this._syncMenuVisibility.bind(this));
this._a11ySettings.connect(`changed::${KEY_DWELL_MODE}`, this._syncMenuVisibility.bind(this));
this._deviceManager = Clutter.DeviceManager.get_default();
this._deviceManager.connect('ptr-a11y-dwell-click-type-changed', this._updateClickType.bind(this));
this._seat = Clutter.get_default_backend().get_default_seat();
this._seat.connect('ptr-a11y-dwell-click-type-changed', this._updateClickType.bind(this));
this._addDwellAction(DWELL_CLICK_MODES.primary);
this._addDwellAction(DWELL_CLICK_MODES.double);
@@ -80,7 +80,7 @@ class DwellClickIndicator extends PanelMenu.Button {
}
_setClickType(mode) {
this._deviceManager.set_pointer_a11y_dwell_click_type(mode.type);
this._seat.set_pointer_a11y_dwell_click_type(mode.type);
this._icon.icon_name = mode.icon;
}
});

View File

@@ -347,22 +347,30 @@ var AppAuthorizer = class {
var GeolocationDialog = GObject.registerClass({
Signals: { 'response': { param_types: [GObject.TYPE_UINT] } },
}, class GeolocationDialog extends ModalDialog.ModalDialog {
_init(name, description, reqAccuracyLevel) {
_init(name, reason, reqAccuracyLevel) {
super._init({ styleClass: 'geolocation-dialog' });
this.reqAccuracyLevel = reqAccuracyLevel;
/* Translators: %s is an application name */
let title = _("Give %s access to your location?").format(name);
let content = new Dialog.MessageDialogContent({
title: _('Allow location access'),
/* Translators: %s is an application name */
description: _('The app %s wants to access your location').format(name),
});
let content = new Dialog.MessageDialogContent({ title, description });
this.contentLayout.add_actor(content);
let reasonLabel = new St.Label({
text: reason,
style_class: 'message-dialog-description',
});
content.add_child(reasonLabel);
let infoLabel = new St.Label({
text: _('Location access can be changed at any time from the privacy settings.'),
x_align: Clutter.ActorAlign.CENTER,
style_class: 'message-dialog-description',
});
content.add_child(infoLabel);
this.contentLayout.add_child(content);
let button = this.addButton({ label: _("Deny Access"),
action: this._onDenyClicked.bind(this),
key: Clutter.KEY_Escape });

View File

@@ -54,8 +54,10 @@ class Indicator extends PanelMenu.SystemIndicator {
let bindFlags = GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE;
let item;
item = new PopupMenu.PopupImageMenuItem(_('Lock Screen Rotation'),
item = new PopupMenu.PopupImageMenuItem(
this._systemActions.getName('lock-orientation'),
this._systemActions.orientation_lock_icon);
item.connect('activate', () => {
this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
this._systemActions.activateLockOrientation();
@@ -68,7 +70,10 @@ class Indicator extends PanelMenu.SystemIndicator {
bindFlags);
this._systemActions.connect('notify::orientation-lock-icon', () => {
let iconName = this._systemActions.orientation_lock_icon;
let labelText = this._systemActions.getName("lock-orientation");
this._orientationLockItem.setIcon(iconName);
this._orientationLockItem.label.text = labelText;
});
let app = this._settingsApp = Shell.AppSystem.get_default().lookup_app(

View File

@@ -45,21 +45,17 @@ const WINDOW_DIMMER_EFFECT_NAME = "gnome-shell-window-dimmer";
var DisplayChangeDialog = GObject.registerClass(
class DisplayChangeDialog extends ModalDialog.ModalDialog {
_init(wm) {
super._init({ styleClass: 'prompt-dialog' });
super._init();
this._wm = wm;
this._countDown = Meta.MonitorManager.get_display_configuration_timeout();
let title = _("Do you want to keep these display settings?");
// Translators: This string should be shorter than 30 characters
let title = _('Keep these display settings?');
let description = this._formatCountDown();
this._content = new Dialog.MessageDialogContent({
title, description,
x_expand: true,
y_expand: true,
});
this._content = new Dialog.MessageDialogContent({ title, description });
this.contentLayout.add_child(this._content);
/* Translators: this and the following message should be limited in length,

View File

@@ -426,7 +426,14 @@ class WorkspacesDisplay extends St.Widget {
this._swipeTracker.connect('begin', this._switchWorkspaceBegin.bind(this));
this._swipeTracker.connect('update', this._switchWorkspaceUpdate.bind(this));
this._swipeTracker.connect('end', this._switchWorkspaceEnd.bind(this));
this.bind_property('mapped', this._swipeTracker, 'enabled', GObject.BindingFlags.SYNC_CREATE);
this.connect('notify::mapped', this._updateSwipeTracker.bind(this));
this._windowDragBeginId =
Main.overview.connect('window-drag-begin',
this._windowDragBegin.bind(this));
this._windowDragEndId =
Main.overview.connect('window-drag-begin',
this._windowDragEnd.bind(this));
this._primaryIndex = Main.layoutManager.primaryIndex;
this._workspacesViews = [];
@@ -443,6 +450,7 @@ class WorkspacesDisplay extends St.Widget {
this._scrollTimeoutId = 0;
this._fullGeometry = null;
this._inWindowDrag = false;
this._gestureActive = false; // touch(pad) gestures
this._canScroll = true; // limiting scrolling speed
@@ -470,6 +478,22 @@ class WorkspacesDisplay extends St.Widget {
global.window_manager.disconnect(this._switchWorkspaceId);
global.workspace_manager.disconnect(this._reorderWorkspacesdId);
Main.overview.disconnect(this._windowDragBeginId);
Main.overview.disconnect(this._windowDragEndId);
}
_windowDragBegin() {
this._inWindowDrag = true;
this._updateSwipeTracker();
}
_windowDragEnd() {
this._inWindowDrag = false;
this._updateSwipeTracker();
}
_updateSwipeTracker() {
this._swipeTracker.enabled = this.mapped && !this._inWindowDrag;
}
_workspacesReordered() {

View File

@@ -55,8 +55,10 @@ pkglibdir = join_paths(libdir, meson.project_name())
autostartdir = join_paths(sysconfdir, 'xdg', 'autostart')
convertdir = join_paths(datadir, 'GConf', 'gsettings')
desktopdir = join_paths(datadir, 'applications')
icondir = join_paths(datadir, 'icons')
ifacedir = join_paths(datadir, 'dbus-1', 'interfaces')
localedir = join_paths(datadir, 'locale')
portaldir = join_paths(datadir, 'xdg-desktop-portal', 'portals')
schemadir = join_paths(datadir, 'glib-2.0', 'schemas')
servicedir = join_paths(datadir, 'dbus-1', 'services')

View File

@@ -8,6 +8,12 @@ datadir = os.path.join(prefix, 'share')
# Packaging tools define DESTDIR and this isn't needed for them
if 'DESTDIR' not in os.environ:
print('Updating icon cache...')
icon_cache_dir = os.path.join(datadir, 'icons', 'hicolor')
if not os.path.exists(icon_cache_dir):
os.makedirs(icon_cache_dir)
subprocess.call(['gtk-update-icon-cache', '-qtf', icon_cache_dir])
print('Updating desktop database...')
desktop_database_dir = os.path.join(datadir, 'applications')
if not os.path.exists(desktop_database_dir):

View File

@@ -1,17 +1,19 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
data/50-gnome-shell-system.xml
data/gnome-shell-extension-prefs.desktop.in.in
data/org.gnome.Extensions.desktop.in.in
data/org.gnome.Shell.desktop.in.in
data/org.gnome.shell.gschema.xml.in
data/org.gnome.Shell.PortalHelper.desktop.in.in
js/extensionPrefs/main.js
js/extensionPrefs/ui/extensions-window.ui
js/gdm/authPrompt.js
js/gdm/loginDialog.js
js/gdm/util.js
js/misc/systemActions.js
js/misc/util.js
js/portalHelper/main.js
js/ui/accessDialog.js
js/ui/appDisplay.js
js/ui/appFavorites.js
js/ui/audioDeviceSelection.js

306
po/ca.po
View File

@@ -10,8 +10,8 @@ msgid ""
msgstr ""
"Project-Id-Version: HEAD\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2019-12-27 13:16+0000\n"
"PO-Revision-Date: 2020-01-03 22:58+0100\n"
"POT-Creation-Date: 2020-01-25 01:15+0000\n"
"PO-Revision-Date: 2020-01-26 10:07+0100\n"
"Last-Translator: Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>\n"
"Language-Team: Catalan <tradgnome@softcatala.org>\n"
"Language: ca\n"
@@ -46,7 +46,7 @@ msgid "Open the application menu"
msgstr "Obre el menú d'aplicació"
#: data/gnome-shell-extension-prefs.desktop.in.in:4
#: js/extensionPrefs/main.js:210
#: js/extensionPrefs/main.js:209
msgid "Shell Extensions"
msgstr "Extensions del Shell"
@@ -415,11 +415,11 @@ msgstr ""
msgid "Network Login"
msgstr "Inici de sessió de xarxa"
#: js/extensionPrefs/main.js:103 js/extensionPrefs/main.js:526
#: js/extensionPrefs/main.js:102 js/extensionPrefs/main.js:525
msgid "Somethings gone wrong"
msgstr "Alguna cosa ha anat malament"
#: js/extensionPrefs/main.js:110
#: js/extensionPrefs/main.js:109
msgid ""
"Were very sorry, but theres been a problem: the settings for this "
"extension cant be displayed. We recommend that you report the issue to the "
@@ -428,27 +428,27 @@ msgstr ""
"Hi ha un problema: no es poden mostrar els paràmetres per a aquesta "
"extensió. Us recomanem que informeu del problema als autors de l'extensió."
#: js/extensionPrefs/main.js:117
#: js/extensionPrefs/main.js:116
msgid "Technical Details"
msgstr "Detalls tècnics"
#: js/extensionPrefs/main.js:152
#: js/extensionPrefs/main.js:151
msgid "Copy Error"
msgstr "Copia l'error"
#: js/extensionPrefs/main.js:179
#: js/extensionPrefs/main.js:178
msgid "Homepage"
msgstr "Pàgina d'inici"
#: js/extensionPrefs/main.js:180
#: js/extensionPrefs/main.js:179
msgid "Visit extension homepage"
msgstr "Visiteu la pàgina d'inici de l'extensió"
#: js/extensionPrefs/main.js:468
#: js/extensionPrefs/main.js:467
msgid "No Extensions Installed"
msgstr "No hi ha cap extensió instal·lada"
#: js/extensionPrefs/main.js:478
#: js/extensionPrefs/main.js:477
msgid ""
"Extensions can be installed through Software or <a href=\"https://extensions."
"gnome.org\">extensions.gnome.org</a>."
@@ -456,11 +456,11 @@ msgstr ""
"Les extensions es poden instal·lar amb el Programari o a <a href=\"https://"
"extensions.gnome.org\">extensions.gnome.org</a>."
#: js/extensionPrefs/main.js:493
#: js/extensionPrefs/main.js:492
msgid "Browse in Software"
msgstr "Navega al Programari"
#: js/extensionPrefs/main.js:533
#: js/extensionPrefs/main.js:532
msgid ""
"Were very sorry, but it was not possible to get the list of installed "
"extensions. Make sure you are logged into GNOME and try again."
@@ -469,9 +469,9 @@ msgstr ""
"heu entrat al GNOME i torneu a provar-ho."
#: js/gdm/authPrompt.js:174 js/ui/audioDeviceSelection.js:57
#: js/ui/components/networkAgent.js:130 js/ui/components/polkitAgent.js:139
#: js/ui/endSessionDialog.js:445 js/ui/extensionDownloader.js:190
#: js/ui/shellMountOperation.js:402 js/ui/shellMountOperation.js:412
#: js/ui/components/networkAgent.js:129 js/ui/components/polkitAgent.js:138
#: js/ui/endSessionDialog.js:374 js/ui/extensionDownloader.js:190
#: js/ui/shellMountOperation.js:399 js/ui/shellMountOperation.js:409
#: js/ui/status/network.js:910
msgid "Cancel"
msgstr "Cancel·la"
@@ -480,7 +480,7 @@ msgstr "Cancel·la"
msgid "Next"
msgstr "Següent"
#: js/gdm/authPrompt.js:237 js/ui/shellMountOperation.js:406
#: js/gdm/authPrompt.js:237 js/ui/shellMountOperation.js:403
#: js/ui/unlockDialog.js:44
msgid "Unlock"
msgstr "Desbloqueja"
@@ -508,8 +508,8 @@ msgstr "(p. ex. l'usuari o %s)"
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: js/gdm/loginDialog.js:899 js/ui/components/networkAgent.js:257
#: js/ui/components/networkAgent.js:280 js/ui/components/networkAgent.js:298
#: js/gdm/loginDialog.js:899 js/ui/components/networkAgent.js:256
#: js/ui/components/networkAgent.js:279 js/ui/components/networkAgent.js:297
msgid "Username: "
msgstr "Nom d'usuari:"
@@ -538,7 +538,7 @@ msgstr "Apaga"
#. Translators: A list of keywords that match the power-off action, separated by semicolons
#: js/misc/systemActions.js:92
msgid "power off;shutdown;reboot;restart"
msgid "power off;shutdown;reboot;restart;halt;stop"
msgstr "apaga;atura;reinicia"
#. Translators: The name of the lock screen action in search
@@ -749,56 +749,52 @@ msgstr ""
#. No support for non-modal system dialogs, so ignore the option
#. let modal = options['modal'] || true;
#: js/ui/accessDialog.js:39 js/ui/status/location.js:364
#: js/ui/accessDialog.js:39 js/ui/status/location.js:366
msgid "Deny Access"
msgstr "Denega l'accés"
#: js/ui/accessDialog.js:40 js/ui/status/location.js:367
#: js/ui/accessDialog.js:40 js/ui/status/location.js:369
msgid "Grant Access"
msgstr "Permet l'accés"
#: js/ui/appDisplay.js:921
#: js/ui/appDisplay.js:904
msgid "Unnamed Folder"
msgstr "Carpeta sense nom"
#: js/ui/appDisplay.js:944
#: js/ui/appDisplay.js:927
msgid "Frequently used applications will appear here"
msgstr "Les aplicacions utilitzades freqüentment apareixeran aquí"
#: js/ui/appDisplay.js:1079
#: js/ui/appDisplay.js:1062
msgid "Frequent"
msgstr "Freqüent"
#: js/ui/appDisplay.js:1086
#: js/ui/appDisplay.js:1069
msgid "All"
msgstr "Totes"
#: js/ui/appDisplay.js:1861
msgid "Rename"
msgstr "Canvia el nom"
#. Translators: This is the heading of a list of open windows
#: js/ui/appDisplay.js:2549 js/ui/panel.js:75
#: js/ui/appDisplay.js:2452 js/ui/panel.js:75
msgid "Open Windows"
msgstr "Obre finestres"
#: js/ui/appDisplay.js:2569 js/ui/panel.js:82
#: js/ui/appDisplay.js:2472 js/ui/panel.js:82
msgid "New Window"
msgstr "Finestra nova"
#: js/ui/appDisplay.js:2580
#: js/ui/appDisplay.js:2483
msgid "Launch using Dedicated Graphics Card"
msgstr "Inicia usant una targeta gràfica dedicada"
#: js/ui/appDisplay.js:2608 js/ui/dash.js:239
#: js/ui/appDisplay.js:2511 js/ui/dash.js:239
msgid "Remove from Favorites"
msgstr "Suprimeix dels preferits"
#: js/ui/appDisplay.js:2614
#: js/ui/appDisplay.js:2517
msgid "Add to Favorites"
msgstr "Afegeix als preferits"
#: js/ui/appDisplay.js:2624 js/ui/panel.js:93
#: js/ui/appDisplay.js:2527 js/ui/panel.js:93
msgid "Show Details"
msgstr "Mostra els detalls"
@@ -845,7 +841,7 @@ msgid "Settings"
msgstr "Paràmetres"
#. Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday).
#: js/ui/calendar.js:40
#: js/ui/calendar.js:41
msgctxt "calendar-no-work"
msgid "06"
msgstr "06"
@@ -855,43 +851,43 @@ msgstr "06"
#. * NOTE: These grid abbreviations are always shown together
#. * and in order, e.g. "S M T W T F S".
#.
#: js/ui/calendar.js:69
#: js/ui/calendar.js:70
msgctxt "grid sunday"
msgid "S"
msgstr "Dg"
#. Translators: Calendar grid abbreviation for Monday
#: js/ui/calendar.js:71
#: js/ui/calendar.js:72
msgctxt "grid monday"
msgid "M"
msgstr "Dl"
#. Translators: Calendar grid abbreviation for Tuesday
#: js/ui/calendar.js:73
#: js/ui/calendar.js:74
msgctxt "grid tuesday"
msgid "T"
msgstr "Dt"
#. Translators: Calendar grid abbreviation for Wednesday
#: js/ui/calendar.js:75
#: js/ui/calendar.js:76
msgctxt "grid wednesday"
msgid "W"
msgstr "Dc"
#. Translators: Calendar grid abbreviation for Thursday
#: js/ui/calendar.js:77
#: js/ui/calendar.js:78
msgctxt "grid thursday"
msgid "T"
msgstr "Dj"
#. Translators: Calendar grid abbreviation for Friday
#: js/ui/calendar.js:79
#: js/ui/calendar.js:80
msgctxt "grid friday"
msgid "F"
msgstr "Dv"
#. Translators: Calendar grid abbreviation for Saturday
#: js/ui/calendar.js:81
#: js/ui/calendar.js:82
msgctxt "grid saturday"
msgid "S"
msgstr "Ds"
@@ -902,7 +898,7 @@ msgstr "Ds"
#. * "%OB" is the new format specifier introduced in glibc 2.27,
#. * in most cases you should not change it.
#.
#: js/ui/calendar.js:370
#: js/ui/calendar.js:371
msgid "%OB"
msgstr "%OB"
@@ -915,55 +911,61 @@ msgstr "%OB"
#. * in most cases you should not use the old "%B" here unless you
#. * absolutely know what you are doing.
#.
#: js/ui/calendar.js:380
#: js/ui/calendar.js:381
msgid "%OB %Y"
msgstr "%OB de %Y"
#: js/ui/calendar.js:439
#: js/ui/calendar.js:440
msgid "Previous month"
msgstr "Mes anterior"
#: js/ui/calendar.js:454
#: js/ui/calendar.js:455
msgid "Next month"
msgstr "Mes següent"
#: js/ui/calendar.js:604
#: js/ui/calendar.js:605
#, no-javascript-format
msgctxt "date day number format"
msgid "%d"
msgstr "%-d"
#: js/ui/calendar.js:660
#: js/ui/calendar.js:661
msgid "Week %V"
msgstr "Setmana %-V"
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
#.
#: js/ui/calendar.js:729
#: js/ui/calendar.js:730
msgctxt "event list time"
msgid "All Day"
msgstr "Tot el dia"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: js/ui/calendar.js:867
msgctxt "calendar heading"
msgid "%A, %B %-d"
msgstr "%A %-d %B"
#: js/ui/calendar.js:871
#. Translators: Shown on calendar heading when selected day occurs on different year
#: js/ui/calendar.js:870
msgctxt "calendar heading"
msgid "%A, %B %-d, %Y"
msgstr "%A %d %B de %Y"
#: js/ui/calendar.js:1097
#: js/ui/calendar.js:1096
msgid "No Notifications"
msgstr "Cap notificació"
#: js/ui/calendar.js:1100
#: js/ui/calendar.js:1099
msgid "No Events"
msgstr "Cap cita"
#: js/ui/calendar.js:1132
#: js/ui/calendar.js:1153
msgid "Do Not Disturb"
msgstr "No molesteu"
#: js/ui/calendar.js:1167
msgid "Clear"
msgstr "Neteja-ho"
@@ -981,11 +983,11 @@ msgstr ""
"Podeu esperar un moment perquè continuï o podeu forçar-ne la sortida "
"completa."
#: js/ui/closeDialog.js:71
#: js/ui/closeDialog.js:70
msgid "Force Quit"
msgstr "Força la sortida"
#: js/ui/closeDialog.js:74
#: js/ui/closeDialog.js:73
msgid "Wait"
msgstr "Espera"
@@ -1011,53 +1013,53 @@ msgstr ""
msgid "Open with %s"
msgstr "Obre amb %s"
#: js/ui/components/keyring.js:71 js/ui/components/polkitAgent.js:279
#: js/ui/components/keyring.js:70 js/ui/components/polkitAgent.js:278
msgid "Password:"
msgstr "Contrasenya:"
#: js/ui/components/keyring.js:105
#: js/ui/components/keyring.js:104
msgid "Type again:"
msgstr "Torneu a escriure-la:"
#: js/ui/components/networkAgent.js:116
#: js/ui/components/networkAgent.js:115
msgid ""
"Alternatively you can connect by pushing the “WPS” button on your router."
msgstr "També us podeu connectar prement el botó «WPS» del vostre encaminador."
#: js/ui/components/networkAgent.js:124 js/ui/status/network.js:223
#: js/ui/components/networkAgent.js:123 js/ui/status/network.js:223
#: js/ui/status/network.js:314 js/ui/status/network.js:913
msgid "Connect"
msgstr "Connecta"
#. Cisco LEAP
#: js/ui/components/networkAgent.js:225 js/ui/components/networkAgent.js:237
#: js/ui/components/networkAgent.js:261 js/ui/components/networkAgent.js:282
#: js/ui/components/networkAgent.js:302 js/ui/components/networkAgent.js:312
#: js/ui/components/networkAgent.js:224 js/ui/components/networkAgent.js:236
#: js/ui/components/networkAgent.js:260 js/ui/components/networkAgent.js:281
#: js/ui/components/networkAgent.js:301 js/ui/components/networkAgent.js:311
msgid "Password: "
msgstr "Contrasenya:"
#. static WEP
#: js/ui/components/networkAgent.js:230
#: js/ui/components/networkAgent.js:229
msgid "Key: "
msgstr "Clau:"
#: js/ui/components/networkAgent.js:265 js/ui/components/networkAgent.js:288
#: js/ui/components/networkAgent.js:264 js/ui/components/networkAgent.js:287
msgid "Private key password: "
msgstr "Contrasenya de la clau privada:"
#: js/ui/components/networkAgent.js:286
#: js/ui/components/networkAgent.js:285
msgid "Identity: "
msgstr "Identitat:"
#: js/ui/components/networkAgent.js:300
#: js/ui/components/networkAgent.js:299
msgid "Service: "
msgstr "Servei:"
#: js/ui/components/networkAgent.js:329 js/ui/components/networkAgent.js:704
#: js/ui/components/networkAgent.js:328 js/ui/components/networkAgent.js:703
msgid "Authentication required by wireless network"
msgstr "La xarxa sense fil requereix autenticació"
#: js/ui/components/networkAgent.js:330 js/ui/components/networkAgent.js:705
#: js/ui/components/networkAgent.js:329 js/ui/components/networkAgent.js:704
#, javascript-format
msgid ""
"Passwords or encryption keys are required to access the wireless network "
@@ -1066,53 +1068,58 @@ msgstr ""
"Per accedir a la xarxa sense fil «%s» calen les contrasenyes o les claus "
"d'encriptació."
#: js/ui/components/networkAgent.js:334 js/ui/components/networkAgent.js:709
#: js/ui/components/networkAgent.js:333 js/ui/components/networkAgent.js:708
msgid "Wired 802.1X authentication"
msgstr "Autenticació 802.1X amb fil"
#: js/ui/components/networkAgent.js:336
#: js/ui/components/networkAgent.js:335
msgid "Network name: "
msgstr "Nom de la xarxa: "
#: js/ui/components/networkAgent.js:341 js/ui/components/networkAgent.js:713
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:712
msgid "DSL authentication"
msgstr "Autenticació DSL"
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:718
#: js/ui/components/networkAgent.js:347 js/ui/components/networkAgent.js:717
msgid "PIN code required"
msgstr "Cal que introduïu el codi PIN"
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:719
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:718
msgid "PIN code is needed for the mobile broadband device"
msgstr "Cal que introduïu el codi PIN del dispositiu de banda ampla mòbil"
#: js/ui/components/networkAgent.js:350
#: js/ui/components/networkAgent.js:349
msgid "PIN: "
msgstr "PIN: "
#: js/ui/components/networkAgent.js:357 js/ui/components/networkAgent.js:725
#: js/ui/components/networkAgent.js:356 js/ui/components/networkAgent.js:724
msgid "Mobile broadband network password"
msgstr "Contrasenya de la xarxa de banda ampla mòbil"
#: js/ui/components/networkAgent.js:358 js/ui/components/networkAgent.js:710
#: js/ui/components/networkAgent.js:714 js/ui/components/networkAgent.js:726
#: js/ui/components/networkAgent.js:357 js/ui/components/networkAgent.js:709
#: js/ui/components/networkAgent.js:713 js/ui/components/networkAgent.js:725
#: js/ui/components/networkAgent.js:729
#, javascript-format
msgid "A password is required to connect to “%s”."
msgstr "Cal introduir una contrasenya per connectar-vos a «%s»."
#: js/ui/components/networkAgent.js:693 js/ui/status/network.js:1688
#: js/ui/components/networkAgent.js:692 js/ui/status/network.js:1688
msgid "Network Manager"
msgstr "Gestor de connexions de xarxa"
#: js/ui/components/polkitAgent.js:42
#: js/ui/components/networkAgent.js:728
msgid "VPN password"
msgstr "Contrasenya VPN"
#: js/ui/components/polkitAgent.js:41
msgid "Authentication Required"
msgstr "Cal autenticació"
#: js/ui/components/polkitAgent.js:82
#: js/ui/components/polkitAgent.js:81
msgid "Administrator"
msgstr "Administrador"
#: js/ui/components/polkitAgent.js:142
#: js/ui/components/polkitAgent.js:141
msgid "Authenticate"
msgstr "Autentica"
@@ -1120,7 +1127,7 @@ msgstr "Autentica"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: js/ui/components/polkitAgent.js:260 js/ui/shellMountOperation.js:386
#: js/ui/components/polkitAgent.js:259 js/ui/shellMountOperation.js:383
msgid "Sorry, that didnt work. Please try again."
msgstr "No ha funcionat. Torneu-ho a provar."
@@ -1131,7 +1138,7 @@ msgstr "No ha funcionat. Torneu-ho a provar."
msgid "%s is now known as %s"
msgstr "En/na %s ara es diu %s"
#: js/ui/ctrlAltTab.js:21 js/ui/viewSelector.js:176
#: js/ui/ctrlAltTab.js:21 js/ui/viewSelector.js:177
msgid "Windows"
msgstr "Finestres"
@@ -1174,19 +1181,19 @@ msgstr "Rellotges del món"
msgid "Weather"
msgstr "El temps"
#: js/ui/dateMenu.js:389
#: js/ui/dateMenu.js:391
msgid "Select a location…"
msgstr "Trieu una ubicació…"
#: js/ui/dateMenu.js:402
#: js/ui/dateMenu.js:404
msgid "Loading…"
msgstr "S'està carregant…"
#: js/ui/dateMenu.js:412
#: js/ui/dateMenu.js:414
msgid "Go online for weather information"
msgstr "Vés en línia per a informació sobre el temps"
#: js/ui/dateMenu.js:414
#: js/ui/dateMenu.js:416
msgid "Weather information is currently unavailable"
msgstr "La informació sobre el temps no està disponible"
@@ -1220,56 +1227,56 @@ msgctxt "button"
msgid "Log Out"
msgstr "Surt"
#: js/ui/endSessionDialog.js:57
#: js/ui/endSessionDialog.js:56
msgctxt "title"
msgid "Power Off"
msgstr "Apagada"
#: js/ui/endSessionDialog.js:58
#: js/ui/endSessionDialog.js:57
msgctxt "title"
msgid "Install Updates & Power Off"
msgstr "Instal·la les actualitzacions i apaga"
#: js/ui/endSessionDialog.js:60
#: js/ui/endSessionDialog.js:59
#, javascript-format
msgid "The system will power off automatically in %d second."
msgid_plural "The system will power off automatically in %d seconds."
msgstr[0] "S'apagarà l'ordinador automàticament d'aquí %d segon."
msgstr[1] "S'apagarà l'ordinador automàticament d'aquí %d segons."
#: js/ui/endSessionDialog.js:64
#: js/ui/endSessionDialog.js:63
msgctxt "checkbox"
msgid "Install pending software updates"
msgstr "Instal·la les actualitzacions pendents"
#: js/ui/endSessionDialog.js:67 js/ui/endSessionDialog.js:84
#: js/ui/endSessionDialog.js:66 js/ui/endSessionDialog.js:82
msgctxt "button"
msgid "Restart"
msgstr "Reinicia"
#: js/ui/endSessionDialog.js:69
#: js/ui/endSessionDialog.js:68
msgctxt "button"
msgid "Power Off"
msgstr "Apaga"
#: js/ui/endSessionDialog.js:76
#: js/ui/endSessionDialog.js:74
msgctxt "title"
msgid "Restart"
msgstr "Reinici"
#: js/ui/endSessionDialog.js:78
#: js/ui/endSessionDialog.js:76
#, javascript-format
msgid "The system will restart automatically in %d second."
msgid_plural "The system will restart automatically in %d seconds."
msgstr[0] "Es reiniciarà l'ordinador automàticament d'aquí %d segon."
msgstr[1] "Es reiniciarà l'ordinador automàticament d'aquí %d segons."
#: js/ui/endSessionDialog.js:92
#: js/ui/endSessionDialog.js:89
msgctxt "title"
msgid "Restart & Install Updates"
msgstr "Reinicia i instal·la les actualitzacions"
#: js/ui/endSessionDialog.js:94
#: js/ui/endSessionDialog.js:91
#, javascript-format
msgid "The system will automatically restart and install updates in %d second."
msgid_plural ""
@@ -1281,22 +1288,22 @@ msgstr[1] ""
"Es reiniciarà l'ordinador automàticament i s'instal·laran les "
"actualitzacions d'aquí %d segons."
#: js/ui/endSessionDialog.js:100 js/ui/endSessionDialog.js:120
#: js/ui/endSessionDialog.js:97 js/ui/endSessionDialog.js:116
msgctxt "button"
msgid "Restart &amp; Install"
msgstr "Reinicia i instal·la"
#: js/ui/endSessionDialog.js:101
#: js/ui/endSessionDialog.js:98
msgctxt "button"
msgid "Install &amp; Power Off"
msgstr "Instal·la i apaga"
#: js/ui/endSessionDialog.js:102
#: js/ui/endSessionDialog.js:99
msgctxt "checkbox"
msgid "Power off after updates are installed"
msgstr "Apaga després d'instal·lar les actualitzacions"
#: js/ui/endSessionDialog.js:110
#: js/ui/endSessionDialog.js:106
msgctxt "title"
msgid "Restart & Install Upgrade"
msgstr "Reinicia i instal·la l'actualització"
@@ -1304,7 +1311,7 @@ msgstr "Reinicia i instal·la l'actualització"
#. Translators: This is the text displayed for system upgrades in the
#. shut down dialog. First %s gets replaced with the distro name and
#. second %s with the distro version to upgrade to
#: js/ui/endSessionDialog.js:115
#: js/ui/endSessionDialog.js:111
#, javascript-format
msgid ""
"%s %s will be installed after restart. Upgrade installation can take a long "
@@ -1314,30 +1321,30 @@ msgstr ""
"instal·lació pot trigar força temps. Assegureu-vos que heu fet còpia de "
"seguretat i que l'ordinador està connectat al corrent."
#: js/ui/endSessionDialog.js:301
msgid "Running on battery power: please plug in before installing updates."
#: js/ui/endSessionDialog.js:259
msgid "Running on battery power: Please plug in before installing updates."
msgstr ""
"S'està utilitzant la bateria: connecteu l'ordinador a la xarxa elèctrica "
"S'està utilitzant la bateria. Connecteu l'ordinador a la xarxa elèctrica "
"abans d'instal·lar les actualitzacions."
#: js/ui/endSessionDialog.js:320
msgid "Some applications are busy or have unsaved work."
#: js/ui/endSessionDialog.js:268
msgid "Some applications are busy or have unsaved work"
msgstr ""
"Hi ha algunes aplicacions que estan ocupades o que tenen documents sense "
"desar."
#: js/ui/endSessionDialog.js:327
msgid "Other users are logged in."
msgstr "Altres usuaris tenen la sessió oberta."
#: js/ui/endSessionDialog.js:273
msgid "Other users are logged in"
msgstr "Altres usuaris tenen la sessió oberta"
#. Translators: Remote here refers to a remote session, like a ssh login
#: js/ui/endSessionDialog.js:649
#: js/ui/endSessionDialog.js:588
#, javascript-format
msgid "%s (remote)"
msgstr "%s (remot)"
#. Translators: Console here refers to a tty like a VT console
#: js/ui/endSessionDialog.js:652
#: js/ui/endSessionDialog.js:591
#, javascript-format
msgid "%s (console)"
msgstr "%s (consola)"
@@ -1361,16 +1368,16 @@ msgid "Application wants to inhibit shortcuts"
msgstr "L'aplicació vol inhabilitar les dreceres"
#. Translators: %s is a keyboard shortcut like "Super+x"
#: js/ui/inhibitShortcutsDialog.js:90
#: js/ui/inhibitShortcutsDialog.js:89
#, javascript-format
msgid "You can restore shortcuts by pressing %s."
msgstr "Podeu restaurar les dreceres si premeu %s."
#: js/ui/inhibitShortcutsDialog.js:96
#: js/ui/inhibitShortcutsDialog.js:95
msgid "Deny"
msgstr "Denega"
#: js/ui/inhibitShortcutsDialog.js:103
#: js/ui/inhibitShortcutsDialog.js:102
msgid "Allow"
msgstr "Permet"
@@ -1418,16 +1425,16 @@ msgstr ""
"Això desactiva la funcionalitat de les tecles enganxoses, que afecta la "
"manera en què funciona el teclat."
#: js/ui/kbdA11yDialog.js:58
#: js/ui/kbdA11yDialog.js:57
msgid "Leave On"
msgstr "Deixa-ho actiu"
#: js/ui/kbdA11yDialog.js:58 js/ui/status/bluetooth.js:135
#: js/ui/kbdA11yDialog.js:57 js/ui/status/bluetooth.js:135
#: js/ui/status/network.js:1285
msgid "Turn On"
msgstr "Activa"
#: js/ui/kbdA11yDialog.js:66 js/ui/status/bluetooth.js:135
#: js/ui/kbdA11yDialog.js:65 js/ui/status/bluetooth.js:135
#: js/ui/status/network.js:131 js/ui/status/network.js:315
#: js/ui/status/network.js:1285 js/ui/status/network.js:1397
#: js/ui/status/nightLight.js:41 js/ui/status/rfkill.js:81
@@ -1435,7 +1442,7 @@ msgstr "Activa"
msgid "Turn Off"
msgstr "Desactiva"
#: js/ui/kbdA11yDialog.js:66
#: js/ui/kbdA11yDialog.js:65
msgid "Leave Off"
msgstr "Deixa-ho desactivat"
@@ -1655,11 +1662,11 @@ msgstr "El GNOME necessita bloquejar la pantalla"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: js/ui/screenShield.js:831 js/ui/screenShield.js:1303
#: js/ui/screenShield.js:830 js/ui/screenShield.js:1301
msgid "Unable to lock"
msgstr "No es pot blocar"
#: js/ui/screenShield.js:832 js/ui/screenShield.js:1304
#: js/ui/screenShield.js:831 js/ui/screenShield.js:1302
msgid "Lock was blocked by an application"
msgstr "Una aplicació està bloquejant el bloqueig"
@@ -1694,60 +1701,60 @@ msgstr "Mostra el text"
msgid "Hide Text"
msgstr "Oculta el text"
#: js/ui/shellEntry.js:161
#: js/ui/shellEntry.js:162
msgid "Caps lock is on."
msgstr "Bloq Maj està activat."
#: js/ui/shellMountOperation.js:308
#: js/ui/shellMountOperation.js:305
msgid "Hidden Volume"
msgstr "Volum ocult"
#: js/ui/shellMountOperation.js:311
#: js/ui/shellMountOperation.js:308
msgid "Windows System Volume"
msgstr "Volum del sistema del Windows"
#: js/ui/shellMountOperation.js:314
#: js/ui/shellMountOperation.js:311
msgid "Uses Keyfiles"
msgstr "Usa fitxers de claus"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:320
#: js/ui/shellMountOperation.js:317
#, javascript-format
msgid ""
"To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead."
msgstr ""
"Per a desbloquejar un volum que usa fitxers de claus, useu l'eina <i>%s</i>."
#: js/ui/shellMountOperation.js:327
#: js/ui/shellMountOperation.js:324
msgid "PIM Number"
msgstr "Número PIM"
#: js/ui/shellMountOperation.js:346
#: js/ui/shellMountOperation.js:343
msgid "The PIM must be a number or empty."
msgstr "El PIM ha de ser un nombre o estar buit."
#: js/ui/shellMountOperation.js:357
#: js/ui/shellMountOperation.js:354
msgid "Password"
msgstr "Contrasenya"
#: js/ui/shellMountOperation.js:393
#: js/ui/shellMountOperation.js:390
msgid "Remember Password"
msgstr "Recorda la contrasenya"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:417
#: js/ui/shellMountOperation.js:414
#, javascript-format
msgid "Open %s"
msgstr "Obre %s"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:489
#: js/ui/shellMountOperation.js:486
#, javascript-format
msgid "Unable to start %s"
msgstr "No es pot iniciar %s"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:491
#: js/ui/shellMountOperation.js:488
#, javascript-format
msgid "Couldnt find the %s application"
msgstr "No s'ha pogut trobar l'aplicació %s"
@@ -1844,11 +1851,11 @@ msgstr "Clic secundari"
msgid "Dwell Click"
msgstr "Clic en passar per sobre"
#: js/ui/status/keyboard.js:818
#: js/ui/status/keyboard.js:825
msgid "Keyboard"
msgstr "Teclat"
#: js/ui/status/keyboard.js:840
#: js/ui/status/keyboard.js:847
msgid "Show Keyboard Layout"
msgstr "Mostra la disposició del teclat"
@@ -1877,12 +1884,12 @@ msgid "Enable"
msgstr "Habilita"
#. Translators: %s is an application name
#: js/ui/status/location.js:357
#: js/ui/status/location.js:355
#, javascript-format
msgid "Give %s access to your location?"
msgstr "Voleu donar a %s accés a la vostra ubicació?"
#: js/ui/status/location.js:358
#: js/ui/status/location.js:361
msgid "Location access can be changed at any time from the privacy settings."
msgstr ""
"Podeu canviar la configuració de l'accés a la ubicació sempre que vulgueu "
@@ -2264,11 +2271,11 @@ msgstr "Entra amb un altre usuari"
msgid "Unlock Window"
msgstr "Desbloqueja la finestra"
#: js/ui/viewSelector.js:180
#: js/ui/viewSelector.js:181
msgid "Applications"
msgstr "Aplicacions"
#: js/ui/viewSelector.js:184
#: js/ui/viewSelector.js:185
msgid "Search"
msgstr "Cerca"
@@ -2277,22 +2284,22 @@ msgstr "Cerca"
msgid "“%s” is ready"
msgstr "«%s» ja està a punt"
#: js/ui/windowManager.js:57
#: js/ui/windowManager.js:54
msgid "Do you want to keep these display settings?"
msgstr "Voleu mantenir aquesta configuració de la pantalla?"
#. Translators: this and the following message should be limited in length,
#. to avoid ellipsizing the labels.
#.
#: js/ui/windowManager.js:71
#: js/ui/windowManager.js:68
msgid "Revert Settings"
msgstr "Descarta els canvis"
#: js/ui/windowManager.js:74
#: js/ui/windowManager.js:71
msgid "Keep Changes"
msgstr "Mantén els canvis"
#: js/ui/windowManager.js:92
#: js/ui/windowManager.js:89
#, javascript-format
msgid "Settings changes will revert in %d second"
msgid_plural "Settings changes will revert in %d seconds"
@@ -2301,7 +2308,7 @@ msgstr[1] "Es descartaran els canvis d'aquí %d segons"
#. Translators: This represents the size of a window. The first number is
#. * the width of the window and the second is the height.
#: js/ui/windowManager.js:690
#: js/ui/windowManager.js:546
#, javascript-format
msgid "%d × %d"
msgstr "%d × %d"
@@ -2390,12 +2397,12 @@ msgstr "Utilitza un mode específic, p. ex. «gdm» per la pantalla d'entrada"
msgid "List possible modes"
msgstr "Llista els modes possibles"
#: src/shell-app.c:265
#: src/shell-app.c:279
msgctxt "program"
msgid "Unknown"
msgstr "Desconegut"
#: src/shell-app.c:516
#: src/shell-app.c:530
#, c-format
msgid "Failed to launch “%s”"
msgstr "No s'ha pogut iniciar «%s»"
@@ -2753,6 +2760,9 @@ msgstr[1] "%u entrades"
msgid "System Sounds"
msgstr "Sons del sistema"
#~ msgid "Rename"
#~ msgstr "Canvia el nom"
#~ msgid "Account Settings"
#~ msgstr "Paràmetres del compte"

469
po/es.po

File diff suppressed because it is too large Load Diff

1385
po/fi.po

File diff suppressed because it is too large Load Diff

308
po/fur.po
View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: video-subtitles master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2019-12-20 22:04+0000\n"
"PO-Revision-Date: 2019-12-22 19:58+0100\n"
"POT-Creation-Date: 2020-01-26 09:11+0000\n"
"PO-Revision-Date: 2020-01-26 20:08+0100\n"
"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
"Language-Team: Friulian <fur@li.org>\n"
"Language: fur\n"
@@ -43,7 +43,7 @@ msgid "Open the application menu"
msgstr "Vierç il menù aplicazions"
#: data/gnome-shell-extension-prefs.desktop.in.in:4
#: js/extensionPrefs/main.js:210
#: js/extensionPrefs/main.js:209
msgid "Shell Extensions"
msgstr "Estensions Shell"
@@ -400,11 +400,11 @@ msgstr ""
msgid "Network Login"
msgstr "Acès di rêt"
#: js/extensionPrefs/main.js:103 js/extensionPrefs/main.js:526
#: js/extensionPrefs/main.js:102 js/extensionPrefs/main.js:525
msgid "Somethings gone wrong"
msgstr "Alc al è lât stuart"
#: js/extensionPrefs/main.js:110
#: js/extensionPrefs/main.js:109
msgid ""
"Were very sorry, but theres been a problem: the settings for this "
"extension cant be displayed. We recommend that you report the issue to the "
@@ -414,27 +414,27 @@ msgstr ""
"puedin jessi mostradis. Si consee di segnalâ il probleme ai autôrs de "
"estension."
#: js/extensionPrefs/main.js:117
#: js/extensionPrefs/main.js:116
msgid "Technical Details"
msgstr "Detais tecnics"
#: js/extensionPrefs/main.js:152
#: js/extensionPrefs/main.js:151
msgid "Copy Error"
msgstr "Copie erôr"
#: js/extensionPrefs/main.js:179
#: js/extensionPrefs/main.js:178
msgid "Homepage"
msgstr "Pagjine principâl"
#: js/extensionPrefs/main.js:180
#: js/extensionPrefs/main.js:179
msgid "Visit extension homepage"
msgstr "Visite la pagjine principâl de estension"
#: js/extensionPrefs/main.js:468
#: js/extensionPrefs/main.js:467
msgid "No Extensions Installed"
msgstr "Nissune estension instalade"
#: js/extensionPrefs/main.js:478
#: js/extensionPrefs/main.js:477
msgid ""
"Extensions can be installed through Software or <a href=\"https://extensions."
"gnome.org\">extensions.gnome.org</a>."
@@ -442,11 +442,11 @@ msgstr ""
"Si puedin instalâ lis estension cun Software o cun <a href=\"https://"
"extensions.gnome.org\">extensions.gnome.org</a>."
#: js/extensionPrefs/main.js:493
#: js/extensionPrefs/main.js:492
msgid "Browse in Software"
msgstr "Esplore in Software"
#: js/extensionPrefs/main.js:533
#: js/extensionPrefs/main.js:532
msgid ""
"Were very sorry, but it was not possible to get the list of installed "
"extensions. Make sure you are logged into GNOME and try again."
@@ -455,9 +455,9 @@ msgstr ""
"instaladis. Controle di jessi jentrât in GNOME e torne prove."
#: js/gdm/authPrompt.js:174 js/ui/audioDeviceSelection.js:57
#: js/ui/components/networkAgent.js:130 js/ui/components/polkitAgent.js:139
#: js/ui/endSessionDialog.js:445 js/ui/extensionDownloader.js:190
#: js/ui/shellMountOperation.js:402 js/ui/shellMountOperation.js:412
#: js/ui/components/networkAgent.js:129 js/ui/components/polkitAgent.js:138
#: js/ui/endSessionDialog.js:374 js/ui/extensionDownloader.js:190
#: js/ui/shellMountOperation.js:399 js/ui/shellMountOperation.js:409
#: js/ui/status/network.js:910
msgid "Cancel"
msgstr "Anule"
@@ -466,7 +466,7 @@ msgstr "Anule"
msgid "Next"
msgstr "Indenant"
#: js/gdm/authPrompt.js:237 js/ui/shellMountOperation.js:406
#: js/gdm/authPrompt.js:237 js/ui/shellMountOperation.js:403
#: js/ui/unlockDialog.js:44
msgid "Unlock"
msgstr "Sbloche"
@@ -494,8 +494,8 @@ msgstr "(p.e., utent o %s)"
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: js/gdm/loginDialog.js:899 js/ui/components/networkAgent.js:257
#: js/ui/components/networkAgent.js:280 js/ui/components/networkAgent.js:298
#: js/gdm/loginDialog.js:899 js/ui/components/networkAgent.js:256
#: js/ui/components/networkAgent.js:279 js/ui/components/networkAgent.js:297
msgid "Username: "
msgstr "Non utent: "
@@ -524,8 +524,8 @@ msgstr "Distudâ"
#. Translators: A list of keywords that match the power-off action, separated by semicolons
#: js/misc/systemActions.js:92
msgid "power off;shutdown;reboot;restart"
msgstr "distudâ;studâ;tornâ a inviâ"
msgid "power off;shutdown;reboot;restart;halt;stop"
msgstr "distudâ;studâ;tornâ a inviâ;fermâ"
#. Translators: The name of the lock screen action in search
#: js/misc/systemActions.js:97
@@ -735,56 +735,52 @@ msgstr ""
#. No support for non-modal system dialogs, so ignore the option
#. let modal = options['modal'] || true;
#: js/ui/accessDialog.js:39 js/ui/status/location.js:364
#: js/ui/accessDialog.js:39 js/ui/status/location.js:366
msgid "Deny Access"
msgstr "Dinee acès"
#: js/ui/accessDialog.js:40 js/ui/status/location.js:367
#: js/ui/accessDialog.js:40 js/ui/status/location.js:369
msgid "Grant Access"
msgstr "Garantìs l'acès"
#: js/ui/appDisplay.js:921
#: js/ui/appDisplay.js:904
msgid "Unnamed Folder"
msgstr "Cartele cence non"
#: js/ui/appDisplay.js:944
#: js/ui/appDisplay.js:927
msgid "Frequently used applications will appear here"
msgstr "Lis aplicazions dopradis dispès a vignaran mostradis culì"
#: js/ui/appDisplay.js:1079
#: js/ui/appDisplay.js:1062
msgid "Frequent"
msgstr "Dispès"
#: js/ui/appDisplay.js:1086
#: js/ui/appDisplay.js:1069
msgid "All"
msgstr "Dutis"
#: js/ui/appDisplay.js:1861
msgid "Rename"
msgstr "Cambie non"
#. Translators: This is the heading of a list of open windows
#: js/ui/appDisplay.js:2549 js/ui/panel.js:75
#: js/ui/appDisplay.js:2452 js/ui/panel.js:75
msgid "Open Windows"
msgstr "Barcons vierts"
#: js/ui/appDisplay.js:2569 js/ui/panel.js:82
#: js/ui/appDisplay.js:2472 js/ui/panel.js:82
msgid "New Window"
msgstr "Gnûf barcon"
#: js/ui/appDisplay.js:2580
#: js/ui/appDisplay.js:2483
msgid "Launch using Dedicated Graphics Card"
msgstr "Invie doprant une schede grafiche dedicade"
#: js/ui/appDisplay.js:2608 js/ui/dash.js:239
#: js/ui/appDisplay.js:2511 js/ui/dash.js:239
msgid "Remove from Favorites"
msgstr "Gjave dai preferîts"
#: js/ui/appDisplay.js:2614
#: js/ui/appDisplay.js:2517
msgid "Add to Favorites"
msgstr "Zonte tai preferîts"
#: js/ui/appDisplay.js:2624 js/ui/panel.js:93
#: js/ui/appDisplay.js:2527 js/ui/panel.js:93
msgid "Show Details"
msgstr "Mostre Detais"
@@ -831,7 +827,7 @@ msgid "Settings"
msgstr "Impostazions"
#. Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday).
#: js/ui/calendar.js:40
#: js/ui/calendar.js:41
msgctxt "calendar-no-work"
msgid "06"
msgstr "06"
@@ -841,43 +837,43 @@ msgstr "06"
#. * NOTE: These grid abbreviations are always shown together
#. * and in order, e.g. "S M T W T F S".
#.
#: js/ui/calendar.js:69
#: js/ui/calendar.js:70
msgctxt "grid sunday"
msgid "S"
msgstr "D"
#. Translators: Calendar grid abbreviation for Monday
#: js/ui/calendar.js:71
#: js/ui/calendar.js:72
msgctxt "grid monday"
msgid "M"
msgstr "L"
#. Translators: Calendar grid abbreviation for Tuesday
#: js/ui/calendar.js:73
#: js/ui/calendar.js:74
msgctxt "grid tuesday"
msgid "T"
msgstr "M"
#. Translators: Calendar grid abbreviation for Wednesday
#: js/ui/calendar.js:75
#: js/ui/calendar.js:76
msgctxt "grid wednesday"
msgid "W"
msgstr "M"
#. Translators: Calendar grid abbreviation for Thursday
#: js/ui/calendar.js:77
#: js/ui/calendar.js:78
msgctxt "grid thursday"
msgid "T"
msgstr "J"
#. Translators: Calendar grid abbreviation for Friday
#: js/ui/calendar.js:79
#: js/ui/calendar.js:80
msgctxt "grid friday"
msgid "F"
msgstr "V"
#. Translators: Calendar grid abbreviation for Saturday
#: js/ui/calendar.js:81
#: js/ui/calendar.js:82
msgctxt "grid saturday"
msgid "S"
msgstr "S"
@@ -888,7 +884,7 @@ msgstr "S"
#. * "%OB" is the new format specifier introduced in glibc 2.27,
#. * in most cases you should not change it.
#.
#: js/ui/calendar.js:370
#: js/ui/calendar.js:371
msgid "%OB"
msgstr "%OB"
@@ -901,55 +897,61 @@ msgstr "%OB"
#. * in most cases you should not use the old "%B" here unless you
#. * absolutely know what you are doing.
#.
#: js/ui/calendar.js:380
#: js/ui/calendar.js:381
msgid "%OB %Y"
msgstr "%OB dal %Y"
#: js/ui/calendar.js:439
#: js/ui/calendar.js:440
msgid "Previous month"
msgstr "Mês indaûr"
#: js/ui/calendar.js:454
#: js/ui/calendar.js:455
msgid "Next month"
msgstr "Prossim mês"
#: js/ui/calendar.js:604
#: js/ui/calendar.js:605
#, no-javascript-format
msgctxt "date day number format"
msgid "%d"
msgstr "%d"
#: js/ui/calendar.js:660
#: js/ui/calendar.js:661
msgid "Week %V"
msgstr "Setemane %V"
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
#.
#: js/ui/calendar.js:729
#: js/ui/calendar.js:730
msgctxt "event list time"
msgid "All Day"
msgstr "Dut il dì"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: js/ui/calendar.js:867
msgctxt "calendar heading"
msgid "%A, %B %-d"
msgstr "%A, %-d di %B"
#: js/ui/calendar.js:871
#. Translators: Shown on calendar heading when selected day occurs on different year
#: js/ui/calendar.js:870
msgctxt "calendar heading"
msgid "%A, %B %-d, %Y"
msgstr "%A, %-d di %B dal %Y"
#: js/ui/calendar.js:1097
#: js/ui/calendar.js:1096
msgid "No Notifications"
msgstr "Nissune notifiche"
#: js/ui/calendar.js:1100
#: js/ui/calendar.js:1099
msgid "No Events"
msgstr "Nissun event"
#: js/ui/calendar.js:1132
#: js/ui/calendar.js:1153
msgid "Do Not Disturb"
msgstr "No sta disturbâ"
#: js/ui/calendar.js:1167
msgid "Clear"
msgstr "Nete"
@@ -967,11 +969,11 @@ msgstr ""
"Si pues sielzi di spietâ un tic che al continui o sfuarçâ la aplicazion a "
"jessî dal dut."
#: js/ui/closeDialog.js:71
#: js/ui/closeDialog.js:70
msgid "Force Quit"
msgstr "Sfuarce jessude"
#: js/ui/closeDialog.js:74
#: js/ui/closeDialog.js:73
msgid "Wait"
msgstr "Spiete"
@@ -996,54 +998,54 @@ msgstr "La version di udisks instalade no supuarte la impostazion PIM"
msgid "Open with %s"
msgstr "Vierç cun %s"
#: js/ui/components/keyring.js:71 js/ui/components/polkitAgent.js:279
#: js/ui/components/keyring.js:70 js/ui/components/polkitAgent.js:278
msgid "Password:"
msgstr "Password:"
#: js/ui/components/keyring.js:105
#: js/ui/components/keyring.js:104
msgid "Type again:"
msgstr "Scîf di gnûf:"
#: js/ui/components/networkAgent.js:116
#: js/ui/components/networkAgent.js:115
msgid ""
"Alternatively you can connect by pushing the “WPS” button on your router."
msgstr ""
"In alternative al è pussibil conetisi fracant il boton “WPS” sul router."
#: js/ui/components/networkAgent.js:124 js/ui/status/network.js:223
#: js/ui/components/networkAgent.js:123 js/ui/status/network.js:223
#: js/ui/status/network.js:314 js/ui/status/network.js:913
msgid "Connect"
msgstr "Conet"
#. Cisco LEAP
#: js/ui/components/networkAgent.js:225 js/ui/components/networkAgent.js:237
#: js/ui/components/networkAgent.js:261 js/ui/components/networkAgent.js:282
#: js/ui/components/networkAgent.js:302 js/ui/components/networkAgent.js:312
#: js/ui/components/networkAgent.js:224 js/ui/components/networkAgent.js:236
#: js/ui/components/networkAgent.js:260 js/ui/components/networkAgent.js:281
#: js/ui/components/networkAgent.js:301 js/ui/components/networkAgent.js:311
msgid "Password: "
msgstr "Password: "
#. static WEP
#: js/ui/components/networkAgent.js:230
#: js/ui/components/networkAgent.js:229
msgid "Key: "
msgstr "Clâf: "
#: js/ui/components/networkAgent.js:265 js/ui/components/networkAgent.js:288
#: js/ui/components/networkAgent.js:264 js/ui/components/networkAgent.js:287
msgid "Private key password: "
msgstr "Password di clâf privade: "
#: js/ui/components/networkAgent.js:286
#: js/ui/components/networkAgent.js:285
msgid "Identity: "
msgstr "Identitât: "
#: js/ui/components/networkAgent.js:300
#: js/ui/components/networkAgent.js:299
msgid "Service: "
msgstr "Servizi: "
#: js/ui/components/networkAgent.js:329 js/ui/components/networkAgent.js:704
#: js/ui/components/networkAgent.js:328 js/ui/components/networkAgent.js:703
msgid "Authentication required by wireless network"
msgstr "La rêt cence fîl e domande autenticazion"
#: js/ui/components/networkAgent.js:330 js/ui/components/networkAgent.js:705
#: js/ui/components/networkAgent.js:329 js/ui/components/networkAgent.js:704
#, javascript-format
msgid ""
"Passwords or encryption keys are required to access the wireless network "
@@ -1052,53 +1054,58 @@ msgstr ""
"Si scugne meti une password o une clâf di cifradure par jentrâ te rêt cence "
"fîl \"%s\"."
#: js/ui/components/networkAgent.js:334 js/ui/components/networkAgent.js:709
#: js/ui/components/networkAgent.js:333 js/ui/components/networkAgent.js:708
msgid "Wired 802.1X authentication"
msgstr "Autenticazion vie fîl 802.1X"
#: js/ui/components/networkAgent.js:336
#: js/ui/components/networkAgent.js:335
msgid "Network name: "
msgstr "Non rêt: "
#: js/ui/components/networkAgent.js:341 js/ui/components/networkAgent.js:713
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:712
msgid "DSL authentication"
msgstr "Autenticazion DSL"
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:718
#: js/ui/components/networkAgent.js:347 js/ui/components/networkAgent.js:717
msgid "PIN code required"
msgstr "Si pretint un codiç PIN"
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:719
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:718
msgid "PIN code is needed for the mobile broadband device"
msgstr "Si scugne meti un codiç PIN pal dispositîf a bande largje mobil"
#: js/ui/components/networkAgent.js:350
#: js/ui/components/networkAgent.js:349
msgid "PIN: "
msgstr "PIN: "
#: js/ui/components/networkAgent.js:357 js/ui/components/networkAgent.js:725
#: js/ui/components/networkAgent.js:356 js/ui/components/networkAgent.js:724
msgid "Mobile broadband network password"
msgstr "Passowrd rêt mobil a bande largje"
#: js/ui/components/networkAgent.js:358 js/ui/components/networkAgent.js:710
#: js/ui/components/networkAgent.js:714 js/ui/components/networkAgent.js:726
#: js/ui/components/networkAgent.js:357 js/ui/components/networkAgent.js:709
#: js/ui/components/networkAgent.js:713 js/ui/components/networkAgent.js:725
#: js/ui/components/networkAgent.js:729
#, javascript-format
msgid "A password is required to connect to “%s”."
msgstr "A covente une password par tacâsi a '%s'."
#: js/ui/components/networkAgent.js:693 js/ui/status/network.js:1688
#: js/ui/components/networkAgent.js:692 js/ui/status/network.js:1688
msgid "Network Manager"
msgstr "Ministradôr di rêt"
#: js/ui/components/polkitAgent.js:42
#: js/ui/components/networkAgent.js:728
msgid "VPN password"
msgstr "Password VPN"
#: js/ui/components/polkitAgent.js:41
msgid "Authentication Required"
msgstr "Autenticazion Necessarie"
#: js/ui/components/polkitAgent.js:82
#: js/ui/components/polkitAgent.js:81
msgid "Administrator"
msgstr "Aministradôr"
#: js/ui/components/polkitAgent.js:142
#: js/ui/components/polkitAgent.js:141
msgid "Authenticate"
msgstr "Autentiche"
@@ -1106,7 +1113,7 @@ msgstr "Autentiche"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: js/ui/components/polkitAgent.js:260 js/ui/shellMountOperation.js:386
#: js/ui/components/polkitAgent.js:259 js/ui/shellMountOperation.js:383
msgid "Sorry, that didnt work. Please try again."
msgstr "Mi displâs, no je lade drete. Prove di gnûf."
@@ -1117,7 +1124,7 @@ msgstr "Mi displâs, no je lade drete. Prove di gnûf."
msgid "%s is now known as %s"
msgstr "L'utent %s al è cognossût cumò come %s"
#: js/ui/ctrlAltTab.js:21 js/ui/viewSelector.js:176
#: js/ui/ctrlAltTab.js:21 js/ui/viewSelector.js:177
msgid "Windows"
msgstr "Barcons"
@@ -1160,19 +1167,19 @@ msgstr "Orlois mondiâi"
msgid "Weather"
msgstr "Timp"
#: js/ui/dateMenu.js:389
#: js/ui/dateMenu.js:391
msgid "Select a location…"
msgstr "Selezione une posizion…"
#: js/ui/dateMenu.js:402
#: js/ui/dateMenu.js:404
msgid "Loading…"
msgstr "Daûr a cjariâ…"
#: js/ui/dateMenu.js:412
#: js/ui/dateMenu.js:414
msgid "Go online for weather information"
msgstr "Va in rêt pes informazions sul timp"
#: js/ui/dateMenu.js:414
#: js/ui/dateMenu.js:416
msgid "Weather information is currently unavailable"
msgstr "Lis informazions sul timp al moment no son disponibilis"
@@ -1206,56 +1213,56 @@ msgctxt "button"
msgid "Log Out"
msgstr "Jes"
#: js/ui/endSessionDialog.js:57
#: js/ui/endSessionDialog.js:56
msgctxt "title"
msgid "Power Off"
msgstr "Distude"
#: js/ui/endSessionDialog.js:58
#: js/ui/endSessionDialog.js:57
msgctxt "title"
msgid "Install Updates & Power Off"
msgstr "Instale inzornaments e distude"
#: js/ui/endSessionDialog.js:60
#: js/ui/endSessionDialog.js:59
#, javascript-format
msgid "The system will power off automatically in %d second."
msgid_plural "The system will power off automatically in %d seconds."
msgstr[0] "Il sisteme si distudarà in automatic chi di %d secont."
msgstr[1] "Il sisteme si studarà in automatic chi di %d seconts."
#: js/ui/endSessionDialog.js:64
#: js/ui/endSessionDialog.js:63
msgctxt "checkbox"
msgid "Install pending software updates"
msgstr "Instale i inzornaments software in spiete"
#: js/ui/endSessionDialog.js:67 js/ui/endSessionDialog.js:84
#: js/ui/endSessionDialog.js:66 js/ui/endSessionDialog.js:82
msgctxt "button"
msgid "Restart"
msgstr "Torne invie"
#: js/ui/endSessionDialog.js:69
#: js/ui/endSessionDialog.js:68
msgctxt "button"
msgid "Power Off"
msgstr "Distude"
#: js/ui/endSessionDialog.js:76
#: js/ui/endSessionDialog.js:74
msgctxt "title"
msgid "Restart"
msgstr "Torne invie"
#: js/ui/endSessionDialog.js:78
#: js/ui/endSessionDialog.js:76
#, javascript-format
msgid "The system will restart automatically in %d second."
msgid_plural "The system will restart automatically in %d seconds."
msgstr[0] "Il sisteme si tornarà a inviâ in automatic chi di %d secont."
msgstr[1] "Il sisteme si tornarà a inviâ in automatic chi di %d secont."
#: js/ui/endSessionDialog.js:92
#: js/ui/endSessionDialog.js:89
msgctxt "title"
msgid "Restart & Install Updates"
msgstr "Torne a inviâ e instale inzornaments"
#: js/ui/endSessionDialog.js:94
#: js/ui/endSessionDialog.js:91
#, javascript-format
msgid "The system will automatically restart and install updates in %d second."
msgid_plural ""
@@ -1267,22 +1274,22 @@ msgstr[1] ""
"Il sisteme al tornarà a inviâsi in automatic instalant i inzornaments chi di "
"%d seconts."
#: js/ui/endSessionDialog.js:100 js/ui/endSessionDialog.js:120
#: js/ui/endSessionDialog.js:97 js/ui/endSessionDialog.js:116
msgctxt "button"
msgid "Restart &amp; Install"
msgstr "Torne invie e instale"
#: js/ui/endSessionDialog.js:101
#: js/ui/endSessionDialog.js:98
msgctxt "button"
msgid "Install &amp; Power Off"
msgstr "Instale e distude"
#: js/ui/endSessionDialog.js:102
#: js/ui/endSessionDialog.js:99
msgctxt "checkbox"
msgid "Power off after updates are installed"
msgstr "Distude dopo vê instalât i inzornaments"
#: js/ui/endSessionDialog.js:110
#: js/ui/endSessionDialog.js:106
msgctxt "title"
msgid "Restart & Install Upgrade"
msgstr "Torne invie e instale avanzament"
@@ -1290,7 +1297,7 @@ msgstr "Torne invie e instale avanzament"
#. Translators: This is the text displayed for system upgrades in the
#. shut down dialog. First %s gets replaced with the distro name and
#. second %s with the distro version to upgrade to
#: js/ui/endSessionDialog.js:115
#: js/ui/endSessionDialog.js:111
#, javascript-format
msgid ""
"%s %s will be installed after restart. Upgrade installation can take a long "
@@ -1300,28 +1307,28 @@ msgstr ""
"dal avanzament e pues tirâ a dilunc: siguriti di vê fat i backup e che il to "
"computer al sedi tacât."
#: js/ui/endSessionDialog.js:301
msgid "Running on battery power: please plug in before installing updates."
#: js/ui/endSessionDialog.js:259
msgid "Running on battery power: Please plug in before installing updates."
msgstr ""
"Funzionament su batarie: par plasê tache la spine prime di instalâ i "
"inzornaments."
#: js/ui/endSessionDialog.js:320
msgid "Some applications are busy or have unsaved work."
msgstr "Cualchi aplicazion e je impegnade opûr e à lavôrs no salvâts."
#: js/ui/endSessionDialog.js:268
msgid "Some applications are busy or have unsaved work"
msgstr "Cualchi aplicazion e je impegnade opûr e à lavôrs no salvâts"
#: js/ui/endSessionDialog.js:327
msgid "Other users are logged in."
msgstr "Altris utents a son jentrâts."
#: js/ui/endSessionDialog.js:273
msgid "Other users are logged in"
msgstr "Altris utents a son jentrâts"
#. Translators: Remote here refers to a remote session, like a ssh login
#: js/ui/endSessionDialog.js:649
#: js/ui/endSessionDialog.js:588
#, javascript-format
msgid "%s (remote)"
msgstr "%s (rimot)"
#. Translators: Console here refers to a tty like a VT console
#: js/ui/endSessionDialog.js:652
#: js/ui/endSessionDialog.js:591
#, javascript-format
msgid "%s (console)"
msgstr "%s (locâl vie tastiere)"
@@ -1345,16 +1352,16 @@ msgid "Application wants to inhibit shortcuts"
msgstr "Une aplicazion e desidere inibî lis scurtis"
#. Translators: %s is a keyboard shortcut like "Super+x"
#: js/ui/inhibitShortcutsDialog.js:90
#: js/ui/inhibitShortcutsDialog.js:89
#, javascript-format
msgid "You can restore shortcuts by pressing %s."
msgstr "Si pues ripristinâ lis scurtis fracant %s."
#: js/ui/inhibitShortcutsDialog.js:96
#: js/ui/inhibitShortcutsDialog.js:95
msgid "Deny"
msgstr "Dinee"
#: js/ui/inhibitShortcutsDialog.js:103
#: js/ui/inhibitShortcutsDialog.js:102
msgid "Allow"
msgstr "Pemet"
@@ -1401,16 +1408,16 @@ msgstr ""
"Chest al disative la funzion tascj singui/tacadiçs, che al determine il mût "
"di lavorâ de tastiere."
#: js/ui/kbdA11yDialog.js:58
#: js/ui/kbdA11yDialog.js:57
msgid "Leave On"
msgstr "Lasse ativât"
#: js/ui/kbdA11yDialog.js:58 js/ui/status/bluetooth.js:135
#: js/ui/kbdA11yDialog.js:57 js/ui/status/bluetooth.js:135
#: js/ui/status/network.js:1285
msgid "Turn On"
msgstr "Impie"
#: js/ui/kbdA11yDialog.js:66 js/ui/status/bluetooth.js:135
#: js/ui/kbdA11yDialog.js:65 js/ui/status/bluetooth.js:135
#: js/ui/status/network.js:131 js/ui/status/network.js:315
#: js/ui/status/network.js:1285 js/ui/status/network.js:1397
#: js/ui/status/nightLight.js:41 js/ui/status/rfkill.js:81
@@ -1418,7 +1425,7 @@ msgstr "Impie"
msgid "Turn Off"
msgstr "Distude"
#: js/ui/kbdA11yDialog.js:66
#: js/ui/kbdA11yDialog.js:65
msgid "Leave Off"
msgstr "Lasse disativât"
@@ -1640,11 +1647,11 @@ msgstr "GNOME al à di blocâ il visôr"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: js/ui/screenShield.js:831 js/ui/screenShield.js:1303
#: js/ui/screenShield.js:830 js/ui/screenShield.js:1301
msgid "Unable to lock"
msgstr "Impussibil blocâ"
#: js/ui/screenShield.js:832 js/ui/screenShield.js:1304
#: js/ui/screenShield.js:831 js/ui/screenShield.js:1302
msgid "Lock was blocked by an application"
msgstr "Il bloc al è stât dineât di une aplicazion"
@@ -1680,24 +1687,24 @@ msgstr "Mostre Test"
msgid "Hide Text"
msgstr "Plate Test"
#: js/ui/shellEntry.js:161
#: js/ui/shellEntry.js:162
msgid "Caps lock is on."
msgstr "BlocMaiusc al è atîf."
#: js/ui/shellMountOperation.js:308
#: js/ui/shellMountOperation.js:305
msgid "Hidden Volume"
msgstr "Volum platât"
#: js/ui/shellMountOperation.js:311
#: js/ui/shellMountOperation.js:308
msgid "Windows System Volume"
msgstr "Volum di sisteme Windows"
#: js/ui/shellMountOperation.js:314
#: js/ui/shellMountOperation.js:311
msgid "Uses Keyfiles"
msgstr "Al dopre i File-clâf"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:320
#: js/ui/shellMountOperation.js:317
#, javascript-format
msgid ""
"To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead."
@@ -1705,36 +1712,36 @@ msgstr ""
"Par sblocâ un volum che al dopre i file-clâf dopre invezit il program di "
"utilitât <i>%s</i>."
#: js/ui/shellMountOperation.js:327
#: js/ui/shellMountOperation.js:324
msgid "PIM Number"
msgstr "Numar PIM"
#: js/ui/shellMountOperation.js:346
#: js/ui/shellMountOperation.js:343
msgid "The PIM must be a number or empty."
msgstr "Il PIM al scugne jessi un numar o vueit."
#: js/ui/shellMountOperation.js:357
#: js/ui/shellMountOperation.js:354
msgid "Password"
msgstr "Password"
#: js/ui/shellMountOperation.js:393
#: js/ui/shellMountOperation.js:390
msgid "Remember Password"
msgstr "Visâsi Password"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:417
#: js/ui/shellMountOperation.js:414
#, javascript-format
msgid "Open %s"
msgstr "Vierç %s"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:489
#: js/ui/shellMountOperation.js:486
#, javascript-format
msgid "Unable to start %s"
msgstr "Impussibil inviâ %s"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:491
#: js/ui/shellMountOperation.js:488
#, javascript-format
msgid "Couldnt find the %s application"
msgstr "Impussibil cjatâ la aplicazion %s"
@@ -1831,11 +1838,11 @@ msgstr "Clic secondari"
msgid "Dwell Click"
msgstr "Clic in polse"
#: js/ui/status/keyboard.js:818
#: js/ui/status/keyboard.js:825
msgid "Keyboard"
msgstr "Tastiere"
#: js/ui/status/keyboard.js:840
#: js/ui/status/keyboard.js:847
msgid "Show Keyboard Layout"
msgstr "Mostre la disposizion de tastiere"
@@ -1864,12 +1871,12 @@ msgid "Enable"
msgstr "Abilite"
#. Translators: %s is an application name
#: js/ui/status/location.js:357
#: js/ui/status/location.js:355
#, javascript-format
msgid "Give %s access to your location?"
msgstr "Permeti a %s di cognossi la tô posizion?"
#: js/ui/status/location.js:358
#: js/ui/status/location.js:361
msgid "Location access can be changed at any time from the privacy settings."
msgstr ""
"L'acès ae posizion al pues jessi cambiât cuant che tu vuelis su impostazions "
@@ -2250,11 +2257,11 @@ msgstr "Jentre come altri utent"
msgid "Unlock Window"
msgstr "Sbloche barcon"
#: js/ui/viewSelector.js:180
#: js/ui/viewSelector.js:181
msgid "Applications"
msgstr "Aplicazions"
#: js/ui/viewSelector.js:184
#: js/ui/viewSelector.js:185
msgid "Search"
msgstr "Cîr"
@@ -2263,22 +2270,22 @@ msgstr "Cîr"
msgid "“%s” is ready"
msgstr "“%s” al è pront"
#: js/ui/windowManager.js:57
#: js/ui/windowManager.js:54
msgid "Do you want to keep these display settings?"
msgstr "Vûstu tignî chestis impostazions di visôr?"
#. Translators: this and the following message should be limited in length,
#. to avoid ellipsizing the labels.
#.
#: js/ui/windowManager.js:71
#: js/ui/windowManager.js:68
msgid "Revert Settings"
msgstr "Ripristine impostazions"
#: js/ui/windowManager.js:74
#: js/ui/windowManager.js:71
msgid "Keep Changes"
msgstr "Ten lis modifichis"
#: js/ui/windowManager.js:92
#: js/ui/windowManager.js:89
#, javascript-format
msgid "Settings changes will revert in %d second"
msgid_plural "Settings changes will revert in %d seconds"
@@ -2289,7 +2296,7 @@ msgstr[1] ""
#. Translators: This represents the size of a window. The first number is
#. * the width of the window and the second is the height.
#: js/ui/windowManager.js:690
#: js/ui/windowManager.js:546
#, javascript-format
msgid "%d × %d"
msgstr "%d × %d"
@@ -2378,12 +2385,12 @@ msgstr "Dopre une modalitât specifiche, par esempli “gdm” pe videade di ac
msgid "List possible modes"
msgstr "Liste modalitâts pussibilis"
#: src/shell-app.c:265
#: src/shell-app.c:279
msgctxt "program"
msgid "Unknown"
msgstr "No cognossût"
#: src/shell-app.c:516
#: src/shell-app.c:530
#, c-format
msgid "Failed to launch “%s”"
msgstr "No soi rivât a eseguî '%s'"
@@ -2743,6 +2750,9 @@ msgstr[1] "%u jentradis"
msgid "System Sounds"
msgstr "Suns di sisteme"
#~ msgid "Rename"
#~ msgstr "Cambie non"
#~ msgid "Account Settings"
#~ msgstr "Impostazions account"

459
po/hr.po

File diff suppressed because it is too large Load Diff

275
po/id.po
View File

@@ -4,23 +4,23 @@
# Andika Triwidada <andika@gmail.com>, 2010-2014, 2017.
# Dirgita <dirgitadevina@yahoo.co.id>, 2011, 2012, 2014.
# Wibiharto <wibinem@yahoo.com>, 2011.
# Kukuh Syafaat <kukuhsyafaat@gnome.org>, 2017, 2018, 2019.
# Kukuh Syafaat <kukuhsyafaat@gnome.org>, 2017-2020.
# Sucipto <sucipto@pm.me>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2020-01-09 01:33+0000\n"
"PO-Revision-Date: 2020-01-13 17:07+0700\n"
"Last-Translator: Sucipto <sucipto@pm.me>\n"
"POT-Creation-Date: 2020-01-22 22:00+0000\n"
"PO-Revision-Date: 2020-01-23 16:31+0700\n"
"Last-Translator: Kukuh Syafaat <kukuhsyafaat@gnome.org>\n"
"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\n"
"Language: id\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural= n!=1;\n"
"X-Generator: Gtranslator 3.34.0\n"
"X-Generator: Poedit 2.2.4\n"
"X-DamnedLies-Scope: partial\n"
"X-Poedit-SourceCharset: UTF-8\n"
@@ -460,9 +460,9 @@ msgstr ""
"dipasang. Pastikan Anda masuk ke GNOME dan coba lagi."
#: js/gdm/authPrompt.js:174 js/ui/audioDeviceSelection.js:57
#: js/ui/components/networkAgent.js:130 js/ui/components/polkitAgent.js:139
#: js/ui/endSessionDialog.js:445 js/ui/extensionDownloader.js:190
#: js/ui/shellMountOperation.js:402 js/ui/shellMountOperation.js:412
#: js/ui/components/networkAgent.js:129 js/ui/components/polkitAgent.js:138
#: js/ui/endSessionDialog.js:374 js/ui/extensionDownloader.js:190
#: js/ui/shellMountOperation.js:399 js/ui/shellMountOperation.js:409
#: js/ui/status/network.js:910
msgid "Cancel"
msgstr "Batal"
@@ -471,7 +471,7 @@ msgstr "Batal"
msgid "Next"
msgstr "Selanjutnya"
#: js/gdm/authPrompt.js:237 js/ui/shellMountOperation.js:406
#: js/gdm/authPrompt.js:237 js/ui/shellMountOperation.js:403
#: js/ui/unlockDialog.js:44
msgid "Unlock"
msgstr "Buka Kunci"
@@ -499,8 +499,8 @@ msgstr "(cth., pengguna dari %s)"
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: js/gdm/loginDialog.js:899 js/ui/components/networkAgent.js:257
#: js/ui/components/networkAgent.js:280 js/ui/components/networkAgent.js:298
#: js/gdm/loginDialog.js:899 js/ui/components/networkAgent.js:256
#: js/ui/components/networkAgent.js:279 js/ui/components/networkAgent.js:297
msgid "Username: "
msgstr "Nama pengguna: "
@@ -740,56 +740,52 @@ msgstr ""
#. No support for non-modal system dialogs, so ignore the option
#. let modal = options['modal'] || true;
#: js/ui/accessDialog.js:39 js/ui/status/location.js:364
#: js/ui/accessDialog.js:39 js/ui/status/location.js:366
msgid "Deny Access"
msgstr "Tolak Akses"
#: js/ui/accessDialog.js:40 js/ui/status/location.js:367
#: js/ui/accessDialog.js:40 js/ui/status/location.js:369
msgid "Grant Access"
msgstr "Beri Akses"
#: js/ui/appDisplay.js:947
#: js/ui/appDisplay.js:904
msgid "Unnamed Folder"
msgstr "Folder Tanpa Nama"
#: js/ui/appDisplay.js:970
#: js/ui/appDisplay.js:927
msgid "Frequently used applications will appear here"
msgstr "Aplikasi yang sering dipakai akan muncul di sini"
#: js/ui/appDisplay.js:1105
#: js/ui/appDisplay.js:1062
msgid "Frequent"
msgstr "Sering"
#: js/ui/appDisplay.js:1112
#: js/ui/appDisplay.js:1069
msgid "All"
msgstr "Semua"
#: js/ui/appDisplay.js:1887
msgid "Rename"
msgstr "Ubah Nama"
#. Translators: This is the heading of a list of open windows
#: js/ui/appDisplay.js:2575 js/ui/panel.js:75
#: js/ui/appDisplay.js:2452 js/ui/panel.js:75
msgid "Open Windows"
msgstr "Buka Jendela"
#: js/ui/appDisplay.js:2595 js/ui/panel.js:82
#: js/ui/appDisplay.js:2472 js/ui/panel.js:82
msgid "New Window"
msgstr "Jendela Baru"
#: js/ui/appDisplay.js:2606
#: js/ui/appDisplay.js:2483
msgid "Launch using Dedicated Graphics Card"
msgstr "Luncurkan menggunakan Kartu Grafis Terdedikasi"
#: js/ui/appDisplay.js:2634 js/ui/dash.js:239
#: js/ui/appDisplay.js:2511 js/ui/dash.js:239
msgid "Remove from Favorites"
msgstr "Hapus dari Favorit"
#: js/ui/appDisplay.js:2640
#: js/ui/appDisplay.js:2517
msgid "Add to Favorites"
msgstr "Tambah ke Favorit"
#: js/ui/appDisplay.js:2650 js/ui/panel.js:93
#: js/ui/appDisplay.js:2527 js/ui/panel.js:93
msgid "Show Details"
msgstr "Tampilkan Rincian"
@@ -836,7 +832,7 @@ msgid "Settings"
msgstr "Pengaturan"
#. Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday).
#: js/ui/calendar.js:40
#: js/ui/calendar.js:41
msgctxt "calendar-no-work"
msgid "06"
msgstr "06"
@@ -846,43 +842,43 @@ msgstr "06"
#. * NOTE: These grid abbreviations are always shown together
#. * and in order, e.g. "S M T W T F S".
#.
#: js/ui/calendar.js:69
#: js/ui/calendar.js:70
msgctxt "grid sunday"
msgid "S"
msgstr "M"
#. Translators: Calendar grid abbreviation for Monday
#: js/ui/calendar.js:71
#: js/ui/calendar.js:72
msgctxt "grid monday"
msgid "M"
msgstr "S"
#. Translators: Calendar grid abbreviation for Tuesday
#: js/ui/calendar.js:73
#: js/ui/calendar.js:74
msgctxt "grid tuesday"
msgid "T"
msgstr "S"
#. Translators: Calendar grid abbreviation for Wednesday
#: js/ui/calendar.js:75
#: js/ui/calendar.js:76
msgctxt "grid wednesday"
msgid "W"
msgstr "R"
#. Translators: Calendar grid abbreviation for Thursday
#: js/ui/calendar.js:77
#: js/ui/calendar.js:78
msgctxt "grid thursday"
msgid "T"
msgstr "K"
#. Translators: Calendar grid abbreviation for Friday
#: js/ui/calendar.js:79
#: js/ui/calendar.js:80
msgctxt "grid friday"
msgid "F"
msgstr "J"
#. Translators: Calendar grid abbreviation for Saturday
#: js/ui/calendar.js:81
#: js/ui/calendar.js:82
msgctxt "grid saturday"
msgid "S"
msgstr "S"
@@ -893,7 +889,7 @@ msgstr "S"
#. * "%OB" is the new format specifier introduced in glibc 2.27,
#. * in most cases you should not change it.
#.
#: js/ui/calendar.js:370
#: js/ui/calendar.js:371
msgid "%OB"
msgstr "%OB"
@@ -906,55 +902,61 @@ msgstr "%OB"
#. * in most cases you should not use the old "%B" here unless you
#. * absolutely know what you are doing.
#.
#: js/ui/calendar.js:380
#: js/ui/calendar.js:381
msgid "%OB %Y"
msgstr "%OB %Y"
#: js/ui/calendar.js:439
#: js/ui/calendar.js:440
msgid "Previous month"
msgstr "Bulan sebelumnya"
#: js/ui/calendar.js:454
#: js/ui/calendar.js:455
msgid "Next month"
msgstr "Bulan selanjutnya"
#: js/ui/calendar.js:604
#: js/ui/calendar.js:605
#, no-javascript-format
msgctxt "date day number format"
msgid "%d"
msgstr "%d"
#: js/ui/calendar.js:660
#: js/ui/calendar.js:661
msgid "Week %V"
msgstr "Minggu %V"
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
#.
#: js/ui/calendar.js:729
#: js/ui/calendar.js:730
msgctxt "event list time"
msgid "All Day"
msgstr "Sepanjang Hari"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: js/ui/calendar.js:867
msgctxt "calendar heading"
msgid "%A, %B %-d"
msgstr "%A, %d %B"
#: js/ui/calendar.js:871
#. Translators: Shown on calendar heading when selected day occurs on different year
#: js/ui/calendar.js:870
msgctxt "calendar heading"
msgid "%A, %B %-d, %Y"
msgstr "%A, %d %B %Y"
#: js/ui/calendar.js:1097
#: js/ui/calendar.js:1096
msgid "No Notifications"
msgstr "Tak Ada Pemberitahuan"
#: js/ui/calendar.js:1100
#: js/ui/calendar.js:1099
msgid "No Events"
msgstr "Tak Ada Kejadian"
#: js/ui/calendar.js:1132
#: js/ui/calendar.js:1153
msgid "Do Not Disturb"
msgstr "Jangan Ganggu"
#: js/ui/calendar.js:1167
msgid "Clear"
msgstr "Bersihkan"
@@ -972,11 +974,11 @@ msgstr ""
"Anda dapat memilih untuk menunggu sebentar untuk melanjutkan atau memaksa "
"aplikasi keluar."
#: js/ui/closeDialog.js:71
#: js/ui/closeDialog.js:70
msgid "Force Quit"
msgstr "Tutup Paksa"
#: js/ui/closeDialog.js:74
#: js/ui/closeDialog.js:73
msgid "Wait"
msgstr "Tunggu"
@@ -1001,55 +1003,55 @@ msgstr "Versi udisks yang dipasang tidak mendukung pengaturan PIM"
msgid "Open with %s"
msgstr "Buka dengan %s"
#: js/ui/components/keyring.js:71 js/ui/components/polkitAgent.js:279
#: js/ui/components/keyring.js:70 js/ui/components/polkitAgent.js:278
msgid "Password:"
msgstr "Sandi:"
#: js/ui/components/keyring.js:105
#: js/ui/components/keyring.js:104
msgid "Type again:"
msgstr "Ketik lagi:"
#: js/ui/components/networkAgent.js:116
#: js/ui/components/networkAgent.js:115
msgid ""
"Alternatively you can connect by pushing the “WPS” button on your router."
msgstr ""
"Sebagai alternatif Anda dapat terhubung dengan menekan tombol \"WPS\" pada "
"router Anda."
#: js/ui/components/networkAgent.js:124 js/ui/status/network.js:223
#: js/ui/components/networkAgent.js:123 js/ui/status/network.js:223
#: js/ui/status/network.js:314 js/ui/status/network.js:913
msgid "Connect"
msgstr "Sambung"
#. Cisco LEAP
#: js/ui/components/networkAgent.js:225 js/ui/components/networkAgent.js:237
#: js/ui/components/networkAgent.js:261 js/ui/components/networkAgent.js:282
#: js/ui/components/networkAgent.js:302 js/ui/components/networkAgent.js:312
#: js/ui/components/networkAgent.js:224 js/ui/components/networkAgent.js:236
#: js/ui/components/networkAgent.js:260 js/ui/components/networkAgent.js:281
#: js/ui/components/networkAgent.js:301 js/ui/components/networkAgent.js:311
msgid "Password: "
msgstr "Sandi: "
#. static WEP
#: js/ui/components/networkAgent.js:230
#: js/ui/components/networkAgent.js:229
msgid "Key: "
msgstr "Tombol: "
#: js/ui/components/networkAgent.js:265 js/ui/components/networkAgent.js:288
#: js/ui/components/networkAgent.js:264 js/ui/components/networkAgent.js:287
msgid "Private key password: "
msgstr "Sandi kunci privat: "
#: js/ui/components/networkAgent.js:286
#: js/ui/components/networkAgent.js:285
msgid "Identity: "
msgstr "Identitas: "
#: js/ui/components/networkAgent.js:300
#: js/ui/components/networkAgent.js:299
msgid "Service: "
msgstr "Layanan: "
#: js/ui/components/networkAgent.js:329 js/ui/components/networkAgent.js:704
#: js/ui/components/networkAgent.js:328 js/ui/components/networkAgent.js:703
msgid "Authentication required by wireless network"
msgstr "Autentikasi diperlukan oleh jaringan nirkabel"
#: js/ui/components/networkAgent.js:330 js/ui/components/networkAgent.js:705
#: js/ui/components/networkAgent.js:329 js/ui/components/networkAgent.js:704
#, javascript-format
msgid ""
"Passwords or encryption keys are required to access the wireless network "
@@ -1058,58 +1060,58 @@ msgstr ""
"Sandi atau kunci enkripsi diperlukan untuk mengakses jaringan nirkabel \"%s"
"\"."
#: js/ui/components/networkAgent.js:334 js/ui/components/networkAgent.js:709
#: js/ui/components/networkAgent.js:333 js/ui/components/networkAgent.js:708
msgid "Wired 802.1X authentication"
msgstr "Autentikasi 802.1X kabel"
#: js/ui/components/networkAgent.js:336
#: js/ui/components/networkAgent.js:335
msgid "Network name: "
msgstr "Nama jaringan: "
#: js/ui/components/networkAgent.js:341 js/ui/components/networkAgent.js:713
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:712
msgid "DSL authentication"
msgstr "Autentikasi DSL"
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:718
#: js/ui/components/networkAgent.js:347 js/ui/components/networkAgent.js:717
msgid "PIN code required"
msgstr "Perlu kode PIN"
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:719
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:718
msgid "PIN code is needed for the mobile broadband device"
msgstr "Kode PIN diperlukan untuk perangkat data seluler"
#: js/ui/components/networkAgent.js:350
#: js/ui/components/networkAgent.js:349
msgid "PIN: "
msgstr "PIN: "
#: js/ui/components/networkAgent.js:357 js/ui/components/networkAgent.js:725
#: js/ui/components/networkAgent.js:356 js/ui/components/networkAgent.js:724
msgid "Mobile broadband network password"
msgstr "Sandi jaringan data seluler"
#: js/ui/components/networkAgent.js:358 js/ui/components/networkAgent.js:710
#: js/ui/components/networkAgent.js:714 js/ui/components/networkAgent.js:726
#: js/ui/components/networkAgent.js:730
#: js/ui/components/networkAgent.js:357 js/ui/components/networkAgent.js:709
#: js/ui/components/networkAgent.js:713 js/ui/components/networkAgent.js:725
#: js/ui/components/networkAgent.js:729
#, javascript-format
msgid "A password is required to connect to “%s”."
msgstr "Perlu suatu sandi untuk menyambung ke \"%s\"."
#: js/ui/components/networkAgent.js:693 js/ui/status/network.js:1688
#: js/ui/components/networkAgent.js:692 js/ui/status/network.js:1688
msgid "Network Manager"
msgstr "Manajer Jaringan"
#: js/ui/components/networkAgent.js:729
#: js/ui/components/networkAgent.js:728
msgid "VPN password"
msgstr "Sandi VPN"
#: js/ui/components/polkitAgent.js:42
#: js/ui/components/polkitAgent.js:41
msgid "Authentication Required"
msgstr "Diperlukan Autentikasi"
#: js/ui/components/polkitAgent.js:82
#: js/ui/components/polkitAgent.js:81
msgid "Administrator"
msgstr "Administrator"
#: js/ui/components/polkitAgent.js:142
#: js/ui/components/polkitAgent.js:141
msgid "Authenticate"
msgstr "Autentikasi"
@@ -1117,7 +1119,7 @@ msgstr "Autentikasi"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: js/ui/components/polkitAgent.js:260 js/ui/shellMountOperation.js:386
#: js/ui/components/polkitAgent.js:259 js/ui/shellMountOperation.js:383
msgid "Sorry, that didnt work. Please try again."
msgstr "Maaf, tidak berhasil. Silakan coba lagi."
@@ -1171,19 +1173,19 @@ msgstr "Jam Dunia"
msgid "Weather"
msgstr "Cuaca"
#: js/ui/dateMenu.js:389
#: js/ui/dateMenu.js:391
msgid "Select a location…"
msgstr "Pilih lokasi…"
#: js/ui/dateMenu.js:402
#: js/ui/dateMenu.js:404
msgid "Loading…"
msgstr "Memuat…"
#: js/ui/dateMenu.js:412
#: js/ui/dateMenu.js:414
msgid "Go online for weather information"
msgstr "Pergi daring untuk informasi cuaca"
#: js/ui/dateMenu.js:414
#: js/ui/dateMenu.js:416
msgid "Weather information is currently unavailable"
msgstr "Informasi cuaca saat ini tidak tersedia"
@@ -1217,56 +1219,56 @@ msgctxt "button"
msgid "Log Out"
msgstr "Keluar"
#: js/ui/endSessionDialog.js:57
#: js/ui/endSessionDialog.js:56
msgctxt "title"
msgid "Power Off"
msgstr "Matikan"
#: js/ui/endSessionDialog.js:58
#: js/ui/endSessionDialog.js:57
msgctxt "title"
msgid "Install Updates & Power Off"
msgstr "Pasang Pemutakhiran & Matikan"
#: js/ui/endSessionDialog.js:60
#: js/ui/endSessionDialog.js:59
#, javascript-format
msgid "The system will power off automatically in %d second."
msgid_plural "The system will power off automatically in %d seconds."
msgstr[0] "Sistem ini akan otomatis dimatikan dalam %d detik."
msgstr[1] "Sistem ini akan otomatis dimatikan dalam %d detik."
#: js/ui/endSessionDialog.js:64
#: js/ui/endSessionDialog.js:63
msgctxt "checkbox"
msgid "Install pending software updates"
msgstr "Pasang pemutakhiran perangkat lunak yang tertunda"
#: js/ui/endSessionDialog.js:67 js/ui/endSessionDialog.js:84
#: js/ui/endSessionDialog.js:66 js/ui/endSessionDialog.js:82
msgctxt "button"
msgid "Restart"
msgstr "Nyalakan Ulang"
#: js/ui/endSessionDialog.js:69
#: js/ui/endSessionDialog.js:68
msgctxt "button"
msgid "Power Off"
msgstr "Matikan"
#: js/ui/endSessionDialog.js:76
#: js/ui/endSessionDialog.js:74
msgctxt "title"
msgid "Restart"
msgstr "Nyalakan Ulang"
#: js/ui/endSessionDialog.js:78
#: js/ui/endSessionDialog.js:76
#, javascript-format
msgid "The system will restart automatically in %d second."
msgid_plural "The system will restart automatically in %d seconds."
msgstr[0] "Sistem ini akan otomatis dimulai ulang dalam %d detik."
msgstr[1] "Sistem ini akan otomatis dimulai ulang dalam %d detik."
#: js/ui/endSessionDialog.js:92
#: js/ui/endSessionDialog.js:89
msgctxt "title"
msgid "Restart & Install Updates"
msgstr "Start Ulang & Pasang Pemutakhiran"
#: js/ui/endSessionDialog.js:94
#: js/ui/endSessionDialog.js:91
#, javascript-format
msgid "The system will automatically restart and install updates in %d second."
msgid_plural ""
@@ -1278,22 +1280,22 @@ msgstr[1] ""
"Sistem ini akan otomatis dimulai ulang dan memasang pemutakhiran dalam %d "
"detik."
#: js/ui/endSessionDialog.js:100 js/ui/endSessionDialog.js:120
#: js/ui/endSessionDialog.js:97 js/ui/endSessionDialog.js:116
msgctxt "button"
msgid "Restart &amp; Install"
msgstr "Nyalakan Ulang &amp; Pasang"
#: js/ui/endSessionDialog.js:101
#: js/ui/endSessionDialog.js:98
msgctxt "button"
msgid "Install &amp; Power Off"
msgstr "Pasang &amp; Matikan"
#: js/ui/endSessionDialog.js:102
#: js/ui/endSessionDialog.js:99
msgctxt "checkbox"
msgid "Power off after updates are installed"
msgstr "Matikan daya setelah pemutakhiran dipasang"
#: js/ui/endSessionDialog.js:110
#: js/ui/endSessionDialog.js:106
msgctxt "title"
msgid "Restart & Install Upgrade"
msgstr "Start Ulang & Pasang Peningkatan"
@@ -1301,7 +1303,7 @@ msgstr "Start Ulang & Pasang Peningkatan"
#. Translators: This is the text displayed for system upgrades in the
#. shut down dialog. First %s gets replaced with the distro name and
#. second %s with the distro version to upgrade to
#: js/ui/endSessionDialog.js:115
#: js/ui/endSessionDialog.js:111
#, javascript-format
msgid ""
"%s %s will be installed after restart. Upgrade installation can take a long "
@@ -1311,27 +1313,27 @@ msgstr ""
"waktu lama: pastikan bahwa Anda telah melakukan back up dan komputer "
"tersambung ke listrik."
#: js/ui/endSessionDialog.js:301
msgid "Running on battery power: please plug in before installing updates."
#: js/ui/endSessionDialog.js:259
msgid "Running on battery power: Please plug in before installing updates."
msgstr ""
"Berjalan memakai daya baterai: harap tancapkan sebelum memasang pemutakhiran."
"Berjalan memakai daya baterai: Harap tancapkan sebelum memasang pemutakhiran."
#: js/ui/endSessionDialog.js:320
msgid "Some applications are busy or have unsaved work."
msgstr "Beberapa aplikasi sedang sibuk atau belum disimpan perubahannya."
#: js/ui/endSessionDialog.js:268
msgid "Some applications are busy or have unsaved work"
msgstr "Beberapa aplikasi sedang sibuk atau belum disimpan perubahannya"
#: js/ui/endSessionDialog.js:327
msgid "Other users are logged in."
msgstr "Pengguna lain sedang log masuk."
#: js/ui/endSessionDialog.js:273
msgid "Other users are logged in"
msgstr "Pengguna lain sedang log masuk"
#. Translators: Remote here refers to a remote session, like a ssh login
#: js/ui/endSessionDialog.js:649
#: js/ui/endSessionDialog.js:588
#, javascript-format
msgid "%s (remote)"
msgstr "%s (jarak jauh)"
#. Translators: Console here refers to a tty like a VT console
#: js/ui/endSessionDialog.js:652
#: js/ui/endSessionDialog.js:591
#, javascript-format
msgid "%s (console)"
msgstr "%s (konsol)"
@@ -1355,16 +1357,16 @@ msgid "Application wants to inhibit shortcuts"
msgstr "Aplikasi ingin mencegah pintasan"
#. Translators: %s is a keyboard shortcut like "Super+x"
#: js/ui/inhibitShortcutsDialog.js:90
#: js/ui/inhibitShortcutsDialog.js:89
#, javascript-format
msgid "You can restore shortcuts by pressing %s."
msgstr "Anda dapat memulihkan pintasan dengan menekan %s."
#: js/ui/inhibitShortcutsDialog.js:96
#: js/ui/inhibitShortcutsDialog.js:95
msgid "Deny"
msgstr "Tolak"
#: js/ui/inhibitShortcutsDialog.js:103
#: js/ui/inhibitShortcutsDialog.js:102
msgid "Allow"
msgstr "Izinkan"
@@ -1410,16 +1412,16 @@ msgstr ""
"berturut-turut. Ini mematikan fitur Tombol Lengket, yang mempengaruhi cara "
"kerja papan tik Anda."
#: js/ui/kbdA11yDialog.js:58
#: js/ui/kbdA11yDialog.js:57
msgid "Leave On"
msgstr "Biarkan Menyala"
#: js/ui/kbdA11yDialog.js:58 js/ui/status/bluetooth.js:135
#: js/ui/kbdA11yDialog.js:57 js/ui/status/bluetooth.js:135
#: js/ui/status/network.js:1285
msgid "Turn On"
msgstr "Nyalakan"
#: js/ui/kbdA11yDialog.js:66 js/ui/status/bluetooth.js:135
#: js/ui/kbdA11yDialog.js:65 js/ui/status/bluetooth.js:135
#: js/ui/status/network.js:131 js/ui/status/network.js:315
#: js/ui/status/network.js:1285 js/ui/status/network.js:1397
#: js/ui/status/nightLight.js:41 js/ui/status/rfkill.js:81
@@ -1427,7 +1429,7 @@ msgstr "Nyalakan"
msgid "Turn Off"
msgstr "Matikan"
#: js/ui/kbdA11yDialog.js:66
#: js/ui/kbdA11yDialog.js:65
msgid "Leave Off"
msgstr "Biarkan Mati"
@@ -1647,11 +1649,11 @@ msgstr "GNOME perlu mengunci layar"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: js/ui/screenShield.js:831 js/ui/screenShield.js:1303
#: js/ui/screenShield.js:830 js/ui/screenShield.js:1301
msgid "Unable to lock"
msgstr "Tak bisa mengunci"
#: js/ui/screenShield.js:832 js/ui/screenShield.js:1304
#: js/ui/screenShield.js:831 js/ui/screenShield.js:1302
msgid "Lock was blocked by an application"
msgstr "Kunci diblokir oleh suatu aplikasi"
@@ -1686,24 +1688,24 @@ msgstr "Tampilkan Teks"
msgid "Hide Text"
msgstr "Sembunyikan Teks"
#: js/ui/shellEntry.js:161
#: js/ui/shellEntry.js:162
msgid "Caps lock is on."
msgstr "Caps lock menyala."
#: js/ui/shellMountOperation.js:308
#: js/ui/shellMountOperation.js:305
msgid "Hidden Volume"
msgstr "Volume Tersembunyi"
#: js/ui/shellMountOperation.js:311
#: js/ui/shellMountOperation.js:308
msgid "Windows System Volume"
msgstr "Volume Sistem Windows"
#: js/ui/shellMountOperation.js:314
#: js/ui/shellMountOperation.js:311
msgid "Uses Keyfiles"
msgstr "Gunakan Berkas Kunci"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:320
#: js/ui/shellMountOperation.js:317
#, javascript-format
msgid ""
"To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead."
@@ -1711,36 +1713,36 @@ msgstr ""
"Untuk membuka kunci volume yang menggunakan berkas kunci, gunakan utilitas "
"<i>%s</i>."
#: js/ui/shellMountOperation.js:327
#: js/ui/shellMountOperation.js:324
msgid "PIM Number"
msgstr "Nomor PIM"
#: js/ui/shellMountOperation.js:346
#: js/ui/shellMountOperation.js:343
msgid "The PIM must be a number or empty."
msgstr "PIM harus berupa angka atau kosong."
#: js/ui/shellMountOperation.js:357
#: js/ui/shellMountOperation.js:354
msgid "Password"
msgstr "Sandi"
#: js/ui/shellMountOperation.js:393
#: js/ui/shellMountOperation.js:390
msgid "Remember Password"
msgstr "Ingat Sandi"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:417
#: js/ui/shellMountOperation.js:414
#, javascript-format
msgid "Open %s"
msgstr "Buka %s"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:489
#: js/ui/shellMountOperation.js:486
#, javascript-format
msgid "Unable to start %s"
msgstr "Tak bisa memulai %s"
#. Translators: %s is the Disks application
#: js/ui/shellMountOperation.js:491
#: js/ui/shellMountOperation.js:488
#, javascript-format
msgid "Couldnt find the %s application"
msgstr "Tak bisa menemukan aplikasi %s"
@@ -1870,12 +1872,12 @@ msgid "Enable"
msgstr "Fungsikan"
#. Translators: %s is an application name
#: js/ui/status/location.js:357
#: js/ui/status/location.js:355
#, javascript-format
msgid "Give %s access to your location?"
msgstr "Beri %s akses ke lokasi Anda?"
#: js/ui/status/location.js:358
#: js/ui/status/location.js:361
msgid "Location access can be changed at any time from the privacy settings."
msgstr "Akses lokasi dapat diubah setiap saat dari pengaturan privasi."
@@ -2266,22 +2268,22 @@ msgstr "Cari"
msgid "“%s” is ready"
msgstr "“%s” siap"
#: js/ui/windowManager.js:57
#: js/ui/windowManager.js:54
msgid "Do you want to keep these display settings?"
msgstr "Apakah Anda ingin mempertahankan pengaturan tampilan ini?"
#. Translators: this and the following message should be limited in length,
#. to avoid ellipsizing the labels.
#.
#: js/ui/windowManager.js:71
#: js/ui/windowManager.js:68
msgid "Revert Settings"
msgstr "Balikkan Tatanan"
#: js/ui/windowManager.js:74
#: js/ui/windowManager.js:71
msgid "Keep Changes"
msgstr "Simpan Perubahan"
#: js/ui/windowManager.js:92
#: js/ui/windowManager.js:89
#, javascript-format
msgid "Settings changes will revert in %d second"
msgid_plural "Settings changes will revert in %d seconds"
@@ -2290,7 +2292,7 @@ msgstr[1] "Perubahan tatanan akan dikembalikan dalam %d detik"
#. Translators: This represents the size of a window. The first number is
#. * the width of the window and the second is the height.
#: js/ui/windowManager.js:690
#: js/ui/windowManager.js:546
#, javascript-format
msgid "%d × %d"
msgstr "%d × %d"
@@ -2742,3 +2744,6 @@ msgstr[1] "%u Masukan"
#: subprojects/gvc/gvc-mixer-control.c:2766
msgid "System Sounds"
msgstr "Suara Sistem"
#~ msgid "Rename"
#~ msgstr "Ubah Nama"

1404
po/ja.po

File diff suppressed because it is too large Load Diff

1512
po/lt.po

File diff suppressed because it is too large Load Diff

1190
po/mjw.po

File diff suppressed because it is too large Load Diff

3708
po/ms.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

718
po/sk.po

File diff suppressed because it is too large Load Diff

1521
po/sv.po

File diff suppressed because it is too large Load Diff

1915
po/uk.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -24,52 +24,6 @@ def show_version(option, opt_str, value, parser):
print("GNOME Shell Performance Test @VERSION@")
sys.exit()
def wait_for_dbus_name(wait_name):
loop = GLib.MainLoop()
def on_name_appeared(connection, name, new_owner, *args):
if not (name == wait_name and new_owner != ''):
return
loop.quit()
return
watch_id = Gio.bus_watch_name(Gio.BusType.SESSION,
wait_name,
Gio.BusNameWatcherFlags.NONE,
on_name_appeared,
None)
def on_timeout():
print("\nFailed to start %s: timed out" % (wait_name,))
sys.exit(1)
GLib.timeout_add_seconds(7, on_timeout)
loop.run()
Gio.bus_unwatch_name(watch_id)
PERF_HELPER_NAME = "org.gnome.Shell.PerfHelper"
PERF_HELPER_IFACE = "org.gnome.Shell.PerfHelper"
PERF_HELPER_PATH = "/org/gnome/Shell/PerfHelper"
def start_perf_helper():
self_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
perf_helper_path = "@libexecdir@/gnome-shell-perf-helper"
subprocess.Popen([perf_helper_path])
wait_for_dbus_name (PERF_HELPER_NAME)
def stop_perf_helper():
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
proxy = Gio.DBusProxy.new_sync(bus,
Gio.DBusProxyFlags.NONE,
None,
PERF_HELPER_NAME,
PERF_HELPER_PATH,
PERF_HELPER_IFACE,
None)
proxy.Exit()
def start_shell(perf_output=None):
# Set up environment
env = dict(os.environ)
@@ -91,6 +45,13 @@ def start_shell(perf_output=None):
if options.replace:
args.append('--replace')
if options.wayland or options.nested:
args.append('--wayland')
if options.nested:
args.append('--nested')
else:
args.append('--display-server')
return subprocess.Popen(args, env=env)
def run_shell(perf_output=None):
@@ -204,8 +165,6 @@ def run_performance_test():
logs = []
metric_summaries = {}
start_perf_helper()
for i in range(0, iters):
# We create an empty temporary file that the shell will overwrite
# with the contents.
@@ -217,14 +176,12 @@ def run_performance_test():
try:
normal_exit = run_shell(perf_output=output_file)
except:
stop_perf_helper()
raise
finally:
if not normal_exit:
os.remove(output_file)
if not normal_exit:
stop_perf_helper()
return False
try:
@@ -232,7 +189,6 @@ def run_performance_test():
output = json.load(f)
f.close()
except:
stop_perf_helper()
raise
finally:
os.remove(output_file)
@@ -260,8 +216,6 @@ def run_performance_test():
logs.append(output['log'])
stop_perf_helper()
if options.perf_output or options.perf_upload:
# Write a complete report, formatted as JSON. The Javascript/C code that
# generates the individual reports we are summarizing here is very careful
@@ -337,6 +291,10 @@ parser.add_option("", "--version", action="callback", callback=show_version,
parser.add_option("-r", "--replace", action="store_true",
help="Replace the running window manager")
parser.add_option("-w", "--wayland", action="store_true",
help="Run as a Wayland compositor")
parser.add_option("-n", "--nested", action="store_true",
help="Run as a Wayland nested compositor")
options, args = parser.parse_args()

View File

@@ -186,7 +186,7 @@ window_backed_app_get_icon (ShellApp *app,
{
MetaWindow *window = NULL;
StWidget *widget;
gint scale;
int scale, scaled_size;
ShellGlobal *global;
StThemeContext *context;
@@ -194,7 +194,7 @@ window_backed_app_get_icon (ShellApp *app,
context = st_theme_context_get_for_stage (shell_global_get_stage (global));
g_object_get (context, "scale-factor", &scale, NULL);
size *= scale;
scaled_size = size * scale;
/* During a state transition from running to not-running for
* window-backend apps, it's possible we get a request for the icon.
@@ -208,14 +208,28 @@ window_backed_app_get_icon (ShellApp *app,
ClutterActor *actor;
actor = clutter_actor_new ();
g_object_set (actor, "opacity", 0, "width", (float) size, "height", (float) size, NULL);
g_object_set (actor,
"opacity", 0,
"width", (float) scaled_size,
"height", (float) scaled_size,
NULL);
return actor;
}
widget = st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
G_OBJECT (window),
"icon",
size);
if (meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_X11)
{
widget = st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
G_OBJECT (window),
"icon",
scaled_size);
}
else
{
widget = g_object_new (ST_TYPE_ICON,
"icon-size", size,
"icon-name", "application-x-executable",
NULL);
}
st_widget_add_style_class_name (widget, "fallback-app-icon");
return CLUTTER_ACTOR (widget);

View File

@@ -1333,9 +1333,12 @@ shell_global_sync_pointer (ShellGlobal *global)
int x, y;
ClutterModifierType mods;
ClutterMotionEvent event;
ClutterSeat *seat;
shell_global_get_pointer (global, &x, &y, &mods);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
event.type = CLUTTER_MOTION;
event.time = shell_global_get_current_time (global);
event.flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
@@ -1344,8 +1347,7 @@ shell_global_sync_pointer (ShellGlobal *global)
event.y = y;
event.modifier_state = mods;
event.axes = NULL;
event.device = clutter_device_manager_get_device (clutter_device_manager_get_default (),
META_VIRTUAL_CORE_POINTER_ID);
event.device = clutter_seat_get_pointer (seat);
/* Leaving event.source NULL will force clutter to look it up, which
* will generate enter/leave events as a side effect, if they are

View File

@@ -146,7 +146,7 @@ G_DEFINE_TYPE(ShellRecorder, shell_recorder, G_TYPE_OBJECT);
/* The default pipeline.
*/
#define DEFAULT_PIPELINE "vp9enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux"
#define DEFAULT_PIPELINE "vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux"
/* If we can find the amount of memory on the machine, we use half
* of that for memory_target, otherwise, we use this value, in kB.
@@ -1467,7 +1467,7 @@ shell_recorder_set_draw_cursor (ShellRecorder *recorder,
* might be used to send the output to an icecast server
* via shout2send or similar.
*
* The default value is 'vp9enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
* The default value is 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
*/
void
shell_recorder_set_pipeline (ShellRecorder *recorder,

View File

@@ -27,6 +27,7 @@ st_headers = [
'st-theme-context.h',
'st-theme-node.h',
'st-types.h',
'st-viewport.h',
'st-widget.h',
'st-widget-accessible.h'
]
@@ -140,6 +141,7 @@ st_sources = [
'st-theme-node.c',
'st-theme-node-drawing.c',
'st-theme-node-transition.c',
'st-viewport.c',
'st-widget.c'
]

View File

@@ -57,16 +57,12 @@
static void st_box_container_iface_init (ClutterContainerIface *iface);
static void st_box_scrollable_interface_init (StScrollableInterface *iface);
enum {
PROP_0,
PROP_VERTICAL,
PROP_PACK_START,
PROP_HADJUST,
PROP_VADJUST
};
struct _StBoxLayoutPrivate
@@ -75,104 +71,10 @@ struct _StBoxLayoutPrivate
StAdjustment *vadjustment;
};
G_DEFINE_TYPE_WITH_CODE (StBoxLayout, st_box_layout, ST_TYPE_WIDGET,
G_DEFINE_TYPE_WITH_CODE (StBoxLayout, st_box_layout, ST_TYPE_VIEWPORT,
G_ADD_PRIVATE (StBoxLayout)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
st_box_container_iface_init)
G_IMPLEMENT_INTERFACE (ST_TYPE_SCROLLABLE,
st_box_scrollable_interface_init));
/*
* StScrollable Interface Implementation
*/
static void
adjustment_value_notify_cb (StAdjustment *adjustment,
GParamSpec *pspec,
StBoxLayout *box)
{
clutter_actor_queue_relayout (CLUTTER_ACTOR (box));
}
static void
scrollable_set_adjustments (StScrollable *scrollable,
StAdjustment *hadjustment,
StAdjustment *vadjustment)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (scrollable)->priv;
g_object_freeze_notify (G_OBJECT (scrollable));
if (hadjustment != priv->hadjustment)
{
if (priv->hadjustment)
{
g_signal_handlers_disconnect_by_func (priv->hadjustment,
adjustment_value_notify_cb,
scrollable);
g_object_unref (priv->hadjustment);
}
if (hadjustment)
{
g_object_ref (hadjustment);
g_signal_connect (hadjustment, "notify::value",
G_CALLBACK (adjustment_value_notify_cb),
scrollable);
}
priv->hadjustment = hadjustment;
g_object_notify (G_OBJECT (scrollable), "hadjustment");
}
if (vadjustment != priv->vadjustment)
{
if (priv->vadjustment)
{
g_signal_handlers_disconnect_by_func (priv->vadjustment,
adjustment_value_notify_cb,
scrollable);
g_object_unref (priv->vadjustment);
}
if (vadjustment)
{
g_object_ref (vadjustment);
g_signal_connect (vadjustment, "notify::value",
G_CALLBACK (adjustment_value_notify_cb),
scrollable);
}
priv->vadjustment = vadjustment;
g_object_notify (G_OBJECT (scrollable), "vadjustment");
}
g_object_thaw_notify (G_OBJECT (scrollable));
}
static void
scrollable_get_adjustments (StScrollable *scrollable,
StAdjustment **hadjustment,
StAdjustment **vadjustment)
{
StBoxLayoutPrivate *priv;
priv = (ST_BOX_LAYOUT (scrollable))->priv;
if (hadjustment)
*hadjustment = priv->hadjustment;
if (vadjustment)
*vadjustment = priv->vadjustment;
}
static void
st_box_scrollable_interface_init (StScrollableInterface *iface)
{
iface->set_adjustments = scrollable_set_adjustments;
iface->get_adjustments = scrollable_get_adjustments;
}
st_box_container_iface_init));
static void
st_box_container_iface_init (ClutterContainerIface *iface)
@@ -188,7 +90,6 @@ st_box_layout_get_property (GObject *object,
GParamSpec *pspec)
{
ClutterLayoutManager *layout;
StAdjustment *adjustment;
ClutterOrientation orientation;
switch (property_id)
@@ -204,16 +105,6 @@ st_box_layout_get_property (GObject *object,
g_value_set_boolean (value, clutter_box_layout_get_pack_start (CLUTTER_BOX_LAYOUT (layout)));
break;
case PROP_HADJUST:
scrollable_get_adjustments (ST_SCROLLABLE (object), &adjustment, NULL);
g_value_set_object (value, adjustment);
break;
case PROP_VADJUST:
scrollable_get_adjustments (ST_SCROLLABLE (object), NULL, &adjustment);
g_value_set_object (value, adjustment);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -237,343 +128,11 @@ st_box_layout_set_property (GObject *object,
st_box_layout_set_pack_start (box, g_value_get_boolean (value));
break;
case PROP_HADJUST:
scrollable_set_adjustments (ST_SCROLLABLE (object),
g_value_get_object (value),
box->priv->vadjustment);
break;
case PROP_VADJUST:
scrollable_set_adjustments (ST_SCROLLABLE (object),
box->priv->hadjustment,
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_box_layout_dispose (GObject *object)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (object)->priv;
if (priv->hadjustment)
{
g_object_unref (priv->hadjustment);
priv->hadjustment = NULL;
}
if (priv->vadjustment)
{
g_object_unref (priv->vadjustment);
priv->vadjustment = NULL;
}
G_OBJECT_CLASS (st_box_layout_parent_class)->dispose (object);
}
static void
st_box_layout_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterLayoutManager *layout = clutter_actor_get_layout_manager (actor);
ClutterActorBox viewport_content_box;
ClutterActorBox content_box;
gfloat avail_width, avail_height, min_width, natural_width, min_height, natural_height;
st_theme_node_get_content_box (theme_node, box, &viewport_content_box);
clutter_actor_box_get_size (&viewport_content_box, &avail_width, &avail_height);
clutter_layout_manager_get_preferred_width (layout, CLUTTER_CONTAINER (actor),
avail_height,
&min_width, &natural_width);
clutter_layout_manager_get_preferred_height (layout, CLUTTER_CONTAINER (actor),
MAX (avail_width, min_width),
&min_height, &natural_height);
/* Because StBoxLayout implements StScrollable, the allocation box passed here
* may not match the minimum sizes reported by the layout manager. When that
* happens, the content box needs to be adjusted to match the reported minimum
* sizes before being passed to clutter_layout_manager_allocate() */
clutter_actor_set_allocation (actor, box, flags);
content_box = viewport_content_box;
content_box.x2 += MAX (0, min_width - avail_width);
content_box.y2 += MAX (0, min_height - avail_height);
clutter_layout_manager_allocate (layout, CLUTTER_CONTAINER (actor),
&content_box, flags);
/* update adjustments for scrolling */
if (priv->vadjustment)
{
gdouble prev_value;
g_object_set (G_OBJECT (priv->vadjustment),
"lower", 0.0,
"upper", MAX (min_height, avail_height),
"page-size", avail_height,
"step-increment", avail_height / 6,
"page-increment", avail_height - avail_height / 6,
NULL);
prev_value = st_adjustment_get_value (priv->vadjustment);
st_adjustment_set_value (priv->vadjustment, prev_value);
}
if (priv->hadjustment)
{
gdouble prev_value;
g_object_set (G_OBJECT (priv->hadjustment),
"lower", 0.0,
"upper", MAX (min_width, avail_width),
"page-size", avail_width,
"step-increment", avail_width / 6,
"page-increment", avail_width - avail_width / 6,
NULL);
prev_value = st_adjustment_get_value (priv->hadjustment);
st_adjustment_set_value (priv->hadjustment, prev_value);
}
}
static void
st_box_layout_apply_transform (ClutterActor *a,
CoglMatrix *m)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (a)->priv;
gdouble x, y;
CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->apply_transform (a, m);
if (priv->hadjustment)
x = st_adjustment_get_value (priv->hadjustment);
else
x = 0;
if (priv->vadjustment)
y = st_adjustment_get_value (priv->vadjustment);
else
y = 0;
cogl_matrix_translate (m, (int) -x, (int) -y, 0);
}
/* If we are translated, then we need to translate back before chaining
* up or the background and borders will be drawn in the wrong place */
static void
get_border_paint_offsets (StBoxLayout *self,
double *x,
double *y)
{
StBoxLayoutPrivate *priv = self->priv;
if (priv->hadjustment)
*x = st_adjustment_get_value (priv->hadjustment);
else
*x = 0;
if (priv->vadjustment)
*y = st_adjustment_get_value (priv->vadjustment);
else
*y = 0;
}
static void
st_box_layout_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
StBoxLayout *self = ST_BOX_LAYOUT (actor);
StBoxLayoutPrivate *priv = self->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
gdouble x, y;
ClutterActorBox allocation_box;
ClutterActorBox content_box;
ClutterActor *child;
CoglFramebuffer *fb = clutter_paint_context_get_framebuffer (paint_context);
get_border_paint_offsets (self, &x, &y);
if (x != 0 || y != 0)
{
cogl_framebuffer_push_matrix (fb);
cogl_framebuffer_translate (fb, (int)x, (int)y, 0);
}
st_widget_paint_background (ST_WIDGET (actor), paint_context);
if (x != 0 || y != 0)
{
cogl_framebuffer_pop_matrix (fb);
}
if (clutter_actor_get_n_children (actor) == 0)
return;
clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
content_box.x1 += x;
content_box.y1 += y;
content_box.x2 += x;
content_box.y2 += y;
/* The content area forms the viewport into the scrolled contents, while
* the borders and background stay in place; after drawing the borders and
* background, we clip to the content area */
if (priv->hadjustment || priv->vadjustment)
cogl_framebuffer_push_rectangle_clip (fb,
(int)content_box.x1,
(int)content_box.y1,
(int)content_box.x2,
(int)content_box.y2);
for (child = clutter_actor_get_first_child (actor);
child != NULL;
child = clutter_actor_get_next_sibling (child))
clutter_actor_paint (child, paint_context);
if (priv->hadjustment || priv->vadjustment)
cogl_framebuffer_pop_clip (fb);
}
static void
st_box_layout_pick (ClutterActor *actor,
ClutterPickContext *pick_context)
{
StBoxLayout *self = ST_BOX_LAYOUT (actor);
StBoxLayoutPrivate *priv = self->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
gdouble x, y;
ClutterActorBox allocation_box;
ClutterActorBox content_box;
ClutterActor *child;
CoglFramebuffer *fb = clutter_pick_context_get_framebuffer (pick_context);
get_border_paint_offsets (self, &x, &y);
if (x != 0 || y != 0)
{
cogl_framebuffer_push_matrix (fb);
cogl_framebuffer_translate (fb, (int)x, (int)y, 0);
}
CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, pick_context);
if (x != 0 || y != 0)
{
cogl_framebuffer_pop_matrix (fb);
}
if (clutter_actor_get_n_children (actor) == 0)
return;
clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
content_box.x1 += x;
content_box.y1 += y;
content_box.x2 += x;
content_box.y2 += y;
if (priv->hadjustment || priv->vadjustment)
cogl_framebuffer_push_rectangle_clip (fb,
(int)content_box.x1,
(int)content_box.y1,
(int)content_box.x2,
(int)content_box.y2);
for (child = clutter_actor_get_first_child (actor);
child != NULL;
child = clutter_actor_get_next_sibling (child))
clutter_actor_pick (child, pick_context);
if (priv->hadjustment || priv->vadjustment)
cogl_framebuffer_pop_clip (fb);
}
static gboolean
st_box_layout_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
StBoxLayout *self = ST_BOX_LAYOUT (actor);
gdouble x, y, lower, upper;
StBoxLayoutPrivate *priv = self->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorBox allocation_box;
ClutterActorBox content_box;
graphene_point3d_t origin;
/* Setting the paint volume does not make sense when we don't have any allocation */
if (!clutter_actor_has_allocation (actor))
return FALSE;
/* When have an adjustment we are clipped to the content box, so base
* our paint volume on that. */
if (priv->hadjustment || priv->vadjustment)
{
gdouble width, height;
clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
origin.x = content_box.x1 - allocation_box.x1;
origin.y = content_box.y1 - allocation_box.y2;
origin.z = 0.f;
if (priv->hadjustment)
{
g_object_get (priv->hadjustment,
"lower", &lower,
"upper", &upper,
NULL);
width = upper - lower;
}
else
{
width = content_box.x2 - content_box.x1;
}
if (priv->vadjustment)
{
g_object_get (priv->vadjustment,
"lower", &lower,
"upper", &upper,
NULL);
height = upper - lower;
}
else
{
height = content_box.y2 - content_box.y1;
}
clutter_paint_volume_set_width (volume, width);
clutter_paint_volume_set_height (volume, height);
}
else if (!CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->get_paint_volume (actor, volume))
return FALSE;
/* When scrolled, st_box_layout_apply_transform() includes the scroll offset
* and affects paint volumes. This is right for our children, but our paint volume
* is determined by our allocation and borders and doesn't scroll, so we need
* to reverse-compensate here, the same as we do when painting.
*/
get_border_paint_offsets (self, &x, &y);
if (x != 0 || y != 0)
{
clutter_paint_volume_get_origin (volume, &origin);
origin.x += x;
origin.y += y;
clutter_paint_volume_set_origin (volume, &origin);
}
return TRUE;
}
static void
st_box_layout_style_changed (StWidget *self)
{
@@ -623,20 +182,11 @@ static void
st_box_layout_class_init (StBoxLayoutClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
GParamSpec *pspec;
object_class->get_property = st_box_layout_get_property;
object_class->set_property = st_box_layout_set_property;
object_class->dispose = st_box_layout_dispose;
actor_class->allocate = st_box_layout_allocate;
actor_class->apply_transform = st_box_layout_apply_transform;
actor_class->paint = st_box_layout_paint;
actor_class->get_paint_volume = st_box_layout_get_paint_volume;
actor_class->pick = st_box_layout_pick;
widget_class->style_changed = st_box_layout_style_changed;
@@ -654,16 +204,6 @@ st_box_layout_class_init (StBoxLayoutClass *klass)
FALSE,
ST_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_PACK_START, pspec);
/* StScrollable properties */
g_object_class_override_property (object_class,
PROP_HADJUST,
"hadjustment");
g_object_class_override_property (object_class,
PROP_VADJUST,
"vadjustment");
}
static void

View File

@@ -26,11 +26,12 @@
#define _ST_BOX_LAYOUT_H
#include <st/st-widget.h>
#include <st/st-viewport.h>
G_BEGIN_DECLS
#define ST_TYPE_BOX_LAYOUT st_box_layout_get_type()
G_DECLARE_FINAL_TYPE (StBoxLayout, st_box_layout, ST, BOX_LAYOUT, StWidget)
G_DECLARE_FINAL_TYPE (StBoxLayout, st_box_layout, ST, BOX_LAYOUT, StViewport)
typedef struct _StBoxLayout StBoxLayout;
typedef struct _StBoxLayoutPrivate StBoxLayoutPrivate;
@@ -44,7 +45,7 @@ typedef struct _StBoxLayoutPrivate StBoxLayoutPrivate;
struct _StBoxLayout
{
/*< private >*/
StWidget parent;
StViewport parent;
StBoxLayoutPrivate *priv;
};

View File

@@ -232,8 +232,7 @@ st_entry_update_hint_visibility (StEntry *self)
StEntryPrivate *priv = ST_ENTRY_PRIV (self);
gboolean hint_visible =
priv->hint_actor != NULL &&
strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") == 0 &&
!HAS_FOCUS (priv->entry);
strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") == 0;
if (priv->hint_actor)
g_object_set (priv->hint_actor, "visible", hint_visible, NULL);
@@ -519,10 +518,6 @@ static void
clutter_text_focus_in_cb (ClutterText *text,
ClutterActor *actor)
{
StEntry *entry = ST_ENTRY (actor);
st_entry_update_hint_visibility (entry);
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "focus");
clutter_text_set_cursor_visible (text, TRUE);
}
@@ -531,12 +526,7 @@ static void
clutter_text_focus_out_cb (ClutterText *text,
ClutterActor *actor)
{
StEntry *entry = ST_ENTRY (actor);
st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus");
st_entry_update_hint_visibility (entry);
clutter_text_set_cursor_visible (text, FALSE);
}
@@ -548,8 +538,12 @@ clutter_text_changed_cb (GObject *object,
StEntry *entry = ST_ENTRY (user_data);
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
st_entry_update_hint_visibility (entry);
/* Since the text changed, force a regen of the shadow texture */
cogl_clear_object (&priv->text_shadow_material);
g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_TEXT]);
}
static void
@@ -1039,10 +1033,8 @@ st_entry_get_text (StEntry *entry)
g_return_val_if_fail (ST_IS_ENTRY (entry), NULL);
priv = st_entry_get_instance_private (entry);
if (priv->hint_actor != NULL && clutter_actor_is_visible (priv->hint_actor))
return "";
else
return clutter_text_get_text (CLUTTER_TEXT (priv->entry));
return clutter_text_get_text (CLUTTER_TEXT (priv->entry));
}
/**
@@ -1064,9 +1056,8 @@ st_entry_set_text (StEntry *entry,
clutter_text_set_text (CLUTTER_TEXT (priv->entry), text);
st_entry_update_hint_visibility (entry);
g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_TEXT]);
/* Note: PROP_TEXT will get notfied from our notify::text handler connected
* to priv->entry. */
}
/**
@@ -1104,6 +1095,8 @@ st_entry_set_hint_text (StEntry *entry,
g_return_if_fail (ST_IS_ENTRY (entry));
label = st_label_new (text);
st_widget_add_style_class_name (label, "hint-text");
st_entry_set_hint_actor (ST_ENTRY (entry), CLUTTER_ACTOR (label));
}

View File

@@ -549,7 +549,7 @@ void
st_icon_set_icon_name (StIcon *icon,
const gchar *icon_name)
{
GIcon *gicon = NULL;
g_autoptr(GIcon) gicon = NULL;
g_return_if_fail (ST_IS_ICON (icon));
@@ -726,7 +726,7 @@ void
st_icon_set_fallback_icon_name (StIcon *icon,
const gchar *fallback_icon_name)
{
GIcon *gicon = NULL;
g_autoptr(GIcon) gicon = NULL;
g_return_if_fail (ST_IS_ICON (icon));

View File

@@ -1707,7 +1707,13 @@ do_size_property (StThemeNode *node,
CRDeclaration *decl,
int *node_value)
{
get_length_from_term_int (node, decl->value, FALSE, node_value);
CRTerm *term = decl->value;
if (term->type == TERM_IDENT &&
strcmp (term->content.str->stryng->str, "auto") == 0)
*node_value = -1;
else
get_length_from_term_int (node, term, FALSE, node_value);
}
void

572
src/st/st-viewport.c Normal file
View File

@@ -0,0 +1,572 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-scrollable-wiget.c: a scrollable actor
*
* Copyright 2009 Intel Corporation.
* Copyright 2009 Abderrahim Kitouni
* Copyright 2009, 2010 Red Hat, Inc.
* Copyright 2010 Florian Muellner
* Copyright 2019 Endless, Inc
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Portions copied from Clutter:
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*/
/**
* SECTION:st-viewport
* @short_description: a scrollable container
*
* The #StViewport is a generic #StScrollable implementation.
*
*/
#include <stdlib.h>
#include "st-viewport.h"
#include "st-private.h"
#include "st-scrollable.h"
static void st_viewport_scrollable_interface_init (StScrollableInterface *iface);
enum {
PROP_0,
PROP_HADJUST,
PROP_VADJUST
};
typedef struct
{
StAdjustment *hadjustment;
StAdjustment *vadjustment;
} StViewportPrivate;
G_DEFINE_TYPE_WITH_CODE (StViewport, st_viewport, ST_TYPE_WIDGET,
G_ADD_PRIVATE (StViewport)
G_IMPLEMENT_INTERFACE (ST_TYPE_SCROLLABLE,
st_viewport_scrollable_interface_init));
/*
* StScrollable Interface Implementation
*/
static void
adjustment_value_notify_cb (StAdjustment *adjustment,
GParamSpec *pspec,
StViewport *viewport)
{
clutter_actor_queue_relayout (CLUTTER_ACTOR (viewport));
}
static void
scrollable_set_adjustments (StScrollable *scrollable,
StAdjustment *hadjustment,
StAdjustment *vadjustment)
{
StViewport *viewport = ST_VIEWPORT (scrollable);
StViewportPrivate *priv =
st_viewport_get_instance_private (viewport);
g_object_freeze_notify (G_OBJECT (scrollable));
if (hadjustment != priv->hadjustment)
{
if (priv->hadjustment)
{
g_signal_handlers_disconnect_by_func (priv->hadjustment,
adjustment_value_notify_cb,
scrollable);
g_object_unref (priv->hadjustment);
}
if (hadjustment)
{
g_object_ref (hadjustment);
g_signal_connect (hadjustment, "notify::value",
G_CALLBACK (adjustment_value_notify_cb),
scrollable);
}
priv->hadjustment = hadjustment;
g_object_notify (G_OBJECT (scrollable), "hadjustment");
}
if (vadjustment != priv->vadjustment)
{
if (priv->vadjustment)
{
g_signal_handlers_disconnect_by_func (priv->vadjustment,
adjustment_value_notify_cb,
scrollable);
g_object_unref (priv->vadjustment);
}
if (vadjustment)
{
g_object_ref (vadjustment);
g_signal_connect (vadjustment, "notify::value",
G_CALLBACK (adjustment_value_notify_cb),
scrollable);
}
priv->vadjustment = vadjustment;
g_object_notify (G_OBJECT (scrollable), "vadjustment");
}
g_object_thaw_notify (G_OBJECT (scrollable));
}
static void
scrollable_get_adjustments (StScrollable *scrollable,
StAdjustment **hadjustment,
StAdjustment **vadjustment)
{
StViewport *viewport = ST_VIEWPORT (scrollable);
StViewportPrivate *priv =
st_viewport_get_instance_private (viewport);
if (hadjustment)
*hadjustment = priv->hadjustment;
if (vadjustment)
*vadjustment = priv->vadjustment;
}
static void
st_viewport_scrollable_interface_init (StScrollableInterface *iface)
{
iface->set_adjustments = scrollable_set_adjustments;
iface->get_adjustments = scrollable_get_adjustments;
}
static void
st_viewport_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
StAdjustment *adjustment;
switch (property_id)
{
case PROP_HADJUST:
scrollable_get_adjustments (ST_SCROLLABLE (object), &adjustment, NULL);
g_value_set_object (value, adjustment);
break;
case PROP_VADJUST:
scrollable_get_adjustments (ST_SCROLLABLE (object), NULL, &adjustment);
g_value_set_object (value, adjustment);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_viewport_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
StViewport *viewport = ST_VIEWPORT (object);
StViewportPrivate *priv =
st_viewport_get_instance_private (viewport);
switch (property_id)
{
case PROP_HADJUST:
scrollable_set_adjustments (ST_SCROLLABLE (object),
g_value_get_object (value),
priv->vadjustment);
break;
case PROP_VADJUST:
scrollable_set_adjustments (ST_SCROLLABLE (object),
priv->hadjustment,
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_viewport_dispose (GObject *object)
{
StViewport *viewport = ST_VIEWPORT (object);
StViewportPrivate *priv =
st_viewport_get_instance_private (viewport);
g_clear_object (&priv->hadjustment);
g_clear_object (&priv->vadjustment);
G_OBJECT_CLASS (st_viewport_parent_class)->dispose (object);
}
static void
st_viewport_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
StViewport *viewport = ST_VIEWPORT (actor);
StViewportPrivate *priv =
st_viewport_get_instance_private (viewport);
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterLayoutManager *layout = clutter_actor_get_layout_manager (actor);
ClutterActorBox viewport_box;
ClutterActorBox content_box;
float avail_width, avail_height;
float min_width, natural_width;
float min_height, natural_height;
st_theme_node_get_content_box (theme_node, box, &viewport_box);
clutter_actor_box_get_size (&viewport_box, &avail_width, &avail_height);
clutter_layout_manager_get_preferred_width (layout, CLUTTER_CONTAINER (actor),
avail_height,
&min_width, &natural_width);
clutter_layout_manager_get_preferred_height (layout, CLUTTER_CONTAINER (actor),
MAX (avail_width, min_width),
&min_height, &natural_height);
/* Because StViewport implements StScrollable, the allocation box passed here
* may not match the minimum sizes reported by the layout manager. When that
* happens, the content box needs to be adjusted to match the reported minimum
* sizes before being passed to clutter_layout_manager_allocate() */
clutter_actor_set_allocation (actor, box, flags);
content_box = viewport_box;
content_box.x2 += MAX (0, min_width - avail_width);
content_box.y2 += MAX (0, min_height - avail_height);
clutter_layout_manager_allocate (layout, CLUTTER_CONTAINER (actor),
&content_box, flags);
/* update adjustments for scrolling */
if (priv->vadjustment)
{
double prev_value;
g_object_set (G_OBJECT (priv->vadjustment),
"lower", 0.0,
"upper", MAX (min_height, avail_height),
"page-size", avail_height,
"step-increment", avail_height / 6,
"page-increment", avail_height - avail_height / 6,
NULL);
prev_value = st_adjustment_get_value (priv->vadjustment);
st_adjustment_set_value (priv->vadjustment, prev_value);
}
if (priv->hadjustment)
{
double prev_value;
g_object_set (G_OBJECT (priv->hadjustment),
"lower", 0.0,
"upper", MAX (min_width, avail_width),
"page-size", avail_width,
"step-increment", avail_width / 6,
"page-increment", avail_width - avail_width / 6,
NULL);
prev_value = st_adjustment_get_value (priv->hadjustment);
st_adjustment_set_value (priv->hadjustment, prev_value);
}
}
static void
st_viewport_apply_transform (ClutterActor *actor,
CoglMatrix *matrix)
{
StViewport *viewport = ST_VIEWPORT (actor);
StViewportPrivate *priv = st_viewport_get_instance_private (viewport);
ClutterActorClass *parent_class =
CLUTTER_ACTOR_CLASS (st_viewport_parent_class);
double x, y;
parent_class->apply_transform (actor, matrix);
if (priv->hadjustment)
x = st_adjustment_get_value (priv->hadjustment);
else
x = 0;
if (priv->vadjustment)
y = st_adjustment_get_value (priv->vadjustment);
else
y = 0;
cogl_matrix_translate (matrix, (int) -x, (int) -y, 0);
}
/* If we are translated, then we need to translate back before chaining
* up or the background and borders will be drawn in the wrong place */
static void
get_border_paint_offsets (StViewport *viewport,
double *x,
double *y)
{
StViewportPrivate *priv = st_viewport_get_instance_private (viewport);
if (priv->hadjustment)
*x = st_adjustment_get_value (priv->hadjustment);
else
*x = 0;
if (priv->vadjustment)
*y = st_adjustment_get_value (priv->vadjustment);
else
*y = 0;
}
static void
st_viewport_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
StViewport *viewport = ST_VIEWPORT (actor);
StViewportPrivate *priv = st_viewport_get_instance_private (viewport);
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
double x, y;
ClutterActorBox allocation_box;
ClutterActorBox content_box;
ClutterActor *child;
CoglFramebuffer *fb = clutter_paint_context_get_framebuffer (paint_context);
get_border_paint_offsets (viewport, &x, &y);
if (x != 0 || y != 0)
{
cogl_framebuffer_push_matrix (fb);
cogl_framebuffer_translate (fb, (int)x, (int)y, 0);
}
st_widget_paint_background (ST_WIDGET (actor), paint_context);
if (x != 0 || y != 0)
cogl_framebuffer_pop_matrix (fb);
if (clutter_actor_get_n_children (actor) == 0)
return;
clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
content_box.x1 += x;
content_box.y1 += y;
content_box.x2 += x;
content_box.y2 += y;
/* The content area forms the viewport into the scrolled contents, while
* the borders and background stay in place; after drawing the borders and
* background, we clip to the content area */
if (priv->hadjustment || priv->vadjustment)
{
cogl_framebuffer_push_rectangle_clip (fb,
(int)content_box.x1,
(int)content_box.y1,
(int)content_box.x2,
(int)content_box.y2);
}
for (child = clutter_actor_get_first_child (actor);
child != NULL;
child = clutter_actor_get_next_sibling (child))
clutter_actor_paint (child, paint_context);
if (priv->hadjustment || priv->vadjustment)
cogl_framebuffer_pop_clip (fb);
}
static void
st_viewport_pick (ClutterActor *actor,
ClutterPickContext *pick_context)
{
StViewport *viewport = ST_VIEWPORT (actor);
StViewportPrivate *priv = st_viewport_get_instance_private (viewport);
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
double x, y;
ClutterActorBox allocation_box;
ClutterActorBox content_box;
ClutterActor *child;
CoglFramebuffer *fb = clutter_pick_context_get_framebuffer (pick_context);
get_border_paint_offsets (viewport, &x, &y);
if (x != 0 || y != 0)
{
cogl_framebuffer_push_matrix (fb);
cogl_framebuffer_translate (fb, (int)x, (int)y, 0);
}
CLUTTER_ACTOR_CLASS (st_viewport_parent_class)->pick (actor, pick_context);
if (x != 0 || y != 0)
cogl_framebuffer_pop_matrix (fb);
if (clutter_actor_get_n_children (actor) == 0)
return;
clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
content_box.x1 += x;
content_box.y1 += y;
content_box.x2 += x;
content_box.y2 += y;
if (priv->hadjustment || priv->vadjustment)
{
cogl_framebuffer_push_rectangle_clip (fb,
(int)content_box.x1,
(int)content_box.y1,
(int)content_box.x2,
(int)content_box.y2);
}
for (child = clutter_actor_get_first_child (actor);
child != NULL;
child = clutter_actor_get_next_sibling (child))
clutter_actor_pick (child, pick_context);
if (priv->hadjustment || priv->vadjustment)
cogl_framebuffer_pop_clip (fb);
}
static gboolean
st_viewport_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
StViewport *viewport = ST_VIEWPORT (actor);
StViewportPrivate *priv = st_viewport_get_instance_private (viewport);
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorBox allocation_box;
ClutterActorBox content_box;
graphene_point3d_t origin;
double x, y, lower, upper;
/* Setting the paint volume does not make sense when we don't have any allocation */
if (!clutter_actor_has_allocation (actor))
return FALSE;
/* When have an adjustment we are clipped to the content box, so base
* our paint volume on that. */
if (priv->hadjustment || priv->vadjustment)
{
double width, height;
clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
origin.x = content_box.x1 - allocation_box.x1;
origin.y = content_box.y1 - allocation_box.y2;
origin.z = 0.f;
if (priv->hadjustment)
{
g_object_get (priv->hadjustment,
"lower", &lower,
"upper", &upper,
NULL);
width = upper - lower;
}
else
{
width = content_box.x2 - content_box.x1;
}
if (priv->vadjustment)
{
g_object_get (priv->vadjustment,
"lower", &lower,
"upper", &upper,
NULL);
height = upper - lower;
}
else
{
height = content_box.y2 - content_box.y1;
}
clutter_paint_volume_set_width (volume, width);
clutter_paint_volume_set_height (volume, height);
}
else if (!CLUTTER_ACTOR_CLASS (st_viewport_parent_class)->get_paint_volume (actor, volume))
{
return FALSE;
}
/* When scrolled, st_viewport_apply_transform() includes the scroll offset
* and affects paint volumes. This is right for our children, but our paint volume
* is determined by our allocation and borders and doesn't scroll, so we need
* to reverse-compensate here, the same as we do when painting.
*/
get_border_paint_offsets (viewport, &x, &y);
if (x != 0 || y != 0)
{
clutter_paint_volume_get_origin (volume, &origin);
origin.x += x;
origin.y += y;
clutter_paint_volume_set_origin (volume, &origin);
}
return TRUE;
}
static void
st_viewport_class_init (StViewportClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
object_class->get_property = st_viewport_get_property;
object_class->set_property = st_viewport_set_property;
object_class->dispose = st_viewport_dispose;
actor_class->allocate = st_viewport_allocate;
actor_class->apply_transform = st_viewport_apply_transform;
actor_class->paint = st_viewport_paint;
actor_class->get_paint_volume = st_viewport_get_paint_volume;
actor_class->pick = st_viewport_pick;
/* StScrollable properties */
g_object_class_override_property (object_class,
PROP_HADJUST,
"hadjustment");
g_object_class_override_property (object_class,
PROP_VADJUST,
"vadjustment");
}
static void
st_viewport_init (StViewport *self)
{
}

40
src/st/st-viewport.h Normal file
View File

@@ -0,0 +1,40 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-viewport.h: viewport actor
*
* Copyright 2009 Intel Corporation.
* Copyright 2009, 2010 Red Hat, Inc.
* Copyright 2019 Endless, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
#error "Only <st/st.h> can be included directly.h"
#endif
#pragma once
#include <st/st-widget.h>
G_BEGIN_DECLS
#define ST_TYPE_VIEWPORT (st_viewport_get_type())
G_DECLARE_DERIVABLE_TYPE (StViewport, st_viewport, ST, VIEWPORT, StWidget)
struct _StViewportClass
{
StWidgetClass parent_class;
};
G_END_DECLS

View File

@@ -1897,12 +1897,12 @@ st_widget_set_hover (StWidget *widget,
void
st_widget_sync_hover (StWidget *widget)
{
ClutterDeviceManager *device_manager;
ClutterInputDevice *pointer;
ClutterActor *pointer_actor;
ClutterSeat *seat;
device_manager = clutter_device_manager_get_default ();
pointer = clutter_device_manager_get_device (device_manager, VIRTUAL_CORE_POINTER_ID);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
pointer = clutter_seat_get_pointer (seat);
pointer_actor = clutter_input_device_get_pointer_actor (pointer);
if (pointer_actor && clutter_actor_get_reactive (CLUTTER_ACTOR (widget)))
st_widget_set_hover (widget, clutter_actor_contains (CLUTTER_ACTOR (widget), pointer_actor));