Compare commits

...

134 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
47a2e58d45 Introduce updates indicator
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/466
2019-03-19 12:18:54 +00:00
Georges Basile Stavracas Neto
20d73be57d Introduce Automatic Updates component
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/466
2019-03-19 12:18:47 +00:00
Carlos Garnacho
62233a4db4 dnd: Multiply drag threshold by output scale
So it comes out right on hidpi, and consistent with clients.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/455
2019-03-13 17:22:35 +00:00
Carlos Garnacho
4a7e2ddff5 dnd: Make startDrag() fail if there is a current grab
This call just went through stomping over previous drag operations if any,
_maybeStartDrag() accounted for this, but other callers (well, WindowClone
in workspace.js) don't. This must bail out early even if a drag operation is
requested, luckily all callers account for it already.

This broke shell state by preserving connected captured-event handlers if
one tried to drag multiple windows simultaneously through multitouch. We
of course don't support that, now more elegantly.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/455
2019-03-13 17:22:35 +00:00
Victor Ibragimov
fb737ebde0 Update Tajik Translation 2019-03-13 21:45:05 +05:00
Victor Ibragimov
bf77cb44e7 Merge branch 'master' of gitlab.gnome.org:GNOME/gnome-shell 2019-03-13 21:40:31 +05:00
Victor Ibragimov
c72e2bb4a9 Update Tajik Translation 2019-03-13 21:39:34 +05:00
Victor Ibragimov
68c182b1df Update Tajik Translation 2019-03-13 21:18:10 +05:00
Alex Monday
348d303794 theme: Fix :checked:active page-indicator
Closes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1036
2019-03-12 11:58:36 +00:00
Florian Müllner
ede0fd8660 magnifier: Fix color argument
Clutter.TextureNode takes a Clutter.Color, not a Cogl.Color.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1020
2019-03-12 01:52:22 +00:00
Robert Mader
187c2193e8 st-theme-node-transition: Exclude get_new_paint_state() from introspection
to silence a build warning.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/449
2019-03-12 01:14:52 +00:00
Florian Müllner
706bdd8059 st-widget: Add missing g_return_val_if_fail()
It's a public function, so it's good practice to sanity-check its
input (unless disabled at compile time of course).

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1018
2019-03-12 01:00:32 +00:00
Jakub Steiner
436861edc8 theme: improve legibility of error messages
- the login dialog uses warning_color, so be consistent
- nevertheless increase lightness of the error_color

Fixes issue https://gitlab.gnome.org/GNOME/gnome-shell/issues/1016
2019-03-12 00:54:26 +00:00
Florian Müllner
9729a2e772 texture-cache: Apply resource scale to the right dimension
Size matters!

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/444
2019-03-12 00:48:11 +00:00
Florian Müllner
6b924c00c5 layout: Use custom actor for uiGroup
The bind constraint that replaced the Shell.GenericContainer in commit
f4682748fa is subtly different from the previous code:
It forces the actor to have the same size as the stage, rather than just
requesting that size.

This breaks the magnifier which relies on the UI being able to be bigger
than the display size. Fix by going back to using a custom actor.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/646
2019-03-12 00:39:40 +00:00
Florian Müllner
b90f4d29a4 userWidget: Fix avatar size
The texture cache now returns an actor with an appropriate ClutterContent
rather than a ClutterTexture. That actor uses the CONTENT_SIZE request
mode, which means that it will unconditionally request the preferred size
of the content. That is, setting an explicit size no longer has an effect.

Fix this by making sure the image is already loaded with the desired
dimensions.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1024
2019-03-12 00:34:04 +00:00
Florian Müllner
47915f8c11 Bump version to 3.32.0
Update NEWS.
2019-03-11 23:54:15 +01:00
Florian Müllner
5dfdeaa4ea theme: Fix menu arrows
After the latest texture cache changes, loading the icon at its preferred
size and scaling it via the actor size no longer works. Instead, use the
icon-size property which is applied when loading the icon.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/452
2019-03-10 22:03:05 +01:00
Mart Raudsepp
98a2a81f2a Update Estonian translation 2019-03-10 16:57:52 +00:00
Piotr Drąg
c4850027bc Fix Icon in translations 2019-03-10 17:32:06 +01:00
Florian Müllner
d4202e7f38 theme: Handle fallback app icons in notifications
Since commit 3eb80dc6c0, the size of notification icons is determined
by the theme to make it font-relative. Also handle the case where the
icon isn't an StIcon, but a fallback window icon.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1027
2019-03-08 16:20:21 +01:00
Florian Müllner
4f65283f31 app: Set styleclass on fallback app icons
For window backed apps, create_icon_texture() doesn't return an StIcon
but a generic widget. Set an appropriate style class to make it easier
to apply a specific style only to fallback icons.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1027
2019-03-08 16:20:21 +01:00
Florian Müllner
d86d3bbe54 texture-cache: Fall back to actor size for bound textures
With StImageContent, the meaning of passing -1 as size parameter changed
from "load the image at its preferred size" to "abort the session". It
is therefore no longer possible to just load the image and then have it
scaled by applying a CSS size to the texture's parent.

Setting the size from CSS is useful though, so to still allow that, fall
back to the actor's size (which can be determined by the style).

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1027
2019-03-08 16:20:21 +01:00
Florian Müllner
6f794738e8 texture-cache: Load bound surfaces into StWidgets
Using widgets instead of plain actors will allow us to set the size
from CSS.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1027
2019-03-08 16:20:21 +01:00
Ryuta Fujii
ef7a93bb07 Update Japanese translation 2019-03-07 11:17:18 +00:00
Victor Ibragimov
5197a992a6 Update Tajik translation 2019-03-06 20:15:01 +05:00
Victor Ibragimov
49d8540f6d Update Tajik Translation 2019-03-06 20:08:28 +05:00
Victor Ibragimov
6e1a1f1a57 Update Tajik Translation 2019-03-06 20:06:55 +05:00
Iain Lane
c73428247c build: Add mutter's private directory to libst's build-time RPATH
We need this to run `test-theme`, otherwise when run as part of the
build tests it fails like:

  error while loading shared libraries: libmutter-cogl-4.so.0: cannot
  open shared object file: No such file or directory

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/442
2019-03-06 12:45:48 +00:00
Gábor Kelemen
fc2caf5794 Update Hungarian translation 2019-03-05 22:05:20 +00:00
Carlos Garnacho
b117826ada keyboard: Add bottom emoji panel row to separate aspect container
So we ensure the row has the right aspect ratio, and buttons neatly aligned
with the bottom row in the alphanumeric view.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/439
2019-03-05 21:11:47 +00:00
Carlos Garnacho
26b44b48ab keyboard: align AspectContainer to bottom if restricting vertically
It is convenient for the OSK so it eg. doesn't appear centered in the
available space (eg. on very narrow portrait layouts), plus it will also
be convenient to align other AspectContainers to the same baseline.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/439
2019-03-05 21:11:47 +00:00
Florian Müllner
6349f0feb1 Bump version to 3.31.92
Update NEWS.
2019-03-05 05:07:44 +01:00
Florian Müllner
2ae17cfb50 userWidget: Remove frame around avatar
There's a push for round user images, for which the existing square
frame is a bad match. So remove the frame and enforce the shape.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/811
2019-03-04 22:50:29 +00:00
Robert Mader
4785093a5c st-shadow: Remove unnecessary ';'
to silence a build warning.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/434
2019-03-04 22:29:33 +00:00
Florian Müllner
859aef78c4 osk-layouts: Fix French layout
The script to convert XML keyboard layouts to json has a small bug
that causes the French-Canadian layout to end up as French.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/997
2019-03-04 20:55:15 +00:00
Florian Müllner
20730a5465 data: Don't drop emoji layout on update
https://gitlab.gnome.org/GNOME/gnome-shell/issues/997
2019-03-04 20:55:15 +00:00
Florian Müllner
fc5f687afc Fix override for fr-CA 2019-03-04 20:55:15 +00:00
Carlos Garnacho
53e56f2395 Generate all json files for the android directory in a go 2019-03-04 20:55:15 +00:00
Alan
da314aff79 Add convert_xml test 2019-03-04 20:55:15 +00:00
Alan
fe89f7c5ac Add level modifiers in JSON
This is needed because some layouts don't have an uppercase level.
That shouldn't make symbols the 2nd level.
2019-03-04 20:55:15 +00:00
Alan
8b3be5e063 Remove garbage 2019-03-04 20:55:15 +00:00
Alan
58dc538510 Load mappings at module initialisation 2019-03-04 20:55:15 +00:00
Alan
6cbef9355d Add unit tests 2019-03-04 20:55:15 +00:00
Alan
22eac5c508 Add basic documentation 2019-03-04 20:55:15 +00:00
Alan
a2860e9c73 Remove useless test 2019-03-04 20:55:15 +00:00
Alan
1c5258ab68 Rename script 2019-03-04 20:55:15 +00:00
Alan
8641eaa538 Output JSON and work on directories 2019-03-04 20:55:14 +00:00
Alan
88436383c0 Add licence statement from Caribou 2019-03-04 20:55:14 +00:00
Alan
affdcdcb0e Import script from caribou source 2019-03-04 20:55:14 +00:00
Florian Müllner
06174be777 build: Include test-theme in tests
It's an existing test that doesn't require interaction, so there's
no reason why it shouldn't be run by `ninja test`.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/419
2019-03-04 20:10:07 +00:00
Florian Müllner
fde8401124 test-theme: Change presumed CWD
The executable is assumed to be run from $top_srcdir/src, which is
essentially an autotools left-over (it's where the program ended
up with srcdir == builddir).

Now with meson, its actual srcdir makes more senses.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/419
2019-03-04 20:10:07 +00:00
Florian Müllner
70ac33d58c test-theme: Force default resolution
Clutter no longer hard-codes a resolution of 96 DPI (although that's
still the default), so any assertions of sizes for physical units
may be off.

Fix this by setting up the test environment according to the
assumptions.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/419
2019-03-04 20:10:07 +00:00
Robert Mader
5a897407d9 shell-tray-manager: Silence gdk_window_set_background_pattern warning
Apparently we can't get rid of it without breaking backward compatibility.
So let's stick to how GTK handles it and just silence the warning.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/423
2019-03-04 19:57:47 +00:00
Robert Mader
1b3c26364b na-tray-child: Silence gdk_window_set_background_pattern warnings
Apparently we can't get rid of them without breaking backward compatibility.
So let's stick to how GTK handles it and just silence the warnings.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/423
2019-03-04 19:57:47 +00:00
Florian Müllner
ae07aa7864 gtk-embed: Hide window actors from pick
Since we started to support tray icons on wayland, the icon we show
is not the actual XEmbed window. Instead, we let mutter create a
MetaWindow for it, then use its window actor as source for a clone
we (or nowadays: extensions) can add, remove and destroy freely.

To not let the real icon get in the way, we set an empty input shape
and make its window actor fully transparent. This works OK on X11,
but on wayland all events still go through Clutter, so any reactive
surface actor inside the window actor will block events for any actors
underneath (and status icons go into the top-windows group, so almost
all actors are affected).

Luckily we can pile another hack onto the pile of status icon hacks ...

https://gitlab.gnome.org/GNOME/gnome-shell/issues/191
2019-03-04 19:52:24 +00:00
Carlos Garnacho
fb80831269 inputMethod: Handle OSK hiding after unfocus
Set a small timeout in order to let focus changes preserve OSK state. If
focus is eventually unset, the OSK will be hidden.

https://gitlab.gnome.org/GNOME/gtk/issues/1277
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/397
2019-03-04 18:24:38 +00:00
Benjamin Berg
561cecf383 shellDBus: Add UngrabAccelerators
While it is possible to register accelerators in-bulk, there is no
proper way to unregister them again. This adds the corresponding call
for UngrabAccelerator to allow ungrabbing multiple accelerators at the
same time.

The idea is that g-s-d can use this in the future to simplify the
keybinding reload logic.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/429
2019-03-04 16:45:16 +00:00
Andrea Azzarone
60ccdc2deb dnd: Only handle touch events in wayland
There are serveral issues around touch passive grab and touch/pointer doubly
handling to use these on X11, so we stick to single-touch/pointer there.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1015
2019-03-04 16:21:28 +00:00
Florian Müllner
d7d996b1d3 automountManager: Fix playing disconnected sound
A typo sneaked in in commit 9a35c990 ...

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/432
2019-03-04 14:39:40 +01:00
Olivier Fourdan
32b8bc39ac inhibitShortcuts: Save choice in permission store
Use the permission store to remember the user's decision as to whether
or not grant the shortcuts request when the application is known.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/382
2019-03-04 10:12:58 +01:00
Aurimas Černius
9dc99ad611 Updated Lithuanian translation 2019-03-03 18:54:25 +02:00
Rūdolfs Mazurs
628cb4d553 Update Latvian translation 2019-03-03 14:18:43 +00:00
Nathan Follens
ad80bce78d Update Dutch translation 2019-03-03 10:15:54 +00:00
Florian Müllner
1c9d821aa2 messageTray: Add source policy setter
Commit 8f15193b4 changed the `policy` property from a regular JS property to
a getter. This was necessary to avoid calling an overridden _createPolicy()
method before a subclass is properly initialized, but it broke the second
way of using notification sources:

Don't create a Source subclass, but use the base class directly and change
its `policy` property.

There's no good reason why we should no longer allow this, so add a setter.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/431
2019-03-03 08:58:56 +00:00
Trần Ngọc Quân
510b060947 Updated Vietnamese translation
Signed-off-by: Trần Ngọc Quân <vnwildman@gmail.com>
2019-03-03 13:48:55 +07:00
Florian Müllner
26e33ff093 windowAttentionHandler: Don't destroy on open
The activateWindow() call is expected to focus the window, which
already destroys the source. If we then destroy it again explicitly,
we get another "invalid access" warning.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/430
2019-03-02 22:09:33 +01:00
Florian Müllner
5f2bd70690 network: Don't destroy wireless dialog twice
The dialog doesn't change the `destroyOnClose` property from its default,
so it is already destroyed automatically on close. So if we also destroy
it explicitly, we end up (rightfully) with one of gjs' infamous "invalid
access" warnings.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/430
2019-03-02 22:09:20 +01:00
Bernd Homuth
6dfa550663 Update German translation 2019-03-02 20:14:39 +00:00
Daniel Șerbănescu
252e2420ad Update Romanian translation 2019-03-02 19:55:56 +00:00
Florian Müllner
572d54981e appsMenu: Fix initial visibility of "Details" item
It is only supposed to be visible when Software is installed, but
we currently only update the visibility on changes.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/989
2019-03-02 18:13:38 +00:00
verdre
61471f9fb4 search: Hide the separator line of the last result
If a result is displayed at the end of the search results, there should
obviously not be a line separating it from the next result underneath
it. To fix this, always hide the separator for the last result visible.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/311
2019-03-02 12:29:41 +00:00
Florian Müllner
4d0a742d64 st: Only consider visible children for :first/:last-child
While mapping the :first/:last-child pseudo classes directly to the
ClutterActor:first-child/:last-child properties allows for an easy
implementation, it is unexpected that rules can appear to not have
an effect because the selected child is hidden. GTK's behavior of
applying the classes to visible children makes much more sense, so
change our implementation to do the same.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/312
2019-03-02 12:19:40 +00:00
Niels De Graef
5f4e0e5ff8 plugin: Style consistency fix
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/315
2019-03-02 11:57:21 +00:00
Niels De Graef
a4c159ecad plugin: Use G_DECLARE_FINAL_TYPE
libmutter-4 added support for this, so we can also drop the boilerplate.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/315
2019-03-02 11:57:21 +00:00
Niels De Graef
b1f893e998 plugin: Move class_init and init below methods
This allows us to get rid of all the forward declarations, tidying up
the file a bit.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/315
2019-03-02 11:57:21 +00:00
Niels De Graef
789dc165af plugin: Add some comments on its purpose
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/315
2019-03-02 11:57:21 +00:00
Marco Trevisan (Treviño)
115eda9650 shell-screenshot: Apply monitor scale to cursor surface
When we grab a screenshot of a framebuffer scaled shell, we shoudl apply the
device scale to the image surface, while the monitor scaling should be applied
to the cursor surface, so that it's painted at proper coordinates and in proper
size in the generated image.

This is not needed for XWayland clients as they are not scaled anyways, while
for wayland clients that are painted in multiple monitors, this might cause
a lower quality cursor in the lower dpi monitor, because the cursor sprite is
generated for the monitor scale, and not for the surface scale.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
d027e35cef shell-screenshot: Always use "actors-painted" signal
Since we don't care about all the stage to be painted here, we can just proceed
when all the actors have been put in place.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
b3e178af9d shell-screenshot: Use mutter paint signals to optionally draw cursor
Under wayland, if the cursor should be included when doing a fullscreen
screenshot, we can rely on mutter "paint" signal to have it composited for free.
Otherwise if it's not requested, we can use the "actors-painted" signal to get a
stage texture before the mouse overlay has been added.

Instead, under X11 or when only a window screenshot is requested, we still
need to draw it manually.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
559ec8750a shell-screenshot: Add utility function to check when draw the cursor
Don't repeat the same logic in multiple places, just set include_cursor to the
proper value once depending on the settings we have.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
02c3980b83 shell-screenshot: Initialize cursor tracker in draw cursor function
Avoid code duplication, since we're using this only if the cursor has to be
painted differently.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
6f027ee7dc shell-util: Apply resource_scale on clipping when getting the meta texture image
https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
6d6c2e5b99 shell-recorder: Use clutter-computed sizes and scaling for the capture
Get from clutter the capture sizes and scale and don't mind
about doing any rounding here, as it might be different
from the one done at clutter level (causing mismatch and
not-working videos). Delegate this to clutter, and forget
about the internal details.

These values are then used to composte the image and set the video caps.

https://bugzilla.gnome.org/show_bug.cgi?id=7650111
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
4a4f752459 dateMenu: Relayout IndicatorPad when parent size changes
This happens often in resource-scaled world

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
8f1fff1374 background: Don't set background actor sizing and scaling
Mutter BackgroundActor is able do detect this at lower level

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
deead2af97 layout: Add scale property to Monitor
https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
9e881ab637 animation: Reload sliced texture on global scale change
When the scale has changed we need to reload the texture at proper size.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
b6ec02cef2 animation: Load sliced image using resource scale, and reload on change
Also make sure that the textures size is matching the container size.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
26e3ccda49 loginDialog: Load logo file texture given resource scale
And reload the logo if the resource scale changes.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
2bda79cb3a st-texture-cache: Use GSlice to manage memory of leaders data
This allows some memory optimizations when possible, so let's use it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
19c60ff5c5 st-texture-cache: use StImageContent for cairo bound surface
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
e3c5c9a2e7 st-texture-cache: Cancel sliced image loading on target actor destroy
It might happen that the target clutter actor that we return on call
of st_texture_cache_load_sliced_image might be destroyed while the
loading task is still running. To protect from this, let's connect
to "destroy" signal and when this happens we use a cancellable to
stop the task.

This allows to safely reuse the return value of this function to
cancel the execution and avoiding that load_callback is called
even for a request that is not anymore under our control.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
2c17c186b8 st-texture-cache: Load sliced contents with REQUEST_CONTENTENT_SIZE
When loading an actor for a sliced image actor, we can now use the
REQUEST_CONTENT_SIZE request-mode for the actor since we the content image
has now a predictable size and thus we can be sure that the size will be applied
taking care of the resource scale.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Marco Trevisan (Treviño)
ef1697d00d st-texture-cache: Set sliced actor size in logical size
The actor size should be set in logical size more than in the actual size
of the texture when using resource scale.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:53 +00:00
Jonas Ådahl
40e7638a4b st-icon: Add resource-scale support
This commit adds support for scaling the StIcon resource (the icon
texture) according to the resource scale.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
aaf69b2898 st-texture-cache: Use StContentImage to create actor contents
This will allow to use resource-scale aware content that will use a preferred
size that takes in account the icon scaling and the resource scaling.

If no size is passed we should just divide the actual resource size by the
resource scale, as we assume that it's loaded with such scaling applied.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
0464361ca5 st-image-content: Wrap ClutterImage with explicit preferred size
Create StImageContent as a simple ClutterImage with preferred width/height
properties in order to be able to use explicit sizing when creating clutter
contents that will be applied to actors whose size depends on the content itself.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
420697693b st-texture-cache: Separate 'scale' to 'paint_scale' and 'resource_scale'
Instead of just passing a scale when getting a cached icon, pass both a
'paint_scale', the scale of which the icon will be painted on the
stage, and a 'resource_scale', the scale of the resource used for
painting.

In effect, the texture size will use the scale 'paint_scale * resource_scale'
in a ceiled value while the size of the actor will use 'paint_scale' when
determining the size.
this would load a bigger texture, but the downscaling would keep the visual
quality.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
37f53a42da st: Create shadow pipeline taking resource scale in account
The shadow pipeline is created doing software blurring of the texture so the
shadow spec blur parameter should be scaled accordingly with the texture scaling
otherwise we won't take enough pixels in account creating stronger shadows.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
5617ffc79c st: Use scaled surfaces for creating cairo background shadows
Create the surfaces for background shadows at scaled sizes and then draw on them
using logical coordinates, by setting the surface device scale accordingly.

Use the said surface scale when generating the actual shadow cairo pattern
but in such case, to reduce the number of code changes, is better to work in
absolute coordinates, and to do so:
  1) Create a temporary shadow-spec copy with scaled values to absolute sizes
  2) Invert the scaling on the shadow matrix
  3) Do the actual painting in absolute coordinates
  4) Set the shadow matrix scaling back to the logical coordinates.

Finally scale down the created shadow pattern surface size when painting it,
applying again a reverse scale to the matrix.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
ca4d86e9e5 st-shadow: Define autoptr cleanup function for StShadow
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
0141fef561 st-theme-node: Paint elements in resource-scale scaled surfaces
Pass resource-scale to drawing phase, and use it to create texture
surfaces scaled with the widget current scaling.
Also redraw by default widgets when the resource scale changes.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Jonas Ådahl
5d4a804c90 st-shadow: Ceil size before comparing with texture
A fractional resource scale would mean we never use the fast path for
creating the shadow, because we'd cast the int to a float before
comparing, which would never match.

Instead compare the expected texture size with the source texture, to
actually potentially trigger the fast path.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Jonas Ådahl
6bc3300e5a st-scroll-view-fade: Include outer bound of pixel on border
The fade shader will draw the fade effect up until the border pixel. If
we set the bottom right coordinate to the outer edge of the pixel we
might end up not drawing the fade effect on all of the pixels. This
could for example happen if one logical pixel (clutter stage pixel)
consists of more than one physical pixel.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
15f69bdc3b st-label: Paint shadow using resource-scaled texture
https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
0bcf76970a st-private: Scale shadows accordingly to actor resource scaling
Use scaled offscreen framebuffer to paint shadows so that it will match the
scaling applied to the actual actor.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Marco Trevisan (Treviño)
03c4628cad st-drawing-area: Draw content taking care of the resource_scale
https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Jonas Ådahl
9f4ae9618a st-widget: Introduce widget resource scale
This commit makes StWidget manage the scale of which its associated
resources should be multiplied with. The resource scale is calculated
by clutter, and is retrieved by clutter_actor_get_resource_scale(). Due
to the resource scale not always being available, the getter may fail,
and the actual widget that draws the content will have to deal with
this situation.

As the resource scale depends on where on the stage the widget is drawn,
the resource scale will in general be available once the widget is
mapped.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
2019-03-01 17:12:52 +00:00
Kukuh Syafaat
3590af15bb Update Indonesian translation 2019-03-01 15:32:29 +00:00
Ask Hjorth Larsen
c5de7fd20e Updated Danish translation 2019-02-28 23:09:39 +01:00
Robert Mader
7127fb1fa1 gvc: Update submodule to up-to-date version
This frees us from all remaining '‘g_type_class_add_private’ is deprecated'
warnings.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/427
2019-02-28 21:59:08 +01:00
Florian Müllner
7cf11abefc build: Bump gjs requirement
While we don't actually require a more recent version at build time,
we do need the latest stable version at runtime. There's no strong
reason for making that differentiation, so bump the requirement.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1006
2019-02-28 19:43:45 +01:00
Marco Trevisan (Treviño)
d78b416e1a lookingGlass: Use symbolic icon for close button
As per commit 4d2dce2c, the actual close button is generated using custom css
and a symbolic icon.

Apply the same change to lookingGlass too.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/425
2019-02-28 16:21:38 +01:00
Марко Костић
f5144ec899 Update Serbian translation 2019-02-28 13:26:19 +00:00
Milo Casagrande
08d1ebe7ee Update Italian translation 2019-02-28 08:14:02 +00:00
Julien Humbert
a665801e9f Update French translation 2019-02-28 07:39:24 +00:00
Changwoo Ryu
112e3b110b Update Korean translation 2019-02-28 03:16:35 +00:00
Robert Mader
94a674c008 na-tray-manager: Use gdk_screen_get_default() and gdk_x11_get_default_screen()
instead of explicit screen arguments and `gdk_screen_get_number()`, as nowadays there
is always only one screen. This silences some deprecation warnings and removes
deprecated API.

Bonus: some code style cleanups

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/422
2019-02-27 00:35:04 +01:00
Florian Müllner
72be8eeb31 ci: Use custom image for JS checks
Running dnf to update and install additional packages every time
the job is executed slows down the CI pipeline. Avoid this by
using another custom images for JS source checks.

In addition to the js shell we use for the existing syntax check,
also include eslint for future jobs and some extension-specific
tooling to make the image more useful to extension authors.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/408
2019-02-26 21:08:17 +00:00
Florian Müllner
ad8690bb2e ci: Check that pot file is generated correctly
This is to guard against the now infamous xgettext bug[0].

[0] https://savannah.gnu.org/bugs/?50920#comment5

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/408
2019-02-26 21:08:17 +00:00
Florian Müllner
76cb08a72a ci: Add test stage
We never gained a proper test suite, but run at least the tests we
have.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/408
2019-02-26 21:08:17 +00:00
Florian Müllner
2d4989e937 ci: Add build stage
So far we are only performing a basic syntax check on javascript
sources; it's time to test the C code as well. As mutter is tightly
coupled, we bite the bullet and build it as well, either using a
matching branch (if it exists), or current master.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/408
2019-02-26 21:08:17 +00:00
Florian Müllner
f248b91f82 ci: Skip source_check stage when appropriate
We don't have to run the static analyzer on javascript sources when
no javascript source was changed.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/408
2019-02-26 21:08:17 +00:00
Florian Müllner
d671eb1969 ci: Sync check-commit-log script with mutter
A couple of cleanups came out from the review in mutter, catch
up with those.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/408
2019-02-26 21:08:17 +00:00
Florian Müllner
70f4906ca5 aggregateLayout: Fix natural width computation
Ouch, this went unnoticed for a long time: As the minimum size of menu
items is generally small (because its label can be ellipsized), we are
requesting the unellipsized width of the last "size child" instead of
the widest one.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/996
2019-02-26 08:25:00 +00:00
Florian Müllner
ffb9aa1ace test-theme: Stop using ClutterCairoTexture
It's deprecated, so use one of our own types for testing type
inheritance.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/420
2019-02-26 03:04:00 +01:00
Robert Mader
823fd855cf na-tray-child: Silence some deprecation warnings
Use `gdk_x11_display_error_trap_...` instead of `gdk_error_trap_...`

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/417
2019-02-26 01:37:54 +01:00
Robert Mader
f5ee225362 shell-tray-icon: Silence some deprecation warnings
Use `gdk_x11_display_error_trap_...` instead of `gdk_error_trap_...`

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/417
2019-02-26 01:37:46 +01:00
Andrea Azzarone
ff1ea4b1c9 st-clipboard: Remove get/set_property functions.
Remove st_clipboard_get_property and st_clipboard_set_property because they are
identical to the default implementation.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/414
2019-02-26 00:23:36 +00:00
Alex Monday
779b5afa51 theme: Add bottom padding for sub menus
Prevents overlapping sub menu borders with menu item background.

Closes https://gitlab.gnome.org/GNOME/gnome-shell/issues/987
2019-02-25 11:35:13 +01:00
Stas Solovey
6d870f6ae4 Update Russian translation 2019-02-24 20:48:43 +00:00
Asier Sarasua Garmendia
d3926cbca9 Update Basque translation 2019-02-23 20:43:56 +00:00
Carmen Bianca BAKKER
a308804679 Update Esperanto translation 2019-02-23 09:23:49 +00:00
103 changed files with 15231 additions and 10890 deletions

View File

@@ -1,9 +1,18 @@
stages:
- review
- source_check
- build
- test
variables:
JS_LOG: "js-report.txt"
POT_LOG: "pot-update.txt"
.only_default: &only_default
only:
- branches
- tags
- merge_requests
check_commit_log:
image: registry.fedoraproject.org/fedora:latest
@@ -16,17 +25,64 @@ check_commit_log:
- merge_requests
js_check:
image: registry.fedoraproject.org/fedora:latest
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: source_check
before_script:
- dnf install -y findutils mozjs60-devel
script:
- find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
- (! grep -q . $JS_LOG)
<<: *only_default
only:
changes:
- js/**/*
artifacts:
paths:
- ${JS_LOG}
when: on_failure
only:
- merge_requests
- /^.*$/
build:
image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
stage: build
before_script:
- .gitlab-ci/checkout-mutter.sh
- meson mutter mutter/build --prefix=/usr -Dtests=false
- ninja -C mutter/build install
script:
- meson . build -Dbuiltype=debugoptimized
- ninja -C build
- ninja -C build install
<<: *only_default
artifacts:
expire_in: 1 day
paths:
- mutter
- build
test:
image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
stage: test
before_script:
- ninja -C mutter/build install
script:
- xvfb-run meson test -C build --no-rebuild
<<: *only_default
artifacts:
expire_in: 1 day
paths:
- build/meson-logs/testlog.txt
when: on_failure
test-pot:
image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
stage: test
before_script:
- ninja -C mutter/build install
script:
# Check that pot files are generated correctly:
# https://savannah.gnu.org/bugs/?50920#comment5
- ninja -C build gnome-shell-pot 2>&1 | awk '
BEGIN { start=0; }
start==1 { print $0; }
/gnome-shell-pot/ { start=1; }
' | tee $POT_LOG
- (! grep -q . $POT_LOG)
<<: *only_default

19
.gitlab-ci/Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM registry.gitlab.gnome.org/gnome/mutter/master:v1
RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(copr)' && \
dnf copr enable -y fmuellner/gnome-shell-ci && \
dnf builddep -y gnome-shell --setopt=install_weak_deps=False && \
# bt only exports HAVE_BLUETOOTH to js, rest are outdated build-requires
dnf remove -y gnome-bluetooth-libs-devel dbus-glib-devel \
upower-devel python3-devel && \
# We'll build mutter ourselves
dnf remove -y --noautoremove mutter mutter-devel && \
# Needed for tests
dnf install -y '*/xvfb-run' gdm-lib accountsservice-libs && \
dnf clean all && \
rm -rf /var/cache/dnf

View File

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

View File

@@ -11,9 +11,21 @@ branch_point=$(git merge-base HEAD FETCH_HEAD)
commits=$(git log --format='format:%H' $branch_point..$CI_COMMIT_SHA)
test -z "$commits" && { echo Commit range empty; exit 1; }
if [ -z "$commits" ]; then
echo Commit range empty
exit 1
fi
function commit_message_has_url() {
commit=$1
commit_message=$(git show -s --format='format:%b' $commit)
echo "$commit_message" | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)"
return $?
}
for commit in $commits; do
git show -s --format='format:%b' $commit | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)" ||
{ echo "Missing merge request or issue URL on commit $(echo $commit | cut -c -8)"; exit 1; }
if ! commit_message_has_url $commit; then
echo "Missing merge request or issue URL on commit $(echo $commit | cut -c -8)"
exit 1
fi
done

31
.gitlab-ci/checkout-mutter.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/bash
shell_branch=$(git describe --contains --all HEAD)
mutter_target=
git clone https://gitlab.gnome.org/GNOME/mutter.git
if [ $? -ne 0 ]; then
echo Checkout failed
exit 1
fi
cd mutter
if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
merge_request_remote=${CI_MERGE_REQUEST_SOURCE_PROJECT_URL//gnome-shell/mutter}
merge_request_branch=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
echo Looking for $merge_request_branch on remote ...
if git fetch $merge_request_remote $merge_request_branch >/dev/null 2>&1; then
mutter_target=FETCH_HEAD
fi
fi
if [ -z "$mutter_target" ]; then
mutter_target=$(git branch -r -l $shell_branch)
mutter_target=${mutter_target:-origin/master}
echo Using $mutter_target instead
fi
git checkout $mutter_target

41
NEWS
View File

@@ -1,3 +1,44 @@
3.32.0
======
* Fix sizing issues in on-screen-keyboard emoji panel [Carlos; !439]
* Fix test linker failure on Debian/Ubuntu [Iain; !442]
* Avoid assertion when sizing fallback app icons from CSS [Florian; #1027]
* Fix mis-sized menu arrows after texture cache changes [Florian; !452]
Contributors:
Carlos Garnacho, Iain Lane, Florian Müllner
Translators:
Gábor Kelemen [hu], Victor Ibragimov [tg], Ryuta Fujii [ja], Piotr Drąg [af,
tg], Mart Raudsepp [et]
3.31.92
=======
* Fix visual glitch in submenus [Alex; #987]
* Support fractional scaling [Jonas, Marco; #765011, !5]
* Only consider visible children for :first-child/:last-child [Florian; !312]
* Hide trailing separator in search results [verdre; !311]
* Remember choice in inhibit-shortcuts dialogue [Olivier; !382]
* Don't toggle on-screen keyboard on every focus change [Carlos; !397]
* Fix legacy tray icons not responding to events on wayland [Florian; #191]
* Fix generating French OSK layout [Florian; #997]
* Use borderless round user images [Florian; #811]
* Misc. bug fixes and cleanups [Andrea, Robert, Florian, Marco, Niels,
Benjamin; !414, !417, !420, #996, !408, !422, !425, #1006, !427, !315,
#989, !430, !431, !432, #1015, !429, !423, !419, !434]
Contributors:
Jonas Ådahl, Alan, Andrea Azzarone, Benjamin Berg, Olivier Fourdan,
Carlos Garnacho, Niels De Graef, Robert Mader, Alex Monday, Florian Müllner,
Marco Trevisan (Treviño), verdre
Translators:
Carmen Bianca BAKKER [eo], Asier Sarasua Garmendia [eu], Stas Solovey [ru],
Changwoo Ryu [ko], Julien Humbert [fr], Milo Casagrande [it],
Марко Костић [sr], Ask Hjorth Larsen [da], Kukuh Syafaat [id],
Daniel Șerbănescu [ro], Bernd Homuth [de], Trần Ngọc Quân [vi],
Nathan Follens [nl], Rūdolfs Mazurs [lv], Aurimas Černius [lt]
3.31.91
=======
* Don't close on-screen-keyboard's language menu on hover [Florian; #171]

40
README.mdwn Normal file
View File

@@ -0,0 +1,40 @@
cldr2json
=========
This script converts Unicode CLDR android keyboard layouts to JSON usable by
GNOME Shell.
CLDR keyboard layouts can be found at
<http://www.unicode.org/Public/cldr/latest/keyboards.zip>
Usage
=====
./cldr2json <input file or directory> <output directory>
example:
./cldr2json cldr/keyboards/android/ json_layouts/
Keyboard layout mapping
=======================
Unicode CLDR layout identifiers are language codes, while XKB layout
identifiers are... something else. The mapping between the two currently uses
heuristic based on the layout descriptions, in this order:
- if the CLDR layout description matches an XKB layout description, chose its
XKB identifier
- if one word of the CLDR layout description matches an XKB layout
description, chose its XKB identifier
- if the CLDR layout description matches one word of an XKB layout description,
chose its XKB identifier
That doesn't always work. For instance it fails for "en" language, that should
match "us" XKB identifier. For such cases, there is a mapping in
LOCALE_TO_XKB_OVERRIDES at the top of the script. If you discover a weird
mapping of if you get a "failed to find XKB mapping for <locale>" warning then
please consider adding an override there.

208
cldr2json.py Executable file
View File

@@ -0,0 +1,208 @@
#!/usr/bin/python3
#
# Copyright 2015 Daiki Ueno <dueno@src.gnome.org>
# 2016 Parag Nemade <pnemade@redhat.com>
# 2017 Alan <alan@boum.org>
#
# This program 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.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# 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/>.
import glob
import json
import locale
import logging
import os
import re
import sys
import xml.etree.ElementTree
import gi
gi.require_version('GnomeDesktop', '3.0') # NOQA: E402
from gi.repository import GnomeDesktop
ESCAPE_PATTERN = re.compile(r'\\u\{([0-9A-Fa-f]+?)\}')
ISO_PATTERN = re.compile(r'[A-E]([0-9]+)')
LOCALE_TO_XKB_OVERRIDES = {
'af': 'za',
'en': 'us',
'en-GB': 'uk',
'es-US': 'latam',
'fr-CA': 'ca',
'hi': 'in+bolnagri',
'ky': 'kg',
'nl-BE': 'be',
'zu': None
}
def parse_single_key(value):
def unescape(m):
return chr(int(m.group(1), 16))
value = ESCAPE_PATTERN.sub(unescape, value)
return value
def parse_rows(keymap):
unsorted_rows = {}
for _map in keymap.iter('map'):
value = _map.get('to')
key = [parse_single_key(value)]
iso = _map.get('iso')
if not ISO_PATTERN.match(iso):
sys.stderr.write('invalid ISO key name: %s\n' % iso)
continue
if not iso[0] in unsorted_rows:
unsorted_rows[iso[0]] = []
unsorted_rows[iso[0]].append((int(iso[1:]), key))
# add subkeys
longPress = _map.get('longPress')
if longPress:
for value in longPress.split(' '):
subkey = parse_single_key(value)
key.append(subkey)
rows = []
for k, v in sorted(list(unsorted_rows.items()),
key=lambda x: x[0],
reverse=True):
row = []
for key in sorted(v, key=lambda x: x):
row.append(key[1])
rows.append(row)
return rows
def convert_xml(tree):
root = {}
for xml_keyboard in tree.iter("keyboard"):
locale_full = xml_keyboard.get("locale")
locale, sep, end = locale_full.partition("-t-")
root["locale"] = locale
for xml_name in tree.iter("name"):
name = xml_name.get("value")
root["name"] = name
root["levels"] = []
# parse levels
for index, keymap in enumerate(tree.iter('keyMap')):
# FIXME: heuristics here
modifiers = keymap.get('modifiers')
if not modifiers:
mode = 'default'
modifiers = ''
elif 'shift' in modifiers.split(' '):
mode = 'latched'
modifiers = 'shift'
else:
mode = 'locked'
level = {}
level["level"] = modifiers
level["mode"] = mode
level["rows"] = parse_rows(keymap)
root["levels"].append(level)
return root
def locale_to_xkb(locale, name):
if locale in sorted(LOCALE_TO_XKB_OVERRIDES.keys()):
xkb = LOCALE_TO_XKB_OVERRIDES[locale]
logging.debug("override for %s%s",
locale, xkb)
if xkb:
return xkb
else:
raise KeyError("layout %s explicitely disabled in overrides"
% locale)
xkb_names = sorted(name_to_xkb.keys())
if name in xkb_names:
return name_to_xkb[name]
else:
logging.debug("name %s failed" % name)
for sub_name in name.split(' '):
if sub_name in xkb_names:
xkb = name_to_xkb[sub_name]
logging.debug("dumb mapping failed but match with locale word: "
"%s (%s) → %s (%s)",
locale, name, xkb, sub_name)
return xkb
else:
logging.debug("sub_name failed")
for xkb_name in xkb_names:
for xkb_sub_name in xkb_name.split(' '):
if xkb_sub_name.strip('()') == name:
xkb = name_to_xkb[xkb_name]
logging.debug("dumb mapping failed but match with xkb word: "
"%s (%s) → %s (%s)",
locale, name, xkb, xkb_name)
return xkb
raise KeyError("failed to find XKB mapping for %s" % locale)
def convert_file(source_file, destination_path):
logging.info("Parsing %s", source_file)
itree = xml.etree.ElementTree.ElementTree()
itree.parse(source_file)
root = convert_xml(itree)
try:
xkb_name = locale_to_xkb(root["locale"], root["name"])
except KeyError as e:
logging.warn(e)
return False
destination_file = os.path.join(destination_path, xkb_name + ".json")
with open(destination_file, 'w', encoding="utf-8") as dest_fd:
json.dump(root, dest_fd, ensure_ascii=False, indent=2, sort_keys=True)
logging.debug("written %s", destination_file)
def load_xkb_mappings():
xkb = GnomeDesktop.XkbInfo()
layouts = xkb.get_all_layouts()
name_to_xkb = {}
for layout in layouts:
name = xkb.get_layout_info(layout).display_name
name_to_xkb[name] = layout
return name_to_xkb
locale.setlocale(locale.LC_ALL, "C")
name_to_xkb = load_xkb_mappings()
if __name__ == "__main__":
if "DEBUG" in os.environ:
logging.basicConfig(level=logging.DEBUG)
if len(sys.argv) < 2:
print("supply a CLDR keyboard file")
sys.exit(1)
if len(sys.argv) < 3:
print("supply an output directory")
sys.exit(1)
source = sys.argv[1]
destination = sys.argv[2]
if os.path.isfile(source):
convert_file(source, destination)
elif os.path.isdir(source):
for path in glob.glob(source + "/*-t-k0-android.xml"):
convert_file(path, destination)

View File

@@ -34,6 +34,10 @@
<arg type="u" direction="in" name="action"/>
<arg type="b" direction="out" name="success"/>
</method>
<method name="UngrabAccelerators">
<arg type="au" direction="in" name="action"/>
<arg type="b" direction="out" name="success"/>
</method>
<signal name="AcceleratorActivated">
<arg name="action" type="u"/>
<arg name="parameters" type="a{sv}"/>

View File

@@ -6,6 +6,7 @@
<file>be.json</file>
<file>bg.json</file>
<file>by.json</file>
<file>ca.json</file>
<file>cz.json</file>
<file>de.json</file>
<file>dk.json</file>

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/shell/theme">
<file>automatic-updates-off-symbolic.svg</file>
<file>automatic-updates-on-symbolic.svg</file>
<file>automatic-updates-scheduled-symbolic.svg</file>
<file>calendar-today.svg</file>
<file>checkbox-focused.svg</file>
<file>checkbox-off-focused.svg</file>

599
data/osk-layouts/ca.json Normal file
View File

@@ -0,0 +1,599 @@
{
"levels": [
{
"level": "",
"mode": "default",
"rows": [
[
[
"q"
],
[
"w"
],
[
"e",
"é",
"è",
"ê",
"ë",
"%",
"ę",
"ė",
"ē"
],
[
"r"
],
[
"t"
],
[
"y",
"%",
"ÿ"
],
[
"u",
"ù",
"û",
"%",
"ü",
"ú",
"ū"
],
[
"i",
"î",
"%",
"ï",
"ì",
"í",
"į",
"ī"
],
[
"o",
"ô",
"œ",
"%",
"ö",
"ò",
"ó",
"õ",
"ø",
"ō",
"º"
],
[
"p"
]
],
[
[
"a",
"à",
"â",
"%",
"æ",
"á",
"ä",
"ã",
"å",
"ā",
"ª"
],
[
"s"
],
[
"d"
],
[
"f"
],
[
"g"
],
[
"h"
],
[
"j"
],
[
"k"
],
[
"l"
]
],
[
[
"z"
],
[
"x"
],
[
"c",
"ç",
"ć",
"č"
],
[
"v"
],
[
"b"
],
[
"n"
],
[
"m"
]
],
[
[
","
],
[
" "
],
[
".",
"#",
"!",
",",
"?",
"-",
":",
"'",
"@"
]
]
]
},
{
"level": "shift",
"mode": "latched",
"rows": [
[
[
"Q"
],
[
"W"
],
[
"E",
"É",
"È",
"Ê",
"Ë",
"%",
"Ę",
"Ė",
"Ē"
],
[
"R"
],
[
"T"
],
[
"Y",
"%",
"Ÿ"
],
[
"U",
"Ù",
"Û",
"%",
"Ü",
"Ú",
"Ū"
],
[
"I",
"Î",
"%",
"Ï",
"Ì",
"Í",
"Į",
"Ī"
],
[
"O",
"Ô",
"Œ",
"%",
"Ö",
"Ò",
"Ó",
"Õ",
"Ø",
"Ō",
"º"
],
[
"P"
]
],
[
[
"A",
"À",
"Â",
"%",
"Æ",
"Á",
"Ä",
"Ã",
"Å",
"Ā",
"ª"
],
[
"S"
],
[
"D"
],
[
"F"
],
[
"G"
],
[
"H"
],
[
"J"
],
[
"K"
],
[
"L"
]
],
[
[
"Z"
],
[
"X"
],
[
"C",
"Ç",
"Ć",
"Č"
],
[
"V"
],
[
"B"
],
[
"N"
],
[
"M"
]
],
[
[
","
],
[
" "
],
[
".",
"#",
"!",
",",
"?",
"-",
":",
"'",
"@"
]
]
]
},
{
"level": "opt",
"mode": "locked",
"rows": [
[
[
"1",
"¹",
"½",
"⅓",
"¼",
"⅛"
],
[
"2",
"²",
"⅔"
],
[
"3",
"³",
"¾",
"⅜"
],
[
"4",
"⁴"
],
[
"5",
"⅝"
],
[
"6"
],
[
"7",
"⅞"
],
[
"8"
],
[
"9"
],
[
"0",
"ⁿ",
"∅"
]
],
[
[
"@"
],
[
"#"
],
[
"$",
"¢",
"£",
"€",
"¥",
"₱"
],
[
"%",
"‰"
],
[
"&"
],
[
"-",
"_",
"",
"—",
"·"
],
[
"+",
"±"
],
[
"(",
"<",
"{",
"["
],
[
")",
">",
"}",
"]"
]
],
[
[
"*",
"†",
"‡",
"★"
],
[
"\"",
"“",
"”",
"«",
"»"
],
[
"'",
"",
"",
"",
""
],
[
":"
],
[
";"
],
[
"!",
"¡"
],
[
"?",
"¿"
]
],
[
[
"_"
],
[
"/"
],
[
" "
],
[
","
],
[
".",
"…"
]
]
]
},
{
"level": "opt+shift",
"mode": "locked",
"rows": [
[
[
"~"
],
[
"`"
],
[
"|"
],
[
"•",
"♪",
"♥",
"♠",
"♦",
"♣"
],
[
"√"
],
[
"Π",
"π"
],
[
"÷"
],
[
"×"
],
[
"¶",
"§"
],
[
"∆"
]
],
[
[
"£"
],
[
"¢"
],
[
"€"
],
[
"¥"
],
[
"^",
"↑",
"↓",
"←",
"→"
],
[
"°",
"",
"″"
],
[
"=",
"≠",
"≈",
"∞"
],
[
"{"
],
[
"}"
]
],
[
[
"\\"
],
[
"©"
],
[
"®"
],
[
"™"
],
[
"℅"
],
[
"["
],
[
"]"
]
],
[
[
"<",
"",
"≤",
"«"
],
[
">",
"",
"≥",
"»"
],
[
" "
],
[
","
],
[
".",
"…"
]
]
]
}
],
"locale": "fr-CA",
"name": "French Canada"
}

View File

@@ -6,10 +6,20 @@
"rows": [
[
[
"q"
"a",
"à",
"â",
"%",
"æ",
"á",
"ä",
"ã",
"å",
"ā",
"ª"
],
[
"w"
"z"
],
[
"e",
@@ -71,17 +81,7 @@
],
[
[
"a",
"à",
"â",
"%",
"æ",
"á",
"ä",
"ã",
"å",
"ā",
"ª"
"q"
],
[
"s"
@@ -106,11 +106,14 @@
],
[
"l"
],
[
"m"
]
],
[
[
"z"
"w"
],
[
"x"
@@ -131,7 +134,11 @@
"n"
],
[
"m"
"'",
"",
"",
"",
""
]
],
[
@@ -161,10 +168,20 @@
"rows": [
[
[
"Q"
"A",
"À",
"Â",
"%",
"Æ",
"Á",
"Ä",
"Ã",
"Å",
"Ā",
"ª"
],
[
"W"
"Z"
],
[
"E",
@@ -226,17 +243,7 @@
],
[
[
"A",
"À",
"Â",
"%",
"Æ",
"Á",
"Ä",
"Ã",
"Å",
"Ā",
"ª"
"Q"
],
[
"S"
@@ -261,11 +268,14 @@
],
[
"L"
],
[
"M"
]
],
[
[
"Z"
"W"
],
[
"X"
@@ -286,7 +296,11 @@
"N"
],
[
"M"
"'",
"",
"",
"",
""
]
],
[
@@ -369,10 +383,10 @@
"#"
],
[
"$",
"",
"¢",
"£",
"",
"$",
"¥",
"₱"
],
@@ -511,13 +525,14 @@
"£"
],
[
"¥"
],
[
"$",
"¢"
],
[
""
],
[
"¥"
"¢"
],
[
"^",
@@ -594,6 +609,6 @@
]
}
],
"locale": "fr-CA",
"name": "French Canada"
"locale": "fr",
"name": "French"
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1auto-updates_OFF</title><path d="M11.03,10.074a.125.125,0,0,0-.086.213l1.347,1.35a5.733,5.733,0,0,1-4.238,1.9,5.6,5.6,0,0,1-2.282-.484l-1.11,1.11a7.024,7.024,0,0,0,3.392.875,7.3,7.3,0,0,0,5.3-2.339l1.357,1.36a.125.125,0,0,0,.213-.086L15,10Z" style="fill:#999"/><path d="M12.921,5.9a6.354,6.354,0,0,1,.326,1.863.248.248,0,0,0,.244.244h1a.261.261,0,0,0,.257-.265,7.543,7.543,0,0,0-.677-2.991Z" style="fill:#999"/><path d="M6.286,9.707a.994.994,0,0,0,.715.3H9a1,1,0,0,0,1-1v-2A.994.994,0,0,0,9.7,6.3l2.175-2.175,0,0L12.93,3.067l0,0,1.4-1.4a.25.25,0,0,0,0-.354L13.617.608a.25.25,0,0,0-.354,0L11.772,2.1A6.97,6.97,0,0,0,7.948.961,7.3,7.3,0,0,0,2.651,3.3L1.293,1.94a.125.125,0,0,0-.214.086L1,6l3.971-.074a.125.125,0,0,0,.086-.213L3.71,4.363a5.733,5.733,0,0,1,4.238-1.9,5.523,5.523,0,0,1,2.723.739L7.86,6.011H7a1,1,0,0,0-1,1V7.87L3.291,10.58a6,6,0,0,1-.537-2.346.248.248,0,0,0-.244-.245h-1a.261.261,0,0,0-.257.265A7.329,7.329,0,0,0,2.172,11.7L.608,13.263a.25.25,0,0,0,0,.354l.707.707a.25.25,0,0,0,.354,0l1.4-1.4,0,0,1.056-1.056,0,0Z" style="fill:#999"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1auto-updates_ON</title><rect x="6.001" y="6.011" width="4" height="4" rx="1" ry="1" style="fill:#999"/><path d="M5.057,5.713,3.71,4.362a5.733,5.733,0,0,1,4.238-1.9,5.173,5.173,0,0,1,5.3,5.305.248.248,0,0,0,.244.244h1a.261.261,0,0,0,.257-.265A6.684,6.684,0,0,0,7.948.961,7.3,7.3,0,0,0,2.65,3.3L1.293,1.94a.125.125,0,0,0-.213.086L1,6l3.971-.074A.125.125,0,0,0,5.057,5.713Z" style="fill:#999"/><path d="M11.03,10.074a.125.125,0,0,0-.086.213l1.347,1.35a5.733,5.733,0,0,1-4.238,1.9,5.173,5.173,0,0,1-5.3-5.305.248.248,0,0,0-.244-.245h-1a.261.261,0,0,0-.257.265,6.684,6.684,0,0,0,6.8,6.785,7.3,7.3,0,0,0,5.3-2.339l1.357,1.36a.125.125,0,0,0,.214-.086L15,10Z" style="fill:#999"/></svg>

After

Width:  |  Height:  |  Size: 767 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1update-scheduled_OUTLINE</title><path d="M7.99,15.054A6.7,6.7,0,0,1,1.06,8,6.7,6.7,0,0,1,7.99.954,6.71,6.71,0,0,1,14.948,8,6.71,6.71,0,0,1,7.99,15.054Zm0-12.6A5.2,5.2,0,0,0,2.56,8a5.2,5.2,0,0,0,5.43,5.55A5.215,5.215,0,0,0,13.448,8,5.216,5.216,0,0,0,7.99,2.454Z" style="fill:#999"/><path d="M9.209,10.443,7.2,8.437a.25.25,0,0,1-.073-.177l0-4.01A.25.25,0,0,1,7.379,4h1.25a.25.25,0,0,1,.25.25l0,3.283a.25.25,0,0,0,.073.177l1.5,1.494a.25.25,0,0,1,0,.354l-.883.884A.25.25,0,0,1,9.209,10.443Z" style="fill:#999"/></svg>

After

Width:  |  Height:  |  Size: 603 B

View File

@@ -16,7 +16,7 @@ $link_visited_color: if($variant == 'light', darken($selected_bg_color, 20%), li
$top_hilight: $borders_edge;
$warning_color: #f57900;
$error_color: #cc0000;
$error_color: #ff8080;
$success_color: if($variant == 'light', #33d17a, darken(#33d17a, 10%));
$destructive_color: if($variant == 'light', #e01b24, darken(#e01b24, 10%));

View File

@@ -267,8 +267,7 @@ StScrollBar {
}
.end-session-dialog-logout-icon {
//border: 2px solid #8b8b8b;
border-radius: 5px;
border-radius: 99px;
width: 48px;
height: 48px;
background-size: contain;
@@ -393,7 +392,7 @@ StScrollBar {
.prompt-dialog-error-label {
font-size: 10pt;
color: $error_color;
color: $warning_color;
padding-bottom: 8px;
}
@@ -428,7 +427,7 @@ StScrollBar {
}
.polkit-dialog-user-icon {
border-radius: 5px;
border-radius: 99px;
background-size: contain;
width: 48px;
height: 48px;
@@ -508,6 +507,7 @@ StScrollBar {
.popup-menu-arrow { } //defined globally in the TOP BAR
.popup-sub-menu {
padding-bottom: 1px;
background-color: darken($bg_color,2%);
box-shadow: inset 0 -1px 0px lighten($borders_color,5%);
}
@@ -1031,6 +1031,11 @@ StScrollBar {
-st-icon-style: symbolic;
}
.message-icon-bin > .fallback-window-icon {
width: 1.09em;
height: 1.09em;
}
.message-secondary-bin {
padding: 0 0.82em;;
}
@@ -1138,7 +1143,7 @@ StScrollBar {
.ripple-box:rtl { border-radius: 0 0 0 52px; } // just a simple change to the border radius position
// not really top bar only
.popup-menu-arrow { width: 16px; height: 16px; }
.popup-menu-arrow { icon-size: 1.09em; }
.popup-menu-icon { icon-size: 1.09em; }
//close buttons
@@ -1284,6 +1289,8 @@ StScrollBar {
.search-section-separator { height: 2px; background-color: rgba(255, 255, 255, 0.2); }
.search-section:last-child .search-section-separator { background-color: transparent; }
.list-search-result-content { spacing: 30px; }
.list-search-result-title { color: darken($osd_fg_color,5%); spacing: 12px; }
.list-search-result-description { color: transparentize(darken($osd_fg_color,15%), 0.5); }
@@ -1446,13 +1453,13 @@ StScrollBar {
height: 12px;
background-color: transparent;
border: 2px solid rgba(255, 255, 255, 0.4);
border-radius:12px;
border-radius: 12px;
}
&:hover .page-indicator-icon { border-color: white; }
&:active .page-indicator-icon { border: none; margin: 2px; background-color:#fff; }
&:active .page-indicator-icon { border: none; margin: 2px; background-color: white; }
&:checked .page-indicator-icon,
&:checked:active { background-color: #fff;}
&:checked:active .page-indicator-icon { background-color: white;}
}
.no-frequent-applications-label { @extend %status_text; }
@@ -1754,13 +1761,11 @@ StScrollBar {
/* Auth Dialogs & Screen Shield */
.framed-user-icon {
.user-icon {
background-size: contain;
border: 2px solid $osd_fg_color;
color: $osd_fg_color;
border-radius: 3px;
border-radius: 99px;
&:hover {
border-color: lighten($osd_fg_color,30%);
color: lighten($osd_fg_color,30%);
}
}

View File

@@ -40,6 +40,7 @@ do
done
cat >>$TMP_GRESOURCE_FILE <<EOF
<file>emoji.json</file>
</gresource>
</gresources>
EOF

View File

@@ -481,6 +481,9 @@ var LoginDialog = GObject.registerClass({
this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END });
this._logoBin.connect('resource-scale-changed', () => {
this._updateLogoTexture(this._textureCache, this._logoFile);
});
this.add_child(this._logoBin);
this._updateLogo();
@@ -778,11 +781,12 @@ var LoginDialog = GObject.registerClass({
return;
this._logoBin.destroy_all_children();
if (this._logoFile) {
if (this._logoFile && this._logoBin.resource_scale > 0) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
-1, _LOGO_ICON_HEIGHT,
scaleFactor));
scaleFactor,
this._logoBin.resource_scale));
}
}

View File

@@ -9,6 +9,7 @@
<file>gdm/realmd.js</file>
<file>gdm/util.js</file>
<file>misc/updateManager.js</file>
<file>misc/config.js</file>
<file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file>
@@ -116,9 +117,11 @@
<file>ui/components/networkAgent.js</file>
<file>ui/components/polkitAgent.js</file>
<file>ui/components/telepathyClient.js</file>
<file>ui/components/updates.js</file>
<file>ui/components/keyring.js</file>
<file>ui/status/accessibility.js</file>
<file>ui/status/automaticUpdates.js</file>
<file>ui/status/brightness.js</file>
<file>ui/status/location.js</file>
<file>ui/status/keyboard.js</file>

View File

@@ -1,8 +1,10 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { Clutter, GObject, IBus } = imports.gi;
const { Clutter, GLib, GObject, IBus } = imports.gi;
const Keyboard = imports.ui.status.keyboard;
var HIDE_PANEL_TIME = 50;
var InputMethod = GObject.registerClass(
class InputMethod extends Clutter.InputMethod {
_init() {
@@ -13,6 +15,7 @@ class InputMethod extends Clutter.InputMethod {
this._preeditStr = '';
this._preeditPos = 0;
this._preeditVisible = false;
this._hidePanelId = 0;
this._ibus = IBus.Bus.new_async();
this._ibus.connect('connected', this._onConnected.bind(this));
this._ibus.connect('disconnected', this._clear.bind(this));
@@ -136,6 +139,11 @@ class InputMethod extends Clutter.InputMethod {
this._updateCapabilities();
this._emitRequestSurrounding();
}
if (this._hidePanelId) {
GLib.source_remove(this._hidePanelId);
this._hidePanelId = 0;
}
}
vfunc_focus_out() {
@@ -150,6 +158,12 @@ class InputMethod extends Clutter.InputMethod {
this.set_preedit_text(null, 0);
this._preeditStr = null;
}
this._hidePanelId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, HIDE_PANEL_TIME, () => {
this.set_input_panel_state(Clutter.InputPanelState.OFF);
this._hidePanelId = 0;
return GLib.SOURCE_REMOVE;
});
}
vfunc_reset() {

338
js/misc/updateManager.js Normal file
View File

@@ -0,0 +1,338 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
//
// Copyright (C) 2019 Endless Mobile, Inc.
//
// This is a GNOME Shell component to wrap the interactions over
// D-Bus with the Mogwai system daemon.
//
// Licensed under the GNU General Public License Version 2
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
const { Clutter, Gio, GLib,
GObject, Gtk, NM, Shell, St } = imports.gi;
const NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME = "connection.automatic-updates-notification-time";
const NM_SETTING_ALLOW_DOWNLOADS = 'connection.allow-downloads';
const NM_SETTING_TARIFF_ENABLED = "connection.tariff-enabled";
const SchedulerInterface = '\
<node> \
<interface name="com.endlessm.DownloadManager1.Scheduler"> \
<property name="ActiveEntryCount" type="u" access="read" /> \
<property name="EntryCount" type="u" access="read" /> \
</interface> \
</node>';
const SchedulerProxy = Gio.DBusProxy.makeProxyWrapper(SchedulerInterface);
let _updateManager = null;
function getUpdateManager() {
if (_updateManager == null)
_updateManager = new UpdateManager();
return _updateManager;
}
var State = {
UNKNOWN: 0,
DISCONNECTED: 1,
DISABLED: 2,
IDLE: 3,
SCHEDULED: 4,
DOWNLOADING: 5
};
function stateToIconName(state) {
switch (state) {
case State.UNKNOWN:
case State.DISCONNECTED:
return null;
case State.DISABLED:
return 'resource:///org/gnome/shell/theme/automatic-updates-off-symbolic.svg';
case State.IDLE:
case State.DOWNLOADING:
return 'resource:///org/gnome/shell/theme/automatic-updates-on-symbolic.svg';
case State.SCHEDULED:
return 'resource:///org/gnome/shell/theme/automatic-updates-scheduled-symbolic.svg';
}
return null;
}
var UpdateManager = GObject.registerClass ({
Properties: {
'last-notification-time': GObject.ParamSpec.int('last-notification-time',
'last-notification-time',
'last-notification-time',
GObject.ParamFlags.READWRITE,
null),
'icon': GObject.ParamSpec.object('icon', 'icon', 'icon',
GObject.ParamFlags.READABLE,
Gio.Icon.$gtype),
'state': GObject.ParamSpec.uint('state', 'state', 'state',
GObject.ParamFlags.READABLE,
null),
},
}, class UpdateManager extends GObject.Object {
_init() {
super._init();
this._activeConnection = null;
this._settingChangedSignalId = 0;
this._updateTimeoutId = 0;
this._state = State.UNKNOWN;
NM.Client.new_async(null, this._clientGot.bind(this));
}
_clientGot(obj, result) {
this._client = NM.Client.new_finish(result);
this._client.connect('notify::primary-connection', this._sync.bind(this));
this._client.connect('notify::state', this._sync.bind(this));
// Start retrieving the Mogwai proxy
this._proxy = new SchedulerProxy(Gio.DBus.system,
'com.endlessm.MogwaiSchedule1',
'/com/endlessm/DownloadManager1',
(proxy, error) => {
if (error) {
log(error.message);
return;
}
this._proxy.connect('g-properties-changed',
this._sync.bind(this));
this._updateStatus();
});
this._sync();
}
_sync() {
if (!this._client || !this._proxy)
return;
if (this._updateTimeoutId > 0) {
GLib.source_remove(this._updateTimeoutId);
this._updateTimeoutId = 0;
}
// Intermediate states (connecting or disconnecting) must not trigger
// any kind of state change.
if (this._client.state == NM.State.CONNECTING || this._client.state == NM.State.DISCONNECTING)
return;
// Use a timeout to avoid instantly throwing the notification at
// the user's face, and to avoid a series of unecessary updates
// that happen when NetworkManager is still figuring out details.
this._updateTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT,
2,
() => {
this._updateStatus();
this._updateTimeoutId = 0;
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._updateTimeoutId, '[update] updateStatus');
}
_updateStatus() {
// Update the current active connection. This will connect to the
// NM.SettingUser signal to sync every time someone updates the
// NM_SETTING_ALLOW_DOWNLOADS setting.
this._updateActiveConnection();
let state = this._getState();
if (state != this._state) {
this._state = state;
this.notify('state');
this._updateIcon();
}
}
_updateActiveConnection() {
let currentActiveConnection = this._getActiveConnection();
if (this._activeConnection == currentActiveConnection)
return;
// Disconnect from the previous active connection
if (this._settingChangedSignalId > 0) {
this._activeConnection.disconnect(this._settingChangedSignalId);
this._settingChangedSignalId = 0;
}
this._activeConnection = currentActiveConnection;
// Connect from the current active connection
if (currentActiveConnection)
this._settingChangedSignalId = currentActiveConnection.connect('changed', this._updateStatus.bind(this));
}
_ensureUserSetting(connection) {
let userSetting = connection.get_setting(NM.SettingUser.$gtype);
if (!userSetting) {
userSetting = new NM.SettingUser();
connection.add_setting(userSetting);
}
return userSetting;
}
_getState() {
if (!this._activeConnection)
return State.DISCONNECTED;
let userSetting = this._ensureUserSetting(this._activeConnection);
// We only return true when:
// * Automatic Updates are on
// * A schedule was set
// * Something is being downloaded
let allowDownloadsValue = userSetting.get_data(NM_SETTING_ALLOW_DOWNLOADS);
if (allowDownloadsValue) {
let allowDownloads = (allowDownloadsValue === '1');
if (!allowDownloads)
return State.DISABLED;
} else {
// Guess the default value from the metered state. Only return
// if it's disabled - if it's not, we want to follow the regular
// code paths and fetch the correct state
let connectionSetting = this._activeConnection.get_setting_connection();
if (!connectionSetting)
return State.DISABLED;
let metered = connectionSetting.get_metered();
if (metered == NM.Metered.YES || metered == NM.Metered.GUESS_YES)
return State.DISABLED;
}
// Without the proxy, we can't really know the state
if (!this._proxy)
return State.UNKNOWN;
let scheduleSet = userSetting.get_data(NM_SETTING_TARIFF_ENABLED) === '1';
if (!scheduleSet)
return State.IDLE;
let downloading = this._proxy.ActiveEntryCount > 0;
if (downloading)
return State.DOWNLOADING;
// At this point we're not downloading anything, but something
// might be queued
let downloadsQueued = this._proxy.EntryCount > 0;
if (downloadsQueued)
return State.SCHEDULED;
else
return State.IDLE;
}
_getActiveConnection() {
let activeConnection = this._client.get_primary_connection();
return activeConnection ? activeConnection.get_connection() : null;
}
_updateIcon() {
let state = this._state;
let iconName = stateToIconName(state);
if (iconName) {
let iconFile = Gio.File.new_for_uri(iconName);
this._icon = new Gio.FileIcon({ file: iconFile });
} else {
this._icon = null;
}
this.notify('icon');
}
get state() {
return this._state;
}
get lastNotificationTime() {
let connection = this._getActiveConnection();
if (!connection)
return -1;
let userSetting = connection.get_setting(NM.SettingUser.$gtype);
if (!userSetting)
return -1;
let time = userSetting.get_data(NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME);
return time ? parseInt(time) : -1;
}
set lastNotificationTime(time) {
if (!this._activeConnection)
return;
let userSetting = this._ensureUserSetting(this._activeConnection);
userSetting.set_data(NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME,
'%s'.format(time));
this._activeConnection.commit_changes(true, null);
}
get active() {
return this._active;
}
set active(_active) {
if (this._active == _active)
return;
this._active = _active;
this.notify('active');
}
get icon() {
return this._icon;
}
toggleAutomaticUpdates() {
if (!this._activeConnection)
return;
let userSetting = this._ensureUserSetting(this._activeConnection);
let state = this._getState();
let value;
if (state == State.IDLE ||
state == State.SCHEDULED ||
state == State.DOWNLOADING) {
value = '0';
} else {
value = '1';
}
userSetting.set_data(NM_SETTING_ALLOW_DOWNLOADS, value);
this._activeConnection.commit_changes_async(true, null, (con, res, data) => {
this._activeConnection.commit_changes_finish(res);
this._updateStatus();
});
}
});

View File

@@ -12,7 +12,16 @@ var SPINNER_ANIMATION_DELAY = 1.0;
var Animation = class {
constructor(file, width, height, speed) {
this.actor = new St.Bin();
this.actor.set_size(width, height);
this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('notify::size', this._syncAnimationSize.bind(this));
this.actor.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._speed = speed;
this._isLoaded = false;
@@ -20,10 +29,7 @@ var Animation = class {
this._timeoutId = 0;
this._frame = 0;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = St.TextureCache.get_default().load_sliced_image (file, width, height, scaleFactor,
this._animationsLoaded.bind(this));
this.actor.set_child(this._animations);
this._loadFile(file, width, height);
}
play() {
@@ -47,6 +53,23 @@ var Animation = class {
this._isPlaying = false;
}
_loadFile(file, width, height) {
let [validResourceScale, resourceScale] = this.actor.get_resource_scale();
this._isLoaded = false;
this.actor.destroy_all_children();
if (!validResourceScale)
return;
let texture_cache = St.TextureCache.get_default();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = texture_cache.load_sliced_image(file, width, height,
scaleFactor, resourceScale,
this._animationsLoaded.bind(this));
this.actor.set_child(this._animations);
}
_showFrame(frame) {
let oldFrameActor = this._animations.get_child_at_index(this._frame);
if (oldFrameActor)
@@ -64,15 +87,32 @@ var Animation = class {
return GLib.SOURCE_CONTINUE;
}
_syncAnimationSize() {
if (!this._isLoaded)
return;
let [width, height] = this.actor.get_size();
for (let i = 0; i < this._animations.get_n_children(); ++i)
this._animations.get_child_at_index(i).set_size(width, height);
}
_animationsLoaded() {
this._isLoaded = this._animations.get_n_children() > 0;
this._syncAnimationSize();
if (this._isPlaying)
this.play();
}
_onDestroy() {
this.stop();
let themeContext = St.ThemeContext.get_for_stage(global.stage);
if (this._scaleChangedId)
themeContext.disconnect(this._scaleChangedId);
this._scaleChangedId = 0;
}
};

View File

@@ -746,10 +746,8 @@ var BackgroundManager = class BackgroundManager {
this._container.add_child(backgroundActor);
let monitor = this._layoutManager.monitors[this._monitorIndex];
backgroundActor.set_size(monitor.width, monitor.height);
if (this._controlPosition) {
let monitor = this._layoutManager.monitors[this._monitorIndex];
backgroundActor.set_position(monitor.x, monitor.y);
backgroundActor.lower_bottom();
}

View File

@@ -93,10 +93,10 @@ var AutomountManager = class {
if (!this._session.SessionIsActive)
return;
let sound = global.display.get_sound();
sound.play_from_theme('device-removed-media',
_("External drive disconnected"),
null);
let player = global.display.get_sound_player();
player.play_from_theme('device-removed-media',
_("External drive disconnected"),
null);
}
_onDriveEjectButton(monitor, drive) {

135
js/ui/components/updates.js Normal file
View File

@@ -0,0 +1,135 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
//
// Copyright (C) 2018 Endless Mobile, Inc.
//
// This is a GNOME Shell component to wrap the interactions over
// D-Bus with the Mogwai system daemon.
//
// Licensed under the GNU General Public License Version 2
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
const { Gio, GLib, Shell } = imports.gi;
const UpdateManager = imports.misc.updateManager;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
var UpdateComponent = class {
constructor() {
this._notification = null;
this._state = UpdateManager.State.UNKNOWN;
this._manager = UpdateManager.getUpdateManager();
this._manager.connect('notify::state', this._updateState.bind(this));
this._updateState();
}
enable() {
}
disable() {
}
_updateState() {
let newState = this._manager.state;
if (this._state == newState)
return;
this._updateNotification(newState);
this._state = newState;
}
_updateNotification(newState) {
// Don't notify when starting up
if (this._manager.state == UpdateManager.State.UNKNOWN)
return;
let alreadySentNotification = this._manager.lastNotificationTime != -1;
let wasDisconnected = this._state == UpdateManager.State.DISCONNECTED;
let wasActive = this._state >= UpdateManager.State.IDLE;
let isActive = newState >= UpdateManager.State.IDLE;
// The criteria to notify about the Automatic Updates setting is:
// 1. If the user was disconnected and connects to a new network; or
// 2. If the user was connected and connects to a network with different status;
if ((wasDisconnected && alreadySentNotification) || (!wasDisconnected && isActive == wasActive))
return;
if (this._notification)
this._notification.destroy();
if (newState == UpdateManager.State.DISCONNECTED)
return;
let source = new MessageTray.SystemNotificationSource();
Main.messageTray.add(source);
// Figure out the title, subtitle and icon
let title, subtitle, iconFile;
if (isActive) {
title = _("Automatic updates on");
subtitle = _("Your connection has unlimited data so automatic updates have been turned on.");
iconFile = UpdateManager.stateToIconName(UpdateManager.State.IDLE);
} else {
title = _("Automatic updates are turned off to save your data");
subtitle = _("You will need to choose which updates to apply when on this connection.");
iconFile = UpdateManager.stateToIconName(UpdateManager.State.DISABLED);
}
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(iconFile) });
// Create the notification.
// The first time we notify the user for a given connection,
// we set the urgency to critical so that we make sure the
// user understands how we may be changing their settings.
// On subsequent notifications for the given connection,
// for instance if the user regularly switches between
// metered and unmetered connections, we set the urgency
// to normal so as not to be too obtrusive.
this._notification = new MessageTray.Notification(source, title, subtitle, { gicon: gicon });
this._notification.setUrgency(alreadySentNotification ?
MessageTray.Urgency.NORMAL : MessageTray.Urgency.CRITICAL);
this._notification.setTransient(false);
this._notification.addAction(_("Close"), () => {
this._notification.destroy();
});
this._notification.addAction(_("Change Settings…"), () => {
// FIXME: this requires the Automatic Updates panel in GNOME
// Settings. Going with the Network panel for now…
let app = Shell.AppSystem.get_default().lookup_app('gnome-network-panel.desktop');
Main.overview.hide();
app.activate();
});
source.notify(this._notification);
this._notification.connect('destroy', () => {
this._notification = null;
});
// Now that we first detected this connection, mark it as such
this._manager.lastNotificationTime = GLib.get_real_time();
}
};
var Component = UpdateComponent;

View File

@@ -94,7 +94,9 @@ var CtrlAltTabManager = class CtrlAltTabManager {
if (app)
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
else
icon = textureCache.bind_cairo_surface_property(windows[i], 'icon');
icon = textureCache.bind_cairo_surface_property(windows[i],
'icon',
POPUP_APPICON_SIZE);
}
items.push({ name: windows[i].title,

View File

@@ -379,6 +379,7 @@ 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();
}

View File

@@ -125,6 +125,16 @@ var _Draggable = class _Draggable {
}
_onTouchEvent(actor, event) {
// We only handle touch events here on wayland. On X11
// we do get emulated pointer events, which already works
// for single-touch cases. Besides, the X11 passive touch grab
// set up by Mutter will make us see first the touch events
// and later the pointer events, so it will look like two
// unrelated series of events, we want to avoid double handling
// in these cases.
if (!Meta.is_wayland_compositor())
return Clutter.EVENT_PROPAGATE;
if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE;
@@ -296,6 +306,9 @@ var _Draggable = class _Draggable {
* for the draggable.
*/
startDrag(stageX, stageY, time, sequence, device) {
if (currentDraggable)
return;
if (device == undefined) {
let event = Clutter.get_current_event();
@@ -437,7 +450,8 @@ var _Draggable = class _Draggable {
let [stageX, stageY] = event.get_coords();
// See if the user has moved the mouse enough to trigger a drag
let threshold = St.Settings.get().drag_threshold;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let threshold = St.Settings.get().drag_threshold * scaleFactor;
if (!currentDraggable &&
(Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) {

View File

@@ -1,11 +1,16 @@
const { Clutter, Gio, GObject, Gtk, Meta, Shell } = imports.gi;
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell } = imports.gi;
const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
const PermissionStore = imports.misc.permissionStore;
const WAYLAND_KEYBINDINGS_SCHEMA = 'org.gnome.mutter.wayland.keybindings';
const APP_WHITELIST = ['gnome-control-center.desktop'];
const APP_PERMISSIONS_TABLE = 'gnome';
const APP_PERMISSIONS_ID = 'shortcuts-inhibitor';
const GRANTED = 'GRANTED';
const DENIED = 'DENIED';
var DialogResponse = Meta.InhibitShortcutsDialogResponse;
@@ -43,6 +48,29 @@ var InhibitShortcutsDialog = GObject.registerClass({
Gtk.accelerator_parse(accel));
}
_shouldUsePermStore() {
return this._app && !this._app.is_window_backed();
}
_saveToPermissionStore(grant) {
if (!this._shouldUsePermStore() || this._permStore == null)
return;
let permissions = {};
permissions[this._app.get_id()] = [grant];
let data = GLib.Variant.new('av', {});
this._permStore.SetRemote(APP_PERMISSIONS_TABLE,
true,
APP_PERMISSIONS_ID,
permissions,
data,
(result, error) => {
if (error != null)
log(error.message);
});
}
_buildLayout() {
let name = this._app ? this._app.get_name() : this._window.title;
@@ -64,12 +92,14 @@ var InhibitShortcutsDialog = GObject.registerClass({
this._dialog.addButton({ label: _("Deny"),
action: () => {
this._saveToPermissionStore(DENIED);
this._emitResponse(DialogResponse.DENY);
},
key: Clutter.KEY_Escape });
this._dialog.addButton({ label: _("Allow"),
action: () => {
this._saveToPermissionStore(GRANTED);
this._emitResponse(DialogResponse.ALLOW);
},
default: true });
@@ -81,10 +111,43 @@ var InhibitShortcutsDialog = GObject.registerClass({
}
vfunc_show() {
if (this._app && APP_WHITELIST.indexOf(this._app.get_id()) != -1)
if (this._app && APP_WHITELIST.indexOf(this._app.get_id()) != -1) {
this._emitResponse(DialogResponse.ALLOW);
else
return;
}
if (!this._shouldUsePermStore()) {
this._dialog.open();
return;
}
/* Check with the permission store */
let appId = this._app.get_id();
this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
if (error) {
log(error.message);
this._dialog.open();
return;
}
this._permStore.LookupRemote(APP_PERMISSIONS_TABLE,
APP_PERMISSIONS_ID,
(res, error) => {
if (error) {
this._dialog.open();
log(error.message);
return;
}
let [permissions, data] = res;
if (permissions[appId] === undefined) // Not found
this._dialog.open();
else if (permissions[appId] == GRANTED)
this._emitResponse(DialogResponse.ALLOW);
else
this._emitResponse(DialogResponse.DENY);
});
});
}
vfunc_hide() {

View File

@@ -73,12 +73,9 @@ class AspectContainer extends St.Widget {
box.x1 += Math.floor(diff / 2);
box.x2 -= Math.ceil(diff / 2);
} else {
/* Restrict vertically */
/* Restrict vertically, align to bottom */
let height = box.get_width() / this._ratio;
let diff = box.get_height() - height;
box.y1 += Math.floor(diff / 2);
box.y2 -= Math.floor(diff / 2);
box.y1 = box.y2 - Math.floor(height);
}
}
@@ -884,7 +881,7 @@ var EmojiSelection = class EmojiSelection {
this._pageIndicator.setReactive(false);
let bottomRow = this._createBottomRow();
this.actor.add(bottomRow, { x_fill: true, y_fill: false });
this.actor.add(bottomRow, { expand: true, x_fill: false, y_fill: false });
this._emojiPager.setCurrentPage(0);
}
@@ -973,7 +970,16 @@ var EmojiSelection = class EmojiSelection {
row.appendKey(key.actor);
row.layoutButtons();
return row;
let actor = new AspectContainer({ layout_manager: new Clutter.BinLayout(),
x_expand: true, y_expand: true });
actor.add_child(row);
/* Regular keyboard layouts are 11.5×4 grids, optimize for that
* at the moment. Ideally this should be as wide as the current
* keymap.
*/
actor.setRatio(11.5, 1);
return actor;
}
};
Signals.addSignalMethods(EmojiSelection.prototype);

View File

@@ -146,12 +146,13 @@ var MonitorConstraint = GObject.registerClass({
});
var Monitor = class Monitor {
constructor(index, geometry) {
constructor(index, geometry, geometry_scale) {
this.index = index;
this.x = geometry.x;
this.y = geometry.y;
this.width = geometry.width;
this.height = geometry.height;
this.geometry_scale = geometry_scale;
}
get inFullscreen() {
@@ -159,6 +160,19 @@ var Monitor = class Monitor {
}
};
const UiActor = GObject.registerClass(
class UiActor extends St.Widget {
vfunc_get_preferred_width (forHeight) {
let width = global.stage.width;
return [width, width];
}
vfunc_get_preferred_height (forWidth) {
let height = global.stage.height;
return [height, height];
}
});
const defaultParams = {
trackFullscreen: false,
affectsStruts: false,
@@ -199,12 +213,8 @@ var LayoutManager = GObject.registerClass({
global.stage.no_clear_hint = true;
// Set up stage hierarchy to group all UI actors under one container.
this.uiGroup = new St.Widget({ name: 'uiGroup' });
this.uiGroup = new UiActor({ name: 'uiGroup' });
this.uiGroup.set_flags(Clutter.ActorFlags.NO_LAYOUT);
this.uiGroup.add_constraint(new Clutter.BindConstraint({
source: global.stage,
coordinate: Clutter.BindCoordinate.ALL,
}));
global.stage.remove_actor(global.window_group);
this.uiGroup.add_actor(global.window_group);
@@ -318,7 +328,9 @@ var LayoutManager = GObject.registerClass({
this.monitors = [];
let nMonitors = display.get_n_monitors();
for (let i = 0; i < nMonitors; i++)
this.monitors.push(new Monitor(i, display.get_monitor_geometry(i)));
this.monitors.push(new Monitor(i,
display.get_monitor_geometry(i),
display.get_monitor_scale(i)));
if (nMonitors == 0) {
this.primaryIndex = this.bottomIndex = -1;

View File

@@ -382,6 +382,7 @@ var ObjInspector = class ObjInspector {
}
button = new St.Button({ style_class: 'window-close' });
button.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' }));
button.connect('clicked', this.close.bind(this));
hbox.add(button);
if (typeof(obj) == typeof({})) {

View File

@@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { Atspi, Clutter, Cogl, GDesktopEnums,
const { Atspi, Clutter, GDesktopEnums,
Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
@@ -65,9 +65,7 @@ var MouseSpriteContent = GObject.registerClass({
if (!this._texture)
return;
let color = new Cogl.Color();
color.init_from_4ub(0, 0, 0, 0);
let color = new Clutter.Color();
let textureNode = new Clutter.TextureNode(this._texture,
color,
Clutter.ScalingFilter.NEAREST,

View File

@@ -708,6 +708,12 @@ var Source = class Source {
return this._policy;
}
set policy(policy) {
if (this._policy)
this._policy.destroy();
this._policy = policy;
}
get count() {
return this.notifications.length;
}

View File

@@ -110,9 +110,14 @@ class AppMenu extends PopupMenu.PopupMenu {
});
this._appSystem.connect('installed-changed', () => {
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
this._detailsItem.actor.visible = (sw != null);
this._updateDetailsVisibility();
});
this._updateDetailsVisibility();
}
_updateDetailsVisibility() {
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
this._detailsItem.actor.visible = (sw != null);
}
isEmpty() {
@@ -729,7 +734,7 @@ class AggregateLayout extends Clutter.BoxLayout {
let child = this._sizeChildren[i];
let [childMin, childNat] = child.get_preferred_width(forHeight);
minWidth = Math.max(minWidth, childMin);
natWidth = Math.max(minWidth, childNat);
natWidth = Math.max(natWidth, childNat);
}
return [minWidth, natWidth];
}
@@ -769,10 +774,17 @@ class AggregateMenu extends PanelMenu.Button {
this._nightLight = new imports.ui.status.nightLight.Indicator();
this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
if (Main.sessionMode.components.includes('updates'))
this._automaticUpdates = new imports.ui.status.automaticUpdates.Indicator();
else
this._automaticUpdates = null;
this._indicators.add_child(this._thunderbolt.indicators);
this._indicators.add_child(this._screencast.indicators);
this._indicators.add_child(this._location.indicators);
this._indicators.add_child(this._nightLight.indicators);
if (this._automaticUpdates)
this._indicators.add_child(this._automaticUpdates.indicators);
if (this._network) {
this._indicators.add_child(this._network.indicators);
}
@@ -791,6 +803,8 @@ class AggregateMenu extends PanelMenu.Button {
if (this._network) {
this.menu.addMenuItem(this._network.menu);
}
if (this._automaticUpdates)
this.menu.addMenuItem(this._automaticUpdates.menu);
if (this._bluetooth) {
this.menu.addMenuItem(this._bluetooth.menu);
}

View File

@@ -92,9 +92,11 @@ const _modes = {
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: Config.HAVE_NETWORKMANAGER ?
['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'] :
'keyring', 'autorunManager', 'automountManager',
'updates'] :
['polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'],
'keyring', 'autorunManager', 'automountManager',
'updates'],
panel: {
left: ['activities', 'appMenu'],

View File

@@ -124,13 +124,20 @@ var GnomeShell = class {
UngrabAcceleratorAsync(params, invocation) {
let [action] = params;
let grabbedBy = this._grabbedAccelerators.get(action);
if (invocation.get_sender() != grabbedBy)
return invocation.return_value(GLib.Variant.new('(b)', [false]));
let sender = invocation.get_sender();
let ungrabSucceeded = this._ungrabAcceleratorForSender(action, sender);
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
}
UngrabAcceleratorsAsync(params, invocation) {
let [actions] = params;
let sender = invocation.get_sender();
let ungrabSucceeded = true;
for (let i = 0; i < actions.length; i++)
ungrabSucceeded &= this._ungrabAcceleratorForSender(actions[i], sender);
let ungrabSucceeded = global.display.ungrab_accelerator(action);
if (ungrabSucceeded)
this._grabbedAccelerators.delete(action);
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
}
@@ -174,6 +181,16 @@ var GnomeShell = class {
let ungrabSucceeded = global.display.ungrab_accelerator(action);
if (ungrabSucceeded)
this._grabbedAccelerators.delete(action);
return ungrabSucceeded;
}
_ungrabAcceleratorForSender(action, sender) {
let grabbedBy = this._grabbedAccelerators.get(action);
if (sender != grabbedBy)
return false;
return this._ungrabAccelerator(action);
}
_onGrabberBusNameVanished(connection, name) {

View File

@@ -0,0 +1,144 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
//
// Copyright (C) 2018 Endless Mobile, Inc.
//
// This is a GNOME Shell component to wrap the interactions over
// D-Bus with the Mogwai system daemon.
//
// Licensed under the GNU General Public License Version 2
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
const { Gio, GLib, Shell, St } = imports.gi;
const UpdateManager = imports.misc.updateManager;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME = "connection.automatic-updates-notification-time";
const NM_SETTING_ALLOW_DOWNLOADS = 'connection.allow-downloads';
const NM_SETTING_TARIFF_ENABLED = "connection.tariff-enabled";
const SchedulerInterface = '\
<node> \
<interface name="com.endlessm.DownloadManager1.Scheduler"> \
<property name="ActiveEntryCount" type="u" access="read" /> \
<property name="EntryCount" type="u" access="read" /> \
</interface> \
</node>';
const SchedulerProxy = Gio.DBusProxy.makeProxyWrapper(SchedulerInterface);
var Indicator = class extends PanelMenu.SystemIndicator {
constructor() {
super();
this._indicator = this._addIndicator();
this._indicator.visible = false;
this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
this._toggleItem = this._item.menu.addAction("", this._toggleAutomaticUpdates.bind(this));
this._item.menu.addAction(_("Updates Queue"), () => {
let params = new GLib.Variant('(sava{sv})', [ 'set-mode', [ new GLib.Variant('s', 'updates') ], {} ]);
Gio.DBus.session.call('org.gnome.Software',
'/org/gnome/Software',
'org.gtk.Actions',
'Activate',
params,
null,
Gio.DBusCallFlags.NONE,
5000,
null,
(conn, result) => {
try {
conn.call_finish(result);
} catch (e) {
logError(e, 'Failed to start gnome-software');
}
});
});
this._item.menu.addSettingsAction(_("Set a Schedule"), 'gnome-updates-panel.desktop');
this.menu.addMenuItem(this._item);
this._manager = UpdateManager.getUpdateManager();
this._manager.connect('notify::state', this._updateState.bind(this));
this._updateState();
}
_updateState() {
this._updateStatus();
}
_sessionUpdated() {
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive);
}
_updateStatus() {
// Toggle item name
this._updateItem();
// Icons
let icon = this._getIcon()
this._item.icon.gicon = icon;
this._indicator.gicon = icon;
// Only show the Automatic Updates icon at the bottom bar when it is
// both enabled, and there are updates being downloaded or installed.
this._updateVisibility();
// The status label
this._item.label.text = _("Automatic Updates");
}
_updateItem() {
let state = this._manager.state;
if (state == UpdateManager.State.DISABLED)
this._toggleItem.label.text = _("Turn On");
else
this._toggleItem.label.text = _("Turn Off");
}
_toggleAutomaticUpdates() {
this._manager.toggleAutomaticUpdates();
}
_getIcon() {
let state = this._manager.state;
let iconName = UpdateManager.stateToIconName(state);
if (!iconName)
return null;
let iconFile = Gio.File.new_for_uri(iconName);
let gicon = new Gio.FileIcon({ file: iconFile });
return gicon;
}
_updateVisibility() {
let state = this._manager.state;
this._item.actor.visible = (state != UpdateManager.State.DISCONNECTED);
this._indicator.visible = (state == UpdateManager.State.DOWNLOADING);
}
};

View File

@@ -1236,7 +1236,6 @@ var NMDeviceWireless = class {
}
_dialogClosed() {
this._dialog.destroy();
this._dialog = null;
}

View File

@@ -18,7 +18,7 @@ var Avatar = class {
this._user = user;
params = Params.parse(params, { reactive: false,
iconSize: AVATAR_ICON_SIZE,
styleClass: 'framed-user-icon' });
styleClass: 'user-icon' });
this._iconSize = params.iconSize;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
@@ -46,15 +46,14 @@ var Avatar = class {
if (iconFile) {
let file = Gio.File.new_for_path(iconFile);
this.actor.child = null;
this.actor.style = 'background-image: url("%s");'.format(iconFile);
this.actor.style = `
background-image: url("${iconFile}");
background-size: ${this._iconSize}px`;
} else {
this.actor.style = null;
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
icon_size: this._iconSize });
}
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this.actor.set_size(this._iconSize * scaleFactor, this._iconSize * scaleFactor);
}
};

View File

@@ -101,6 +101,5 @@ var Source = class WindowAttentionSource extends MessageTray.Source {
open() {
Main.activateWindow(this._window);
this.destroy();
}
};

View File

@@ -1,5 +1,5 @@
project('gnome-shell', 'c',
version: '3.31.91',
version: '3.32.0',
meson_version: '>= 0.47.0',
license: 'GPLv2+'
)
@@ -20,10 +20,10 @@ gcr_req = '>= 3.7.5'
gdesktop_req = '>= 3.7.90'
gio_req = '>= 2.56.0'
gi_req = '>= 1.49.1'
gjs_req = '>= 1.47.0'
gjs_req = '>= 1.54.0'
gtk_req = '>= 3.15.0'
json_glib_req = '>= 0.13.2'
mutter_req = '>= 3.31.91'
mutter_req = '>= 3.32.0'
polkit_req = '>= 0.100'
schemas_req = '>= 3.27.90'
startup_req = '>= 0.11'

View File

@@ -52,6 +52,7 @@ js/ui/search.js
js/ui/shellEntry.js
js/ui/shellMountOperation.js
js/ui/status/accessibility.js
js/ui/status/automaticUpdates.js
js/ui/status/bluetooth.js
js/ui/status/brightness.js
js/ui/status/keyboard.js

View File

@@ -330,7 +330,7 @@ msgstr "Netwerkaanmelding"
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
msgid "network-workgroup"
msgstr "netwerk-werkgroep"
msgstr "network-workgroup"
#: js/extensionPrefs/main.js:120
#, javascript-format

794
po/da.po

File diff suppressed because it is too large Load Diff

1026
po/de.po

File diff suppressed because it is too large Load Diff

917
po/eo.po

File diff suppressed because it is too large Load Diff

1067
po/et.po

File diff suppressed because it is too large Load Diff

2110
po/eu.po

File diff suppressed because it is too large Load Diff

987
po/fr.po

File diff suppressed because it is too large Load Diff

765
po/hu.po

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ 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: 2019-02-11 18:01+0000\n"
"POT-Creation-Date: 2019-02-21 18:43+0000\n"
"PO-Revision-Date: 2019-02-14 22:18+0700\n"
"Last-Translator: Kukuh Syafaat <kukuhsyafaat@gnome.org>\n"
"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\n"
@@ -480,7 +480,7 @@ msgstr "Jendela Log Masuk"
#: js/gdm/util.js:337
msgid "Authentication error"
msgstr "Galat otentikasi"
msgstr "Galat autentikasi"
#. We don't show fingerprint messages directly since it's
#. not the main auth service. Instead we use the messages
@@ -748,12 +748,12 @@ msgstr "Tambah ke Favorit"
msgid "Show Details"
msgstr "Tampilkan Rincian"
#: js/ui/appFavorites.js:139
#: js/ui/appFavorites.js:141
#, javascript-format
msgid "%s has been added to your favorites."
msgstr "%s telah ditambahkan ke favorit Anda."
#: js/ui/appFavorites.js:173
#: js/ui/appFavorites.js:175
#, javascript-format
msgid "%s has been removed from your favorites."
msgstr "%s telah dihapus dari favorit Anda."
@@ -791,7 +791,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:38
#: js/ui/calendar.js:40
msgctxt "calendar-no-work"
msgid "06"
msgstr "06"
@@ -801,43 +801,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:67
#: js/ui/calendar.js:69
msgctxt "grid sunday"
msgid "S"
msgstr "M"
#. Translators: Calendar grid abbreviation for Monday
#: js/ui/calendar.js:69
#: js/ui/calendar.js:71
msgctxt "grid monday"
msgid "M"
msgstr "S"
#. Translators: Calendar grid abbreviation for Tuesday
#: js/ui/calendar.js:71
#: js/ui/calendar.js:73
msgctxt "grid tuesday"
msgid "T"
msgstr "S"
#. Translators: Calendar grid abbreviation for Wednesday
#: js/ui/calendar.js:73
#: js/ui/calendar.js:75
msgctxt "grid wednesday"
msgid "W"
msgstr "R"
#. Translators: Calendar grid abbreviation for Thursday
#: js/ui/calendar.js:75
#: js/ui/calendar.js:77
msgctxt "grid thursday"
msgid "T"
msgstr "K"
#. Translators: Calendar grid abbreviation for Friday
#: js/ui/calendar.js:77
#: js/ui/calendar.js:79
msgctxt "grid friday"
msgid "F"
msgstr "J"
#. Translators: Calendar grid abbreviation for Saturday
#: js/ui/calendar.js:79
#: js/ui/calendar.js:81
msgctxt "grid saturday"
msgid "S"
msgstr "S"
@@ -848,7 +848,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:342
#: js/ui/calendar.js:332
msgid "%OB"
msgstr "%OB"
@@ -861,55 +861,55 @@ 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:352
#: js/ui/calendar.js:342
msgid "%OB %Y"
msgstr "%OB %Y"
#: js/ui/calendar.js:409
#: js/ui/calendar.js:399
msgid "Previous month"
msgstr "Bulan sebelumnya"
#: js/ui/calendar.js:420
#: js/ui/calendar.js:410
msgid "Next month"
msgstr "Bulan selanjutnya"
#: js/ui/calendar.js:574
#: js/ui/calendar.js:564
#, no-javascript-format
msgctxt "date day number format"
msgid "%d"
msgstr "%d"
#: js/ui/calendar.js:629
#: js/ui/calendar.js:619
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:697
#: js/ui/calendar.js:687
msgctxt "event list time"
msgid "All Day"
msgstr "Sepanjang Hari"
#: js/ui/calendar.js:829
#: js/ui/calendar.js:819
msgctxt "calendar heading"
msgid "%A, %B %-d"
msgstr "%A, %d %B"
#: js/ui/calendar.js:833
#: js/ui/calendar.js:823
msgctxt "calendar heading"
msgid "%A, %B %-d, %Y"
msgstr "%A, %d %B %Y"
#: js/ui/calendar.js:1056
#: js/ui/calendar.js:1046
msgid "No Notifications"
msgstr "Tak Ada Pemberitahuan"
#: js/ui/calendar.js:1059
#: js/ui/calendar.js:1049
msgid "No Events"
msgstr "Tak Ada Kejadian"
#: js/ui/calendar.js:1085
#: js/ui/calendar.js:1075
msgid "Clear"
msgstr "Bersihkan"
@@ -1045,7 +1045,7 @@ msgstr "Manajer Jaringan"
#: js/ui/components/polkitAgent.js:34
msgid "Authentication Required"
msgstr "Diperlukan Otentikasi"
msgstr "Diperlukan Autentikasi"
#: js/ui/components/polkitAgent.js:62
msgid "Administrator"
@@ -2266,7 +2266,7 @@ msgstr "Sandi tidak boleh kosong"
#: src/shell-polkit-authentication-agent.c:348
msgid "Authentication dialog was dismissed by the user"
msgstr "Dialog otentikasi ditolak oleh pengguna"
msgstr "Dialog autentikasi ditolak oleh pengguna"
#. translators:
#. * The number of sound outputs on a particular device

1506
po/it.po

File diff suppressed because it is too large Load Diff

757
po/ja.po

File diff suppressed because it is too large Load Diff

992
po/ko.po

File diff suppressed because it is too large Load Diff

905
po/lt.po

File diff suppressed because it is too large Load Diff

1554
po/lv.po

File diff suppressed because it is too large Load Diff

1515
po/nl.po

File diff suppressed because it is too large Load Diff

1039
po/ro.po

File diff suppressed because it is too large Load Diff

981
po/ru.po

File diff suppressed because it is too large Load Diff

986
po/sr.po

File diff suppressed because it is too large Load Diff

1909
po/tg.po

File diff suppressed because it is too large Load Diff

1495
po/vi.po

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,16 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* GnomeShellPlugin is the entry point for for GNOME Shell into and out of
* Mutter. By registering itself into Mutter using
* meta_plugin_manager_set_plugin_type(), Mutter will call the vfuncs of the
* plugin at the appropriate time.
*
* The funcions in in GnomeShellPlugin are all just stubs, which just call the
* similar methods in GnomeShellWm.
*/
#include "config.h"
#include <stdlib.h>
@@ -37,72 +47,10 @@
#include "shell-perf-log.h"
#include "shell-wm-private.h"
static void gnome_shell_plugin_start (MetaPlugin *plugin);
static void gnome_shell_plugin_minimize (MetaPlugin *plugin,
MetaWindowActor *actor);
static void gnome_shell_plugin_unminimize (MetaPlugin *plugin,
MetaWindowActor *actor);
static void gnome_shell_plugin_size_changed (MetaPlugin *plugin,
MetaWindowActor *actor);
static void gnome_shell_plugin_size_change (MetaPlugin *plugin,
MetaWindowActor *actor,
MetaSizeChange which_change,
MetaRectangle *old_frame_rect,
MetaRectangle *old_buffer_rect);
static void gnome_shell_plugin_map (MetaPlugin *plugin,
MetaWindowActor *actor);
static void gnome_shell_plugin_destroy (MetaPlugin *plugin,
MetaWindowActor *actor);
static void gnome_shell_plugin_switch_workspace (MetaPlugin *plugin,
gint from,
gint to,
MetaMotionDirection direction);
static void gnome_shell_plugin_kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *actor);
static void gnome_shell_plugin_kill_switch_workspace (MetaPlugin *plugin);
static void gnome_shell_plugin_show_tile_preview (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor);
static void gnome_shell_plugin_hide_tile_preview (MetaPlugin *plugin);
static void gnome_shell_plugin_show_window_menu (MetaPlugin *plugin,
MetaWindow *window,
MetaWindowMenuType menu,
int x,
int y);
static void gnome_shell_plugin_show_window_menu_for_rect (MetaPlugin *plugin,
MetaWindow *window,
MetaWindowMenuType menu,
MetaRectangle *rect);
static gboolean gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
XEvent *event);
static gboolean gnome_shell_plugin_keybinding_filter (MetaPlugin *plugin,
MetaKeyBinding *binding);
static void gnome_shell_plugin_confirm_display_change (MetaPlugin *plugin);
static const MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin);
static MetaCloseDialog * gnome_shell_plugin_create_close_dialog (MetaPlugin *plugin,
MetaWindow *window);
static MetaInhibitShortcutsDialog * gnome_shell_plugin_create_inhibit_shortcuts_dialog (MetaPlugin *plugin,
MetaWindow *window);
#define GNOME_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
#define GNOME_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPlugin))
#define GNOME_SHELL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPluginClass))
#define GNOME_IS_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_SHELL_PLUGIN_TYPE))
#define GNOME_IS_SHELL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_SHELL_PLUGIN))
#define GNOME_SHELL_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPluginClass))
typedef struct _GnomeShellPlugin GnomeShellPlugin;
typedef struct _GnomeShellPluginClass GnomeShellPluginClass;
#define GNOME_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
G_DECLARE_FINAL_TYPE (GnomeShellPlugin, gnome_shell_plugin,
GNOME, SHELL_PLUGIN,
MetaPlugin)
struct _GnomeShellPlugin
{
@@ -116,54 +64,8 @@ struct _GnomeShellPlugin
ShellGlobal *global;
};
struct _GnomeShellPluginClass
{
MetaPluginClass parent_class;
};
GType gnome_shell_plugin_get_type (void);
G_DEFINE_TYPE (GnomeShellPlugin, gnome_shell_plugin, META_TYPE_PLUGIN)
static void
gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
{
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
plugin_class->start = gnome_shell_plugin_start;
plugin_class->map = gnome_shell_plugin_map;
plugin_class->minimize = gnome_shell_plugin_minimize;
plugin_class->unminimize = gnome_shell_plugin_unminimize;
plugin_class->size_changed = gnome_shell_plugin_size_changed;
plugin_class->size_change = gnome_shell_plugin_size_change;
plugin_class->destroy = gnome_shell_plugin_destroy;
plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
plugin_class->kill_window_effects = gnome_shell_plugin_kill_window_effects;
plugin_class->kill_switch_workspace = gnome_shell_plugin_kill_switch_workspace;
plugin_class->show_tile_preview = gnome_shell_plugin_show_tile_preview;
plugin_class->hide_tile_preview = gnome_shell_plugin_hide_tile_preview;
plugin_class->show_window_menu = gnome_shell_plugin_show_window_menu;
plugin_class->show_window_menu_for_rect = gnome_shell_plugin_show_window_menu_for_rect;
plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
plugin_class->keybinding_filter = gnome_shell_plugin_keybinding_filter;
plugin_class->confirm_display_change = gnome_shell_plugin_confirm_display_change;
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
plugin_class->create_inhibit_shortcuts_dialog = gnome_shell_plugin_create_inhibit_shortcuts_dialog;
}
static void
gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
{
}
static gboolean
gnome_shell_plugin_has_swap_event (GnomeShellPlugin *shell_plugin)
{
@@ -416,8 +318,8 @@ gnome_shell_plugin_confirm_display_change (MetaPlugin *plugin)
_shell_wm_confirm_display_change (get_shell_wm ());
}
static const
MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
static const MetaPluginInfo *
gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
{
static const MetaPluginInfo info = {
.name = "GNOME Shell",
@@ -443,3 +345,42 @@ gnome_shell_plugin_create_inhibit_shortcuts_dialog (MetaPlugin *plugin,
{
return _shell_wm_create_inhibit_shortcuts_dialog (get_shell_wm (), window);
}
static void
gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
{
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
plugin_class->start = gnome_shell_plugin_start;
plugin_class->map = gnome_shell_plugin_map;
plugin_class->minimize = gnome_shell_plugin_minimize;
plugin_class->unminimize = gnome_shell_plugin_unminimize;
plugin_class->size_changed = gnome_shell_plugin_size_changed;
plugin_class->size_change = gnome_shell_plugin_size_change;
plugin_class->destroy = gnome_shell_plugin_destroy;
plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
plugin_class->kill_window_effects = gnome_shell_plugin_kill_window_effects;
plugin_class->kill_switch_workspace = gnome_shell_plugin_kill_switch_workspace;
plugin_class->show_tile_preview = gnome_shell_plugin_show_tile_preview;
plugin_class->hide_tile_preview = gnome_shell_plugin_hide_tile_preview;
plugin_class->show_window_menu = gnome_shell_plugin_show_window_menu;
plugin_class->show_window_menu_for_rect = gnome_shell_plugin_show_window_menu_for_rect;
plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
plugin_class->keybinding_filter = gnome_shell_plugin_keybinding_filter;
plugin_class->confirm_display_change = gnome_shell_plugin_confirm_display_change;
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
plugin_class->create_inhibit_shortcuts_dialog = gnome_shell_plugin_create_inhibit_shortcuts_dialog;
}
static void
gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
{
}

View File

@@ -184,7 +184,7 @@ window_backed_app_get_icon (ShellApp *app,
int size)
{
MetaWindow *window = NULL;
ClutterActor *actor;
StWidget *widget;
gint scale;
ShellGlobal *global;
StThemeContext *context;
@@ -204,16 +204,20 @@ window_backed_app_get_icon (ShellApp *app,
if (window == NULL)
{
ClutterActor *actor;
actor = clutter_actor_new ();
g_object_set (actor, "opacity", 0, "width", (float) size, "height", (float) size, NULL);
return actor;
}
actor = st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
G_OBJECT (window),
"icon");
g_object_set (actor, "width", (float) size, "height", (float) size, NULL);
return actor;
widget = st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
G_OBJECT (window),
"icon",
size);
st_widget_add_style_class_name (widget, "fallback-app-icon");
return CLUTTER_ACTOR (widget);
}
/**

View File

@@ -4,6 +4,7 @@
#include "shell-embedded-window-private.h"
#include "shell-global.h"
#include "shell-util.h"
#include <gdk/gdkx.h>
#include <meta/display.h>
@@ -94,6 +95,10 @@ shell_gtk_embed_window_created_cb (MetaDisplay *display,
as a normal window */
clutter_actor_set_opacity (window_actor, 0);
/* Also make sure it (or any of its children) doesn't block
events on wayland */
shell_util_set_hidden_from_pick (window_actor, TRUE);
/* Set an empty input shape on the window so that it can't get
any input. This probably isn't the ideal way to achieve this.
It would probably be better to force the window to go behind

View File

@@ -51,6 +51,10 @@ struct _ShellRecorder {
int stage_width;
int stage_height;
int capture_width;
int capture_height;
float scale;
int pointer_x;
int pointer_y;
@@ -430,10 +434,8 @@ recorder_record_frame (ShellRecorder *recorder,
return;
recorder->last_frame_time = now;
clutter_stage_capture (recorder->stage, paint, &recorder->area,
&captures, &n_captures);
if (n_captures == 0)
if (!clutter_stage_capture (recorder->stage, paint, &recorder->area,
&captures, &n_captures))
return;
if (n_captures == 1)
@@ -443,8 +445,9 @@ recorder_record_frame (ShellRecorder *recorder,
n_captures,
recorder->area.x,
recorder->area.y,
recorder->area.width,
recorder->area.height);
recorder->capture_width,
recorder->capture_height,
recorder->scale);
data = cairo_image_surface_get_data (image);
size = (cairo_image_surface_get_height (image) *
@@ -500,6 +503,11 @@ recorder_update_size (ShellRecorder *recorder)
recorder->area.y = 0;
recorder->area.width = recorder->stage_width;
recorder->area.height = recorder->stage_height;
clutter_stage_get_capture_final_size (recorder->stage, NULL,
&recorder->capture_width,
&recorder->capture_height,
&recorder->scale);
}
}
@@ -618,6 +626,8 @@ recorder_connect_stage_callbacks (ShellRecorder *recorder)
G_CALLBACK (recorder_on_stage_notify_size), recorder);
g_signal_connect (recorder->stage, "notify::height",
G_CALLBACK (recorder_on_stage_notify_size), recorder);
g_signal_connect (recorder->stage, "notify::resource-scale",
G_CALLBACK (recorder_on_stage_notify_size), recorder);
}
static void
@@ -875,6 +885,7 @@ shell_recorder_class_init (ShellRecorderClass *klass)
static void
recorder_pipeline_set_caps (RecorderPipeline *pipeline)
{
ShellRecorder *recorder = pipeline->recorder;
GstCaps *caps;
/* The data is always native-endian xRGB; videoconvert
@@ -887,9 +898,9 @@ recorder_pipeline_set_caps (RecorderPipeline *pipeline)
#else
"format", G_TYPE_STRING, "xRGB",
#endif
"framerate", GST_TYPE_FRACTION, pipeline->recorder->framerate, 1,
"width", G_TYPE_INT, pipeline->recorder->area.width,
"height", G_TYPE_INT, pipeline->recorder->area.height,
"framerate", GST_TYPE_FRACTION, recorder->framerate, 1,
"width", G_TYPE_INT, recorder->capture_width,
"height", G_TYPE_INT, recorder->capture_height,
NULL);
g_object_set (pipeline->src, "caps", caps, NULL);
gst_caps_unref (caps);
@@ -1496,6 +1507,11 @@ shell_recorder_set_area (ShellRecorder *recorder,
recorder->area.height = CLAMP (height,
0, recorder->stage_height - recorder->area.y);
clutter_stage_get_capture_final_size (recorder->stage, &recorder->area,
&recorder->capture_width,
&recorder->capture_height,
&recorder->scale);
/* This breaks the recording but tweaking the GStreamer pipeline a bit
* might make it work, at least if the codec can handle a stream where
* the frame size changes in the middle.

View File

@@ -40,6 +40,13 @@ struct _ShellScreenshotPrivate
gboolean include_frame;
};
typedef enum
{
SHELL_SCREENSHOT_SCREEN,
SHELL_SCREENSHOT_WINDOW,
SHELL_SCREENSHOT_AREA,
} ShellScreenshotMode;
G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
static void
@@ -222,29 +229,32 @@ do_grab_screenshot (ShellScreenshot *screenshot,
int height)
{
ShellScreenshotPrivate *priv = screenshot->priv;
cairo_rectangle_int_t screenshot_rect = { x, y, width, height };
ClutterCapture *captures;
int n_captures;
int i;
clutter_stage_capture (stage, FALSE,
&(cairo_rectangle_int_t) {
.x = x,
.y = y,
.width = width,
.height = height
},
&captures,
&n_captures);
if (n_captures == 0)
if (!clutter_stage_capture (stage, FALSE,
&screenshot_rect,
&captures,
&n_captures))
return;
else if (n_captures == 1)
if (n_captures == 1)
priv->image = cairo_surface_reference (captures[0].image);
else
priv->image = shell_util_composite_capture_images (captures,
n_captures,
x, y,
width, height);
{
float target_scale;
clutter_stage_get_capture_final_size (stage, &screenshot_rect,
&width, &height, &target_scale);
priv->image = shell_util_composite_capture_images (captures,
n_captures,
x, y,
width, height,
target_scale);
}
priv->datetime = g_date_time_new_now_local ();
for (i = 0; i < n_captures; i++)
@@ -253,22 +263,41 @@ do_grab_screenshot (ShellScreenshot *screenshot,
g_free (captures);
}
static gboolean
should_draw_cursor_image (ShellScreenshotMode mode)
{
if (mode == SHELL_SCREENSHOT_WINDOW || !meta_is_wayland_compositor ())
{
g_autoptr (GSettings) settings = g_settings_new (A11Y_APPS_SCHEMA);
if (!g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
return TRUE;
}
return FALSE;
}
static void
_draw_cursor_image (MetaCursorTracker *tracker,
cairo_surface_t *surface,
cairo_rectangle_int_t area)
draw_cursor_image (cairo_surface_t *surface,
cairo_rectangle_int_t area)
{
CoglTexture *texture;
int width, height;
int stride;
guint8 *data;
MetaDisplay *display;
MetaCursorTracker *tracker;
cairo_surface_t *cursor_surface;
cairo_region_t *screenshot_region;
cairo_t *cr;
int x, y;
int xhot, yhot;
double xscale, yscale;
display = shell_global_get_display (shell_global_get ());
tracker = meta_cursor_tracker_get_for_display (display);
texture = meta_cursor_tracker_get_sprite (tracker);
if (!texture)
return;
@@ -294,6 +323,22 @@ _draw_cursor_image (MetaCursorTracker *tracker,
width, height,
stride);
cairo_surface_get_device_scale (surface, &xscale, &yscale);
if (xscale != 1.0 || yscale != 1.0)
{
int monitor;
float monitor_scale;
MetaRectangle cursor_rect = {
.x = x, .y = y, .width = width, .height = height
};
monitor = meta_display_get_monitor_index_for_rect (display, &cursor_rect);
monitor_scale = meta_display_get_monitor_scale (display, monitor);
cairo_surface_set_device_scale (cursor_surface, monitor_scale, monitor_scale);
}
cr = cairo_create (surface);
cairo_set_source_surface (cr,
cursor_surface,
@@ -312,9 +357,7 @@ grab_screenshot (ClutterActor *stage,
GTask *result)
{
MetaDisplay *display;
MetaCursorTracker *tracker;
int width, height;
GSettings *settings;
ShellScreenshot *screenshot = g_task_get_source_object (result);
ShellScreenshotPrivate *priv = screenshot->priv;
GTask *task;
@@ -368,14 +411,8 @@ grab_screenshot (ClutterActor *stage,
priv->screenshot_area.width = width;
priv->screenshot_area.height = height;
settings = g_settings_new (A11Y_APPS_SCHEMA);
if (priv->include_cursor &&
!g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
{
tracker = meta_cursor_tracker_get_for_display (display);
_draw_cursor_image (tracker, priv->image, priv->screenshot_area);
}
g_object_unref (settings);
if (priv->include_cursor)
draw_cursor_image (priv->image, priv->screenshot_area);
g_signal_handlers_disconnect_by_func (stage, grab_screenshot, result);
@@ -412,9 +449,7 @@ grab_window_screenshot (ClutterActor *stage,
ShellScreenshot *screenshot = g_task_get_source_object (result);
ShellScreenshotPrivate *priv = screenshot->priv;
GTask *task;
GSettings *settings;
MetaDisplay *display = shell_global_get_display (priv->global);
MetaCursorTracker *tracker;
MetaWindow *window = meta_display_get_focus_window (display);
ClutterActor *window_actor;
gfloat actor_x, actor_y;
@@ -442,13 +477,19 @@ grab_window_screenshot (ClutterActor *stage,
priv->image = meta_shaped_texture_get_image (stex, &clip);
priv->datetime = g_date_time_new_now_local ();
settings = g_settings_new (A11Y_APPS_SCHEMA);
if (priv->include_cursor && !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
if (priv->include_cursor)
{
tracker = meta_cursor_tracker_get_for_display (display);
_draw_cursor_image (tracker, priv->image, priv->screenshot_area);
if (meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
float resource_scale;
if (!clutter_actor_get_resource_scale (window_actor, &resource_scale))
resource_scale = 1.0f;
cairo_surface_set_device_scale (priv->image, resource_scale, resource_scale);
}
draw_cursor_image (priv->image, priv->screenshot_area);
}
g_object_unref (settings);
g_signal_handlers_disconnect_by_func (stage, grab_window_screenshot, result);
task = g_task_new (screenshot, NULL, on_screenshot_written, result);
@@ -520,6 +561,7 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
{
ClutterActor *stage;
ShellScreenshotPrivate *priv = screenshot->priv;
const char *paint_signal;
GTask *result;
if (priv->filename != NULL) {
@@ -539,13 +581,22 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
g_task_set_source_tag (result, shell_screenshot_screenshot);
priv->filename = g_strdup (filename);
priv->include_cursor = include_cursor;
priv->include_cursor = FALSE;
stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
paint_signal = "actors-painted";
meta_disable_unredirect_for_display (shell_global_get_display (priv->global));
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), result);
if (include_cursor)
{
if (should_draw_cursor_image (SHELL_SCREENSHOT_SCREEN))
priv->include_cursor = TRUE;
else
paint_signal = "paint";
}
g_signal_connect_after (stage, paint_signal, G_CALLBACK (grab_screenshot), result);
clutter_actor_queue_redraw (stage);
}
@@ -634,7 +685,7 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), result);
g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_area_screenshot), result);
clutter_actor_queue_redraw (stage);
}
@@ -713,13 +764,14 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
priv->filename = g_strdup (filename);
priv->include_frame = include_frame;
priv->include_cursor = include_cursor;
priv->include_cursor = include_cursor &&
should_draw_cursor_image (SHELL_SCREENSHOT_WINDOW);
stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_window_screenshot), result);
g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_window_screenshot), result);
clutter_actor_queue_redraw (stage);
}
@@ -787,7 +839,7 @@ shell_screenshot_pick_color (ShellScreenshot *screenshot,
meta_disable_unredirect_for_display (display);
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_pixel), result);
g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_pixel), result);
clutter_actor_queue_redraw (stage);
}

View File

@@ -77,13 +77,13 @@ shell_tray_icon_constructed (GObject *object)
plug_xid = GDK_WINDOW_XID (icon_app_window);
display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket));
gdk_error_trap_push ();
gdk_x11_display_error_trap_push (display);
_NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID");
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid,
_NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL,
&type, &format, &nitems,
&bytes_after, (guchar **)&val);
if (!gdk_error_trap_pop () &&
if (!gdk_x11_display_error_trap_pop (display) &&
result == Success &&
type == XA_CARDINAL &&
nitems == 1)
@@ -190,6 +190,7 @@ shell_tray_icon_click (ShellTrayIcon *icon,
XKeyEvent xkevent;
XButtonEvent xbevent;
XCrossingEvent xcevent;
GdkDisplay *display;
GdkWindow *remote_window;
GdkScreen *screen;
int x_root, y_root;
@@ -201,21 +202,23 @@ shell_tray_icon_click (ShellTrayIcon *icon,
event_type == CLUTTER_KEY_PRESS ||
event_type == CLUTTER_KEY_RELEASE);
gdk_error_trap_push ();
remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
if (remote_window == NULL)
{
g_warning ("shell tray: plug window is gone");
gdk_error_trap_pop_ignored ();
return;
}
xwindow = GDK_WINDOW_XID (remote_window);
xdisplay = GDK_WINDOW_XDISPLAY (remote_window);
display = gdk_x11_lookup_xdisplay (xdisplay);
gdk_x11_display_error_trap_push (display);
xwindow = GDK_WINDOW_XID (remote_window);
screen = gdk_window_get_screen (remote_window);
xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
gdk_window_get_origin (remote_window, &x_root, &y_root);
/* First make the icon believe the pointer is inside it */
xcevent.type = EnterNotify;
xcevent.window = xwindow;
@@ -287,5 +290,5 @@ shell_tray_icon_click (ShellTrayIcon *icon,
xcevent.type = LeaveNotify;
XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent);
gdk_error_trap_pop_ignored ();
gdk_x11_display_error_trap_pop_ignored (display);
}

View File

@@ -212,13 +212,7 @@ void
shell_tray_manager_manage_screen (ShellTrayManager *manager,
StWidget *theme_widget)
{
GdkDisplay *display;
GdkScreen *gdk_screen;
display = gdk_display_get_default ();
gdk_screen = gdk_display_get_default_screen (display);
na_tray_manager_manage_screen (manager->priv->na_manager, gdk_screen);
na_tray_manager_manage_screen (manager->priv->na_manager);
g_signal_connect_object (theme_widget, "style-changed",
G_CALLBACK (shell_tray_manager_style_changed),
@@ -245,8 +239,10 @@ shell_tray_manager_child_on_realize (GtkWidget *widget,
bg_pattern = cairo_pattern_create_rgb (color.red / 255.,
color.green / 255.,
color.blue / 255.);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gdk_window_set_background_pattern (gtk_widget_get_window (widget),
bg_pattern);
G_GNUC_END_IGNORE_DEPRECATIONS
cairo_pattern_destroy (bg_pattern);
}

View File

@@ -3,6 +3,7 @@
#include "config.h"
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
@@ -434,14 +435,23 @@ shell_util_get_content_for_window_actor (MetaWindowActor *window_actor,
cairo_surface_t *surface;
cairo_rectangle_int_t clip;
gfloat actor_x, actor_y;
gfloat resource_scale;
texture = meta_window_actor_get_texture (window_actor);
clutter_actor_get_position (CLUTTER_ACTOR (window_actor), &actor_x, &actor_y);
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (window_actor),
&resource_scale))
{
resource_scale = 1.0;
g_warning ("Actor resource scale is not know at this point, "
"falling back to default 1.0");
}
clip.x = window_rect->x - (gint) actor_x;
clip.y = window_rect->y - (gint) actor_y;
clip.width = window_rect->width;
clip.height = window_rect->height;
clip.width = ceilf (window_rect->width * resource_scale);
clip.height = ceilf (window_rect->height * resource_scale);
surface = meta_shaped_texture_get_image (META_SHAPED_TEXTURE (texture),
&clip);
@@ -462,31 +472,20 @@ shell_util_composite_capture_images (ClutterCapture *captures,
int n_captures,
int x,
int y,
int width,
int height)
int target_width,
int target_height,
float target_scale)
{
int i;
double target_scale;
cairo_format_t format;
cairo_surface_t *image;
cairo_t *cr;
g_assert (n_captures > 0);
target_scale = 0.0;
for (i = 0; i < n_captures; i++)
{
ClutterCapture *capture = &captures[i];
double capture_scale = 1.0;
cairo_surface_get_device_scale (capture->image, &capture_scale, NULL);
target_scale = MAX (target_scale, capture_scale);
}
g_assert (target_scale > 0.0f);
format = cairo_image_surface_get_format (captures[0].image);
image = cairo_image_surface_create (format,
width * target_scale,
height * target_scale);
image = cairo_image_surface_create (format, target_width, target_height);
cairo_surface_set_device_scale (image, target_scale, target_scale);
cr = cairo_create (image);

View File

@@ -53,8 +53,9 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture *captures
int n_captures,
int x,
int y,
int width,
int height);
int target_width,
int target_height,
float target_scale);
void shell_util_check_cloexec_fds (void);

View File

@@ -12,6 +12,7 @@ st_headers = [
'st-generic-accessible.h',
'st-icon.h',
'st-icon-colors.h',
'st-image-content.h',
'st-label.h',
'st-private.h',
'st-scrollable.h',
@@ -66,6 +67,7 @@ st_sources = [
'st-generic-accessible.c',
'st-icon.c',
'st-icon-colors.c',
'st-image-content.c',
'st-label.c',
'st-private.c',
'st-scrollable.c',
@@ -124,6 +126,7 @@ libst = shared_library('st-1.0',
sources: st_gir_sources + st_non_gir_sources,
c_args: st_cflags,
dependencies: [clutter_dep, gtk_dep, croco_dep, x11_dep, m_dep],
build_rpath: mutter_typelibdir,
install_rpath: mutter_typelibdir,
install_dir: pkglibdir,
install: true
@@ -137,9 +140,14 @@ test_theme = executable('test-theme',
sources: 'test-theme.c',
c_args: st_cflags,
dependencies: [clutter_dep, gtk_dep],
build_rpath: mutter_typelibdir,
link_with: libst
)
test('CSS styling support', test_theme,
workdir: meson.current_source_dir()
)
libst_gir = gnome.generate_gir(libst,
sources: st_gir_sources,
nsversion: '1.0',

View File

@@ -58,32 +58,6 @@ static Atom __atom_clip = None;
static Atom __utf8_string = None;
static Atom __atom_targets = None;
static void
st_clipboard_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_clipboard_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_clipboard_dispose (GObject *object)
{
@@ -180,8 +154,6 @@ st_clipboard_class_init (StClipboardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = st_clipboard_get_property;
object_class->set_property = st_clipboard_set_property;
object_class->dispose = st_clipboard_dispose;
object_class->finalize = st_clipboard_finalize;
}

View File

@@ -35,6 +35,7 @@
#include "st-drawing-area.h"
#include <cairo.h>
#include <math.h>
typedef struct _StDrawingAreaPrivate StDrawingAreaPrivate;
struct _StDrawingAreaPrivate {
@@ -84,12 +85,22 @@ st_drawing_area_allocate (ClutterActor *self,
ClutterContent *content = clutter_actor_get_content (self);
ClutterActorBox content_box;
int width, height;
float resource_scale;
if (!st_widget_get_resource_scale (ST_WIDGET (self), &resource_scale))
{
ClutterActorBox empty = CLUTTER_ACTOR_BOX_INIT_ZERO;
clutter_actor_set_allocation (self, &empty, 0);
return;
}
clutter_actor_set_allocation (self, box, flags);
st_theme_node_get_content_box (theme_node, box, &content_box);
width = (int)(0.5 + content_box.x2 - content_box.x1);
height = (int)(0.5 + content_box.y2 - content_box.y1);
clutter_canvas_set_scale_factor (CLUTTER_CANVAS (content), resource_scale);
clutter_canvas_set_size (CLUTTER_CANVAS (content), width, height);
}
@@ -101,6 +112,16 @@ st_drawing_area_style_changed (StWidget *self)
st_drawing_area_queue_repaint (ST_DRAWING_AREA (self));
}
static void
st_drawing_area_resource_scale_changed (StWidget *self)
{
float resource_scale;
ClutterContent *content = clutter_actor_get_content (CLUTTER_ACTOR (self));
if (st_widget_get_resource_scale (ST_WIDGET (self), &resource_scale))
clutter_canvas_set_scale_factor (CLUTTER_CANVAS (content), resource_scale);
}
static void
st_drawing_area_class_init (StDrawingAreaClass *klass)
{
@@ -109,6 +130,7 @@ st_drawing_area_class_init (StDrawingAreaClass *klass)
actor_class->allocate = st_drawing_area_allocate;
widget_class->style_changed = st_drawing_area_style_changed;
widget_class->resource_scale_changed = st_drawing_area_resource_scale_changed;
st_drawing_area_signals[REPAINT] =
g_signal_new ("repaint",
@@ -185,7 +207,7 @@ st_drawing_area_get_surface_size (StDrawingArea *area,
{
StDrawingAreaPrivate *priv;
ClutterContent *content;
float w, h;
float w, h, resource_scale;
g_return_if_fail (ST_IS_DRAWING_AREA (area));
@@ -195,8 +217,18 @@ st_drawing_area_get_surface_size (StDrawingArea *area,
content = clutter_actor_get_content (CLUTTER_ACTOR (area));
clutter_content_get_preferred_size (content, &w, &h);
if (st_widget_get_resource_scale (ST_WIDGET (area), &resource_scale))
{
w /= resource_scale;
h /= resource_scale;
}
else
{
w = h = 0.0f;
}
if (width)
*width = (guint)w;
*width = ceilf (w);
if (height)
*height = (guint)h;
*height = ceilf (h);
}

View File

@@ -210,6 +210,12 @@ st_icon_style_changed (StWidget *widget)
st_icon_update (self);
}
static void
st_icon_resource_scale_changed (StWidget *widget)
{
st_icon_update (ST_ICON (widget));
}
static void
st_icon_class_init (StIconClass *klass)
{
@@ -226,6 +232,7 @@ st_icon_class_init (StIconClass *klass)
actor_class->paint = st_icon_paint;
widget_class->style_changed = st_icon_style_changed;
widget_class->resource_scale_changed = st_icon_resource_scale_changed;
pspec = g_param_spec_object ("gicon",
"GIcon",
@@ -344,6 +351,8 @@ st_icon_finish_update (StIcon *icon)
g_signal_connect_object (priv->icon_texture, "notify::content",
G_CALLBACK (on_content_changed), icon, 0);
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (icon));
}
static void
@@ -366,9 +375,10 @@ st_icon_update (StIcon *icon)
StIconPrivate *priv = icon->priv;
StThemeNode *theme_node;
StTextureCache *cache;
gint scale;
gint paint_scale;
ClutterActor *stage;
StThemeContext *context;
float resource_scale;
if (priv->pending_texture)
{
@@ -378,13 +388,16 @@ st_icon_update (StIcon *icon)
priv->opacity_handler_id = 0;
}
if (!st_widget_get_resource_scale (ST_WIDGET (icon), &resource_scale))
return;
theme_node = st_widget_peek_theme_node (ST_WIDGET (icon));
if (theme_node == NULL)
return;
stage = clutter_actor_get_stage (CLUTTER_ACTOR (icon));
context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage));
g_object_get (context, "scale-factor", &scale, NULL);
g_object_get (context, "scale-factor", &paint_scale, NULL);
cache = st_texture_cache_get_default ();
@@ -393,14 +406,16 @@ st_icon_update (StIcon *icon)
theme_node,
priv->gicon,
priv->icon_size,
scale);
paint_scale,
resource_scale);
if (priv->pending_texture == NULL && priv->fallback_gicon != NULL)
priv->pending_texture = st_texture_cache_load_gicon (cache,
theme_node,
priv->fallback_gicon,
priv->icon_size,
scale);
paint_scale,
resource_scale);
if (priv->pending_texture)
{

191
src/st/st-image-content.c Normal file
View File

@@ -0,0 +1,191 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-image-content.h: A content image with scaling support
*
* Copyright 2019 Canonical, Ltd
*
* This program 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.1 of
* the License, or (at your option) any later version.
*
* 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/>.
*/
#include "st-image-content.h"
struct _StImageContent
{
/*< private >*/
ClutterImage parent_instance;
};
typedef struct _StImageContentPrivate StImageContentPrivate;
struct _StImageContentPrivate
{
int width;
int height;
};
enum
{
PROP_0,
PROP_PREFERRED_WIDTH,
PROP_PREFERRED_HEIGHT,
};
static void clutter_content_interface_init (ClutterContentInterface *iface);
G_DEFINE_TYPE_WITH_CODE (StImageContent, st_image_content, CLUTTER_TYPE_IMAGE,
G_ADD_PRIVATE (StImageContent)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
clutter_content_interface_init))
static void
st_image_content_init (StImageContent *self)
{
}
static void
st_image_content_constructed (GObject *object)
{
StImageContent *self = ST_IMAGE_CONTENT (object);
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
if (priv->width < 0 || priv->height < 0)
g_warning ("StImageContent initialized with invalid preferred size: %dx%d\n",
priv->width, priv->height);
}
static void
st_image_content_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
StImageContent *self = ST_IMAGE_CONTENT (object);
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
switch (prop_id)
{
case PROP_PREFERRED_WIDTH:
g_value_set_int (value, priv->width);
break;
case PROP_PREFERRED_HEIGHT:
g_value_set_int (value, priv->height);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
st_image_content_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
StImageContent *self = ST_IMAGE_CONTENT (object);
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
switch (prop_id)
{
case PROP_PREFERRED_WIDTH:
priv->width = g_value_get_int (value);
break;
case PROP_PREFERRED_HEIGHT:
priv->height = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
st_image_content_class_init (StImageContentClass *klass)
{
GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = st_image_content_constructed;
object_class->get_property = st_image_content_get_property;
object_class->set_property = st_image_content_set_property;
pspec = g_param_spec_int ("preferred-width",
"Preferred Width",
"Preferred Width of the Content when painted",
-1, G_MAXINT, -1,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_PREFERRED_WIDTH, pspec);
pspec = g_param_spec_int ("preferred-height",
"Preferred Height",
"Preferred Height of the Content when painted",
-1, G_MAXINT, -1,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_PREFERRED_HEIGHT, pspec);
}
static gboolean
st_image_content_get_preferred_size (ClutterContent *content,
float *width,
float *height)
{
StImageContent *self = ST_IMAGE_CONTENT (content);
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
ClutterTexture *texture;
texture = clutter_image_get_texture (CLUTTER_IMAGE (content));
if (texture == NULL)
return FALSE;
g_assert_cmpint (priv->width, >, -1);
g_assert_cmpint (priv->height, >, -1);
if (width != NULL)
*width = (float) priv->width;
if (height != NULL)
*height = (float) priv->height;
return TRUE;
}
static void
clutter_content_interface_init (ClutterContentInterface *iface)
{
iface->get_preferred_size = st_image_content_get_preferred_size;
}
/**
* st_image_content_new_with_preferred_size:
* @width: The preferred width to be used when drawing the content
* @height: The preferred width to be used when drawing the content
*
* Creates a new #StImageContent, a simple content for sized images.
*
* Return value: (transfer full): the newly created #StImageContent content
* Use g_object_unref() when done.
*/
ClutterContent *
st_image_content_new_with_preferred_size (int width,
int height)
{
return g_object_new (ST_TYPE_IMAGE_CONTENT,
"preferred-width", width,
"preferred-height", height,
NULL);
}

33
src/st/st-image-content.h Normal file
View File

@@ -0,0 +1,33 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-image-content.h: A content image with scaling support
*
* Copyright 2019 Canonical, Ltd
*
* This program 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.1 of
* the License, or (at your option) any later version.
*
* 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/>.
*/
#ifndef __ST_IMAGE_CONTENT_H__
#define __ST_IMAGE_CONTENT_H__
#include <clutter/clutter.h>
#define ST_TYPE_IMAGE_CONTENT (st_image_content_get_type ())
G_DECLARE_FINAL_TYPE (StImageContent, st_image_content,
ST, IMAGE_CONTENT, ClutterImage)
ClutterContent *st_image_content_new_with_preferred_size (int width,
int height);
#endif /* __ST_IMAGE_CONTENT_H__ */

View File

@@ -197,34 +197,52 @@ st_label_paint (ClutterActor *actor)
if (shadow_spec)
{
ClutterActorBox allocation;
float width, height;
float resource_scale;
clutter_actor_get_allocation_box (priv->label, &allocation);
clutter_actor_box_get_size (&allocation, &width, &height);
if (priv->text_shadow_pipeline == NULL ||
width != priv->shadow_width ||
height != priv->shadow_height)
if (clutter_actor_get_resource_scale (priv->label, &resource_scale))
{
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
ClutterActorBox allocation;
float width, height;
priv->shadow_width = width;
priv->shadow_height = height;
priv->text_shadow_pipeline = _st_create_shadow_pipeline_from_actor (shadow_spec, priv->label);
clutter_actor_get_allocation_box (priv->label, &allocation);
clutter_actor_box_get_size (&allocation, &width, &height);
width *= resource_scale;
height *= resource_scale;
if (priv->text_shadow_pipeline == NULL ||
width != priv->shadow_width ||
height != priv->shadow_height)
{
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
priv->shadow_width = width;
priv->shadow_height = height;
priv->text_shadow_pipeline =
_st_create_shadow_pipeline_from_actor (shadow_spec,
priv->label);
}
if (priv->text_shadow_pipeline != NULL)
_st_paint_shadow_with_opacity (shadow_spec,
cogl_get_draw_framebuffer (),
priv->text_shadow_pipeline,
&allocation,
clutter_actor_get_paint_opacity (priv->label));
}
if (priv->text_shadow_pipeline != NULL)
_st_paint_shadow_with_opacity (shadow_spec,
cogl_get_draw_framebuffer (),
priv->text_shadow_pipeline,
&allocation,
clutter_actor_get_paint_opacity (priv->label));
}
clutter_actor_paint (priv->label);
}
static void
st_label_resource_scale_changed (StWidget *widget)
{
StLabelPrivate *priv = ST_LABEL (widget)->priv;
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
}
static void
st_label_class_init (StLabelClass *klass)
{
@@ -243,6 +261,7 @@ st_label_class_init (StLabelClass *klass)
actor_class->get_preferred_height = st_label_get_preferred_height;
widget_class->style_changed = st_label_style_changed;
widget_class->resource_scale_changed = st_label_resource_scale_changed;
widget_class->get_accessible_type = st_label_accessible_get_type;
pspec = g_param_spec_object ("clutter-text",

View File

@@ -359,7 +359,8 @@ blur_pixels (guchar *pixels_in,
CoglPipeline *
_st_create_shadow_pipeline (StShadow *shadow_spec,
CoglTexture *src_texture)
CoglTexture *src_texture,
float resource_scale)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
@@ -386,7 +387,7 @@ _st_create_shadow_pipeline (StShadow *shadow_spec,
rowstride_in, pixels_in);
pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
shadow_spec->blur,
shadow_spec->blur * resource_scale,
&width_out, &height_out, &rowstride_out);
g_free (pixels_in);
@@ -431,6 +432,7 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
{
ClutterContent *image = NULL;
CoglPipeline *shadow_pipeline = NULL;
float resource_scale;
float width, height;
g_return_val_if_fail (clutter_actor_has_allocation (actor), NULL);
@@ -440,6 +442,12 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
if (width == 0 || height == 0)
return NULL;
if (!clutter_actor_get_resource_scale (actor, &resource_scale))
return NULL;
width = ceilf (width * resource_scale);
height = ceilf (height * resource_scale);
image = clutter_actor_get_content (actor);
if (image && CLUTTER_IS_IMAGE (image))
{
@@ -449,7 +457,8 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
if (texture &&
cogl_texture_get_width (texture) == width &&
cogl_texture_get_height (texture) == height)
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, texture);
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, texture,
resource_scale);
}
if (shadow_pipeline == NULL)
@@ -491,6 +500,7 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
cogl_framebuffer_translate (fb, -x, -y, 0);
cogl_framebuffer_orthographic (fb, 0, 0, width, height, 0, 1.0);
cogl_framebuffer_scale (fb, resource_scale, resource_scale, 1);
clutter_actor_set_opacity_override (actor, 255);
clutter_actor_paint (actor);
@@ -502,7 +512,8 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
cogl_object_unref (fb);
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, buffer);
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, buffer,
resource_scale);
cogl_object_unref (buffer);
}
@@ -528,9 +539,10 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
* the offset.
*/
cairo_pattern_t *
_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
_st_create_shadow_cairo_pattern (StShadow *shadow_spec_in,
cairo_pattern_t *src_pattern)
{
g_autoptr(StShadow) shadow_spec = NULL;
static cairo_user_data_key_t shadow_pattern_user_data;
cairo_t *cr;
cairo_surface_t *src_surface;
@@ -541,9 +553,10 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
gint width_in, height_in, rowstride_in;
gint width_out, height_out, rowstride_out;
cairo_matrix_t shadow_matrix;
double xscale_in, yscale_in;
int i, j;
g_return_val_if_fail (shadow_spec != NULL, NULL);
g_return_val_if_fail (shadow_spec_in != NULL, NULL);
g_return_val_if_fail (src_pattern != NULL, NULL);
if (cairo_pattern_get_surface (src_pattern, &src_surface) != CAIRO_STATUS_SUCCESS)
@@ -556,6 +569,25 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
width_in = cairo_image_surface_get_width (src_surface);
height_in = cairo_image_surface_get_height (src_surface);
cairo_surface_get_device_scale (src_surface, &xscale_in, &yscale_in);
if (xscale_in != 1.0 || yscale_in != 1.0)
{
/* Scale the shadow specifications in a temporary copy so that
* we can work everywhere in absolute surface coordinates */
double scale = (xscale_in + yscale_in) / 2.0;
shadow_spec = st_shadow_new (&shadow_spec_in->color,
shadow_spec_in->xoffset * xscale_in,
shadow_spec_in->yoffset * yscale_in,
shadow_spec_in->blur * scale,
shadow_spec_in->spread * scale,
shadow_spec_in->inset);
}
else
{
shadow_spec = st_shadow_ref (shadow_spec_in);
}
/* We want the output to be a color agnostic alpha mask,
* so we need to strip the color channels from the input
*/
@@ -598,6 +630,7 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
width_out,
height_out,
rowstride_out);
cairo_surface_set_device_scale (surface_out, xscale_in, yscale_in);
cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
pixels_out, (cairo_destroy_func_t) g_free);
@@ -608,6 +641,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
if (shadow_spec->inset)
{
/* Scale the matrix in surface absolute coordinates */
cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
/* For inset shadows, offsets and spread radius have already been
* applied to the original pattern, so all left to do is shift the
* blurred image left, so that it aligns centered under the
@@ -616,6 +652,10 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
cairo_matrix_translate (&shadow_matrix,
(width_out - width_in) / 2.0,
(height_out - height_in) / 2.0);
/* Scale back the matrix in original coordinates */
cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
return dst_pattern;
}
@@ -628,6 +668,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
/* 6. Invert the matrix back */
cairo_matrix_invert (&shadow_matrix);
/* Scale the matrix in surface absolute coordinates */
cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
/* 5. Adjust based on specified offsets */
cairo_matrix_translate (&shadow_matrix,
shadow_spec->xoffset,
@@ -649,6 +692,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
- (width_out - width_in) / 2.0,
- (height_out - height_in) / 2.0);
/* Scale back the matrix in scaled coordinates */
cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
/* 1. Invert the matrix so we can work with it in pattern space
*/
cairo_matrix_invert (&shadow_matrix);

View File

@@ -63,7 +63,8 @@ CoglPipeline * _st_create_texture_pipeline (CoglTexture *src_texture);
/* Helper for widgets which need to draw additional shadows */
CoglPipeline * _st_create_shadow_pipeline (StShadow *shadow_spec,
CoglTexture *src_texture);
CoglTexture *src_texture,
float resource_scale);
CoglPipeline * _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
ClutterActor *actor);
cairo_pattern_t *_st_create_shadow_cairo_pattern (StShadow *shadow_spec,

View File

@@ -110,8 +110,8 @@ st_scroll_view_fade_paint_target (ClutterOffscreenEffect *effect)
*/
fade_area_topleft[0] = content_box.x1 + (verts[0].x - paint_box.x1);
fade_area_topleft[1] = content_box.y1 + (verts[0].y - paint_box.y1);
fade_area_bottomright[0] = content_box.x2 + (verts[3].x - paint_box.x2);
fade_area_bottomright[1] = content_box.y2 + (verts[3].y - paint_box.y2);
fade_area_bottomright[0] = content_box.x2 + (verts[3].x - paint_box.x2) + 1;
fade_area_bottomright[1] = content_box.y2 + (verts[3].y - paint_box.y2) + 1;
g_object_get (ST_SCROLL_VIEW (self->actor),
"hscrollbar-visible", &h_scroll_visible,

View File

@@ -72,6 +72,8 @@ void st_shadow_get_box (StShadow *shadow,
const ClutterActorBox *actor_box,
ClutterActorBox *shadow_box);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (StShadow, st_shadow_unref)
GType st_shadow_helper_get_type (void) G_GNUC_CONST;

View File

@@ -21,10 +21,12 @@
#include "config.h"
#include "st-image-content.h"
#include "st-texture-cache.h"
#include "st-private.h"
#include "st-settings.h"
#include <gtk/gtk.h>
#include <math.h>
#include <string.h>
#include <glib.h>
@@ -284,7 +286,8 @@ typedef struct {
guint width;
guint height;
guint scale;
guint paint_scale;
gfloat resource_scale;
GSList *actors;
GtkIconInfo *icon_info;
@@ -312,7 +315,7 @@ texture_load_data_free (gpointer p)
if (data->actors)
g_slist_free_full (data->actors, (GDestroyNotify) g_object_unref);
g_free (data);
g_slice_free (AsyncTextureLoadData, data);
}
/**
@@ -430,7 +433,8 @@ static GdkPixbuf *
impl_load_pixbuf_file (GFile *file,
int available_width,
int available_height,
int scale,
int paint_scale,
float resource_scale,
GError **error)
{
GdkPixbuf *pixbuf = NULL;
@@ -439,6 +443,7 @@ impl_load_pixbuf_file (GFile *file,
if (g_file_load_contents (file, NULL, &contents, &size, NULL, error))
{
int scale = ceilf (paint_scale * resource_scale);
pixbuf = impl_load_pixbuf_data ((const guchar *) contents, size,
available_width, available_height,
scale,
@@ -463,7 +468,9 @@ load_pixbuf_thread (GTask *result,
g_assert (data != NULL);
g_assert (data->file != NULL);
pixbuf = impl_load_pixbuf_file (data->file, data->width, data->height, data->scale, &error);
pixbuf = impl_load_pixbuf_file (data->file, data->width, data->height,
data->paint_scale, data->resource_scale,
&error);
if (error != NULL)
g_task_return_error (result, error);
@@ -480,12 +487,26 @@ load_pixbuf_async_finish (StTextureCache *cache, GAsyncResult *result, GError **
}
static ClutterContent *
pixbuf_to_clutter_image (GdkPixbuf *pixbuf)
pixbuf_to_st_content_image (GdkPixbuf *pixbuf,
int width,
int height,
int paint_scale,
float resource_scale)
{
ClutterContent *image;
g_autoptr(GError) error = NULL;
image = clutter_image_new ();
if (width < 0)
width = ceilf (gdk_pixbuf_get_width (pixbuf) / resource_scale);
else
width *= paint_scale;
if (height < 0)
height = ceilf (gdk_pixbuf_get_height (pixbuf) / resource_scale);
else
height *= paint_scale;
image = st_image_content_new_with_preferred_size (width, height);
clutter_image_set_data (CLUTTER_IMAGE (image),
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf) ?
@@ -547,7 +568,10 @@ finish_texture_load (AsyncTextureLoadData *data,
if (!g_hash_table_lookup_extended (cache->priv->keyed_cache, data->key,
&orig_key, &value))
{
image = pixbuf_to_clutter_image (pixbuf);
image = pixbuf_to_st_content_image (pixbuf,
data->width, data->height,
data->paint_scale,
data->resource_scale);
if (!image)
goto out;
@@ -561,7 +585,10 @@ finish_texture_load (AsyncTextureLoadData *data,
}
else
{
image = pixbuf_to_clutter_image (pixbuf);
image = pixbuf_to_st_content_image (pixbuf,
data->width, data->height,
data->paint_scale,
data->resource_scale);
if (!image)
goto out;
}
@@ -652,6 +679,7 @@ load_texture_async (StTextureCache *cache,
typedef struct {
StTextureCache *cache;
ClutterActor *actor;
gint size;
GObject *source;
guint notify_signal_id;
gboolean weakref_active;
@@ -672,10 +700,14 @@ st_texture_cache_reset_texture (StTextureCachePropertyBind *bind,
{
g_autoptr(ClutterContent) image = NULL;
g_autoptr(GError) error = NULL;
int size = bind->size;
if (size < 0)
clutter_actor_get_preferred_width (bind->actor, -1, NULL, (float *)&size);
image = clutter_actor_get_content (bind->actor);
if (!image || !CLUTTER_IS_IMAGE (image))
image = clutter_image_new ();
image = st_image_content_new_with_preferred_size (size, size);
else
g_object_ref (image);
@@ -723,7 +755,7 @@ st_texture_cache_free_bind (gpointer data)
StTextureCachePropertyBind *bind = data;
if (bind->weakref_active)
g_object_weak_unref (G_OBJECT (bind->actor), st_texture_cache_bind_weak_notify, bind);
g_free (bind);
g_slice_free (StTextureCachePropertyBind, bind);
}
/**
@@ -739,24 +771,30 @@ st_texture_cache_free_bind (gpointer data)
* If the source object is destroyed, the texture will continue to show the last
* value of the property.
*
* Return value: (transfer none): A new #ClutterActor
* Return value: (transfer none): A new #StWidget
*/
ClutterActor *
StWidget *
st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
GObject *object,
const char *property_name)
const char *property_name,
gint size)
{
ClutterActor *actor;
StWidget *widget;
gchar *notify_key;
StTextureCachePropertyBind *bind;
actor = clutter_actor_new ();
widget = g_object_new (ST_TYPE_WIDGET,
"opacity", 0,
"width", (float)size,
"height", (float)size,
NULL);
bind = g_new0 (StTextureCachePropertyBind, 1);
bind = g_slice_new0 (StTextureCachePropertyBind);
bind->cache = cache;
bind->actor = actor;
bind->actor = CLUTTER_ACTOR (widget);
bind->size = size;
bind->source = object;
g_object_weak_ref (G_OBJECT (actor), st_texture_cache_bind_weak_notify, bind);
g_object_weak_ref (G_OBJECT (widget), st_texture_cache_bind_weak_notify, bind);
bind->weakref_active = TRUE;
st_texture_cache_reset_texture (bind, property_name);
@@ -766,7 +804,7 @@ st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
bind, (GClosureNotify)st_texture_cache_free_bind, 0);
g_free (notify_key);
return actor;
return widget;
}
/**
@@ -849,7 +887,7 @@ ensure_request (StTextureCache *cache,
if (pending == NULL)
{
/* Not cached and no pending request, create it */
*request = g_new0 (AsyncTextureLoadData, 1);
*request = g_slice_new0 (AsyncTextureLoadData);
if (policy != ST_TEXTURE_CACHE_POLICY_NONE)
g_hash_table_insert (cache->priv->outstanding_requests, g_strdup (key), *request);
}
@@ -869,7 +907,8 @@ ensure_request (StTextureCache *cache,
* if the icon must not be recolored
* @icon: the #GIcon to load
* @size: Size of themed
* @scale: Scale factor of display
* @paint_scale: Scale factor of display
* @resource_scale: Resource scale factor
*
* This method returns a new #ClutterActor for a given #GIcon. If the
* icon isn't loaded already, the texture will be filled
@@ -882,12 +921,15 @@ st_texture_cache_load_gicon (StTextureCache *cache,
StThemeNode *theme_node,
GIcon *icon,
gint size,
gint scale)
gint paint_scale,
gfloat resource_scale)
{
AsyncTextureLoadData *request;
ClutterActor *actor;
gint scale;
char *gicon_string;
char *key;
float actor_size;
GtkIconTheme *theme;
GtkIconInfo *info;
StTextureCachePolicy policy;
@@ -916,7 +958,10 @@ st_texture_cache_load_gicon (StTextureCache *cache,
else
lookup_flags |= GTK_ICON_LOOKUP_DIR_LTR;
info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, size, scale, lookup_flags);
scale = ceilf (paint_scale * resource_scale);
info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon,
size, scale,
lookup_flags);
if (info == NULL)
return NULL;
@@ -945,8 +990,8 @@ st_texture_cache_load_gicon (StTextureCache *cache,
g_free (gicon_string);
actor = create_invisible_actor ();
clutter_actor_set_size (actor, size * scale, size * scale);
actor_size = size * paint_scale;
clutter_actor_set_size (actor, actor_size, actor_size);
if (ensure_request (cache, key, policy, &request, actor))
{
/* If there's an outstanding request, we've just added ourselves to it */
@@ -964,7 +1009,8 @@ st_texture_cache_load_gicon (StTextureCache *cache,
request->colors = colors ? st_icon_colors_ref (colors) : NULL;
request->icon_info = info;
request->width = request->height = size;
request->scale = scale;
request->paint_scale = paint_scale;
request->resource_scale = resource_scale;
load_texture_async (cache, request);
}
@@ -973,17 +1019,18 @@ st_texture_cache_load_gicon (StTextureCache *cache,
}
static ClutterActor *
load_from_pixbuf (GdkPixbuf *pixbuf)
load_from_pixbuf (GdkPixbuf *pixbuf,
int paint_scale,
float resource_scale)
{
g_autoptr(ClutterContent) image = NULL;
ClutterActor *actor;
int width = gdk_pixbuf_get_width (pixbuf);
int height = gdk_pixbuf_get_height (pixbuf);
image = pixbuf_to_clutter_image (pixbuf);
image = pixbuf_to_st_content_image (pixbuf, -1, -1, paint_scale, resource_scale);
actor = clutter_actor_new ();
clutter_actor_set_size (actor, width, height);
actor = g_object_new (CLUTTER_TYPE_ACTOR,
"request-mode", CLUTTER_REQUEST_CONTENT_SIZE,
NULL);
clutter_actor_set_content (actor, image);
return actor;
@@ -1041,8 +1088,10 @@ ensure_monitor_for_file (StTextureCache *cache,
typedef struct {
GFile *gfile;
gint grid_width, grid_height;
gint scale_factor;
gint paint_scale;
gfloat resource_scale;
ClutterActor *actor;
GCancellable *cancellable;
GFunc load_callback;
gpointer load_callback_data;
} AsyncImageData;
@@ -1053,7 +1102,18 @@ on_data_destroy (gpointer data)
AsyncImageData *d = (AsyncImageData *)data;
g_object_unref (d->gfile);
g_object_unref (d->actor);
g_free (d);
g_object_unref (d->cancellable);
g_slice_free (AsyncImageData, d);
}
static void
on_sliced_image_actor_destroyed (ClutterActor *actor,
gpointer data)
{
GTask *task = data;
GCancellable *cancellable = g_task_get_cancellable (task);
g_cancellable_cancel (cancellable);
}
static void
@@ -1066,20 +1126,26 @@ on_sliced_image_loaded (GObject *source_object,
GTask *task = G_TASK (res);
GList *list, *pixbufs;
if (g_task_had_error (task))
if (g_task_had_error (task) || g_cancellable_is_cancelled (data->cancellable))
return;
pixbufs = g_task_propagate_pointer (task, NULL);
for (list = pixbufs; list; list = list->next)
{
ClutterActor *actor = load_from_pixbuf (GDK_PIXBUF (list->data));
ClutterActor *actor = load_from_pixbuf (GDK_PIXBUF (list->data),
data->paint_scale,
data->resource_scale);
clutter_actor_hide (actor);
clutter_actor_add_child (data->actor, actor);
}
g_list_free_full (pixbufs, g_object_unref);
g_signal_handlers_disconnect_by_func (data->actor,
on_sliced_image_actor_destroyed,
task);
if (data->load_callback != NULL)
data->load_callback (cache, data->load_callback_data);
}
@@ -1097,9 +1163,9 @@ on_loader_size_prepared (GdkPixbufLoader *loader,
gpointer user_data)
{
AsyncImageData *data = user_data;
gdk_pixbuf_loader_set_size (loader,
width * data->scale_factor,
height * data->scale_factor);
int scale = ceilf (data->paint_scale * data->resource_scale);
gdk_pixbuf_loader_set_size (loader, width * scale, height * scale);
}
static void
@@ -1112,12 +1178,13 @@ load_sliced_image (GTask *result,
GList *res = NULL;
GdkPixbuf *pix;
gint width, height, y, x;
gint scale_factor;
GdkPixbufLoader *loader;
GError *error = NULL;
gchar *buffer = NULL;
gsize length;
g_assert (!cancellable);
g_assert (cancellable);
data = task_data;
g_assert (data);
@@ -1125,7 +1192,7 @@ load_sliced_image (GTask *result,
loader = gdk_pixbuf_loader_new ();
g_signal_connect (loader, "size-prepared", G_CALLBACK (on_loader_size_prepared), data);
if (!g_file_load_contents (data->gfile, NULL, &buffer, &length, NULL, &error))
if (!g_file_load_contents (data->gfile, cancellable, &buffer, &length, NULL, &error))
{
g_warning ("Failed to open sliced image: %s", error->message);
goto out;
@@ -1143,13 +1210,14 @@ load_sliced_image (GTask *result,
pix = gdk_pixbuf_loader_get_pixbuf (loader);
width = gdk_pixbuf_get_width (pix);
height = gdk_pixbuf_get_height (pix);
for (y = 0; y < height; y += data->grid_height * data->scale_factor)
scale_factor = ceilf (data->paint_scale * data->resource_scale);
for (y = 0; y < height; y += data->grid_height * scale_factor)
{
for (x = 0; x < width; x += data->grid_width * data->scale_factor)
for (x = 0; x < width; x += data->grid_width * scale_factor)
{
GdkPixbuf *pixbuf = gdk_pixbuf_new_subpixbuf (pix, x, y,
data->grid_width * data->scale_factor,
data->grid_height * data->scale_factor);
data->grid_width * scale_factor,
data->grid_height * scale_factor);
g_assert (pixbuf != NULL);
res = g_list_append (res, pixbuf);
}
@@ -1170,13 +1238,13 @@ load_sliced_image (GTask *result,
* @file: A #GFile
* @grid_width: Width in pixels
* @grid_height: Height in pixels
* @scale: Scale factor of the display
* @paint_scale: Scale factor of the display
* @load_callback: (scope async) (nullable): Function called when the image is loaded, or %NULL
* @user_data: Data to pass to the load callback
*
* This function reads a single image file which contains multiple images internally.
* The image file will be divided using @grid_width and @grid_height;
* note that the dimensions of the image loaded from @path
* note that the dimensions of the image loaded from @path
* should be a multiple of the specified grid dimensions.
*
* Returns: (transfer none): A new #ClutterActor
@@ -1186,25 +1254,37 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
GFile *file,
gint grid_width,
gint grid_height,
gint scale,
gint paint_scale,
gfloat resource_scale,
GFunc load_callback,
gpointer user_data)
{
AsyncImageData *data;
GTask *result;
ClutterActor *actor = clutter_actor_new ();
GCancellable *cancellable = g_cancellable_new ();
data = g_new0 (AsyncImageData, 1);
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_assert (paint_scale > 0);
g_assert (resource_scale > 0);
data = g_slice_new0 (AsyncImageData);
data->grid_width = grid_width;
data->grid_height = grid_height;
data->scale_factor = scale;
data->paint_scale = paint_scale;
data->resource_scale = resource_scale;
data->gfile = g_object_ref (file);
data->actor = actor;
data->cancellable = cancellable;
data->load_callback = load_callback;
data->load_callback_data = user_data;
g_object_ref (G_OBJECT (actor));
result = g_task_new (cache, NULL, on_sliced_image_loaded, data);
result = g_task_new (cache, cancellable, on_sliced_image_loaded, data);
g_signal_connect (actor, "destroy",
G_CALLBACK (on_sliced_image_actor_destroyed), result);
g_task_set_task_data (result, data, on_data_destroy);
g_task_run_in_thread (result, load_sliced_image);
@@ -1219,7 +1299,8 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
* @file: a #GFile of the image file from which to create a pixbuf
* @available_width: available width for the image, can be -1 if not limited
* @available_height: available height for the image, can be -1 if not limited
* @scale: scale factor of the display
* @paint_scale: scale factor of the display
* @resource_scale: Resource scale factor
*
* Asynchronously load an image. Initially, the returned texture will have a natural
* size of zero. At some later point, either the image will be loaded successfully
@@ -1232,14 +1313,17 @@ st_texture_cache_load_file_async (StTextureCache *cache,
GFile *file,
int available_width,
int available_height,
int scale)
int paint_scale,
gfloat resource_scale)
{
ClutterActor *actor;
AsyncTextureLoadData *request;
StTextureCachePolicy policy;
gchar *key;
int scale;
key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file));
scale = ceilf (paint_scale * resource_scale);
key = g_strdup_printf (CACHE_PREFIX_FILE "%u%d", g_file_hash (file), scale);
policy = ST_TEXTURE_CACHE_POLICY_NONE; /* XXX */
@@ -1261,7 +1345,8 @@ st_texture_cache_load_file_async (StTextureCache *cache,
request->policy = policy;
request->width = available_width;
request->height = available_height;
request->scale = scale;
request->paint_scale = paint_scale;
request->resource_scale = resource_scale;
load_texture_async (cache, request);
}
@@ -1277,7 +1362,8 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
GFile *file,
int available_width,
int available_height,
int scale,
int paint_scale,
gfloat resource_scale,
GError **error)
{
ClutterContent *image;
@@ -1285,18 +1371,21 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
GdkPixbuf *pixbuf;
char *key;
key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file));
key = g_strdup_printf (CACHE_PREFIX_FILE "%u%f", g_file_hash (file), resource_scale);
texdata = NULL;
image = g_hash_table_lookup (cache->priv->keyed_cache, key);
if (image == NULL)
{
pixbuf = impl_load_pixbuf_file (file, available_width, available_height, scale, error);
pixbuf = impl_load_pixbuf_file (file, available_width, available_height,
paint_scale, resource_scale, error);
if (!pixbuf)
goto out;
image = pixbuf_to_clutter_image (pixbuf);
image = pixbuf_to_st_content_image (pixbuf,
available_height, available_width,
paint_scale, resource_scale);
g_object_unref (pixbuf);
if (!image)
@@ -1325,20 +1414,22 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
GFile *file,
int available_width,
int available_height,
int scale,
int paint_scale,
gfloat resource_scale,
GError **error)
{
cairo_surface_t *surface;
GdkPixbuf *pixbuf;
char *key;
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file));
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u%f", g_file_hash (file), resource_scale);
surface = g_hash_table_lookup (cache->priv->keyed_surface_cache, key);
if (surface == NULL)
{
pixbuf = impl_load_pixbuf_file (file, available_width, available_height, scale, error);
pixbuf = impl_load_pixbuf_file (file, available_width, available_height,
paint_scale, resource_scale, error);
if (!pixbuf)
goto out;
@@ -1366,7 +1457,8 @@ out:
* st_texture_cache_load_file_to_cogl_texture: (skip)
* @cache: A #StTextureCache
* @file: A #GFile in supported image format
* @scale: Scale factor of the display
* @paint_scale: Scale factor of the display
* @resource_scale: Resource scale factor
*
* This function synchronously loads the given file path
* into a COGL texture. On error, a warning is emitted
@@ -1377,13 +1469,15 @@ out:
CoglTexture *
st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
GFile *file,
gint scale)
gint paint_scale,
gfloat resource_scale)
{
CoglTexture *texture;
GError *error = NULL;
texture = st_texture_cache_load_file_sync_to_cogl_texture (cache, ST_TEXTURE_CACHE_POLICY_FOREVER,
file, -1, -1, scale, &error);
file, -1, -1, paint_scale, resource_scale,
&error);
if (texture == NULL)
{
@@ -1400,7 +1494,8 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
* st_texture_cache_load_file_to_cairo_surface:
* @cache: A #StTextureCache
* @file: A #GFile in supported image format
* @scale: Scale factor of the display
* @paint_scale: Scale factor of the display
* @resource_scale: Resource scale factor
*
* This function synchronously loads the given file path
* into a cairo surface. On error, a warning is emitted
@@ -1411,13 +1506,15 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
cairo_surface_t *
st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache,
GFile *file,
gint scale)
gint paint_scale,
gfloat resource_scale)
{
cairo_surface_t *surface;
GError *error = NULL;
surface = st_texture_cache_load_file_sync_to_cairo_surface (cache, ST_TEXTURE_CACHE_POLICY_FOREVER,
file, -1, -1, scale, &error);
file, -1, -1, paint_scale, resource_scale,
&error);
if (surface == NULL)
{

View File

@@ -32,6 +32,7 @@
#include <st/st-types.h>
#include <st/st-theme-node.h>
#include <st/st-widget.h>
#define ST_TYPE_TEXTURE_CACHE (st_texture_cache_get_type ())
G_DECLARE_FINAL_TYPE (StTextureCache, st_texture_cache,
@@ -58,33 +59,39 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
GFile *file,
gint grid_width,
gint grid_height,
gint scale,
gint paint_scale,
gfloat resource_scale,
GFunc load_callback,
gpointer user_data);
ClutterActor *st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
GObject *object,
const char *property_name);
StWidget *st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
GObject *object,
const char *property_name,
gint size);
ClutterActor *st_texture_cache_load_gicon (StTextureCache *cache,
StThemeNode *theme_node,
GIcon *icon,
gint size,
gint scale);
gint paint_scale,
gfloat resource_scale);
ClutterActor *st_texture_cache_load_file_async (StTextureCache *cache,
GFile *file,
int available_width,
int available_height,
int scale);
int paint_scale,
gfloat resource_scale);
CoglTexture *st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
GFile *file,
gint scale);
gint paint_scale,
gfloat resource_scale);
cairo_surface_t *st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache,
GFile *file,
gint scale);
gint paint_scale,
gfloat resource_scale);
/**
* StTextureCacheLoader: (skip)

View File

@@ -48,6 +48,7 @@ typedef struct {
guint radius;
guint border_width_1;
guint border_width_2;
float resource_scale;
} StCornerSpec;
static void
@@ -78,10 +79,13 @@ create_corner_material (StCornerSpec *corner)
guint rowstride;
guint8 *data;
guint size;
guint logical_size;
guint max_border_width;
double device_scaling;
max_border_width = MAX(corner->border_width_2, corner->border_width_1);
size = 2 * MAX(max_border_width, corner->radius);
logical_size = 2 * MAX(max_border_width, corner->radius);
size = ceilf (logical_size * corner->resource_scale);
rowstride = size * 4;
data = g_new0 (guint8, size * rowstride);
@@ -89,9 +93,11 @@ create_corner_material (StCornerSpec *corner)
CAIRO_FORMAT_ARGB32,
size, size,
rowstride);
device_scaling = (double) size / logical_size;
cairo_surface_set_device_scale (surface, device_scaling, device_scaling);
cr = cairo_create (surface);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_scale (cr, size, size);
cairo_scale (cr, logical_size, logical_size);
if (max_border_width <= corner->radius)
{
@@ -189,13 +195,14 @@ create_corner_material (StCornerSpec *corner)
static char *
corner_to_string (StCornerSpec *corner)
{
return g_strdup_printf ("st-theme-node-corner:%02x%02x%02x%02x,%02x%02x%02x%02x,%02x%02x%02x%02x,%u,%u,%u",
return g_strdup_printf ("st-theme-node-corner:%02x%02x%02x%02x,%02x%02x%02x%02x,%02x%02x%02x%02x,%u,%u,%u,%.4f",
corner->color.red, corner->color.blue, corner->color.green, corner->color.alpha,
corner->border_color_1.red, corner->border_color_1.green, corner->border_color_1.blue, corner->border_color_1.alpha,
corner->border_color_2.red, corner->border_color_2.green, corner->border_color_2.blue, corner->border_color_2.alpha,
corner->radius,
corner->border_width_1,
corner->border_width_2);
corner->border_width_2,
corner->resource_scale);
}
static CoglTexture *
@@ -352,6 +359,7 @@ static CoglPipeline *
st_theme_node_lookup_corner (StThemeNode *node,
float width,
float height,
float resource_scale,
StCorner corner_id)
{
CoglTexture *texture = NULL;
@@ -370,6 +378,7 @@ st_theme_node_lookup_corner (StThemeNode *node,
corner.radius = radius[corner_id];
corner.color = node->background_color;
corner.resource_scale = resource_scale;
st_theme_node_get_corner_border_widths (node, corner_id,
&corner.border_width_1,
&corner.border_width_2);
@@ -431,7 +440,7 @@ get_background_scale (StThemeNode *node,
switch (node->background_size)
{
case ST_BACKGROUND_SIZE_AUTO:
*scale_w = 1.0;
*scale_w = 1.0f;
break;
case ST_BACKGROUND_SIZE_CONTAIN:
*scale_w = MIN (painting_area_width / background_image_width,
@@ -485,6 +494,7 @@ get_background_coordinates (StThemeNode *node,
static void
get_background_position (StThemeNode *self,
const ClutterActorBox *allocation,
float resource_scale,
ClutterActorBox *result,
ClutterActorBox *texture_coords)
{
@@ -497,6 +507,9 @@ get_background_position (StThemeNode *self,
background_image_width = cogl_texture_get_width (self->background_texture);
background_image_height = cogl_texture_get_height (self->background_texture);
background_image_width /= resource_scale;
background_image_height /= resource_scale;
/* get the painting area size */
painting_area_width = allocation->x2 - allocation->x1;
painting_area_height = allocation->y2 - allocation->y1;
@@ -506,6 +519,7 @@ get_background_position (StThemeNode *self,
painting_area_width, painting_area_height,
background_image_width, background_image_height,
&scale_w, &scale_h);
background_image_width *= scale_w;
background_image_height *= scale_h;
@@ -615,6 +629,7 @@ static cairo_pattern_t *
create_cairo_pattern_of_background_image (StThemeNode *node,
float width,
float height,
float resource_scale,
gboolean *needs_background_fill)
{
cairo_surface_t *surface;
@@ -635,7 +650,9 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
texture_cache = st_texture_cache_get_default ();
g_object_get (node->context, "scale-factor", &scale_factor, NULL);
surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file, scale_factor);
surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file,
scale_factor,
resource_scale);
if (surface == NULL)
return NULL;
@@ -652,12 +669,22 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
cairo_matrix_init_identity (&matrix);
if (resource_scale != 1.0)
{
background_image_width /= resource_scale;
background_image_height /= resource_scale;
cairo_matrix_scale (&matrix, resource_scale, resource_scale);
}
get_background_scale (node,
width, height,
background_image_width, background_image_height,
&scale_w, &scale_h);
if ((scale_w != 1) || (scale_h != 1))
cairo_matrix_scale (&matrix, 1.0/scale_w, 1.0/scale_h);
background_image_width *= scale_w;
background_image_height *= scale_h;
@@ -742,6 +769,7 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
{
cairo_surface_t *surface;
int width, height;
double xscale, yscale;
cairo_matrix_t matrix;
cairo_save (cr);
@@ -758,11 +786,13 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
/* Something went wrong previously */
goto no_surface;
cairo_surface_get_device_scale (surface, &xscale, &yscale);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
cairo_pattern_get_matrix (pattern, &matrix);
cairo_matrix_invert (&matrix);
cairo_matrix_scale (&matrix, 1.0 / xscale, 1.0 / yscale);
cairo_transform (cr, &matrix);
cairo_rectangle (cr, 0, height, width, - height);
@@ -786,7 +816,8 @@ paint_background_image_shadow_to_cairo_context (StThemeNode *node,
int x,
int y,
int width,
int height)
int height,
float resource_scale)
{
cairo_pattern_t *shadow_pattern;
@@ -802,7 +833,10 @@ paint_background_image_shadow_to_cairo_context (StThemeNode *node,
/* Prerender the pattern to a temporary surface,
* so it's properly clipped before we create a shadow from it
*/
width = ceilf (width * resource_scale);
height = ceilf (height * resource_scale);
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cairo_surface_set_device_scale (clipped_surface, resource_scale, resource_scale);
temp_cr = cairo_create (clipped_surface);
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
@@ -866,6 +900,7 @@ path_extents (cairo_path_t *path,
static void
paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
StShadow *shadow_spec,
float resource_scale,
cairo_t *cr,
cairo_path_t *shadow_outline)
{
@@ -906,8 +941,8 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
/* Bounds of temporary surface */
int surface_x = floor (shrunk_extents_x1);
int surface_y = floor (shrunk_extents_y1);
int surface_width = ceil (shrunk_extents_x2) - surface_x;
int surface_height = ceil (shrunk_extents_y2) - surface_y;
int surface_width = ceil ((shrunk_extents_x2 - surface_x) * resource_scale);
int surface_height = ceil ((shrunk_extents_y2 - surface_y) * resource_scale);
/* Center of the original path */
double x_center = (extents_x1 + extents_x2) / 2;
@@ -918,6 +953,7 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
cairo_matrix_t matrix;
shadow_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, surface_width, surface_height);
cairo_surface_set_device_scale (shadow_surface, resource_scale, resource_scale);
temp_cr = cairo_create (shadow_surface);
/* Match the coordinates in the temporary context to the parent context */
@@ -966,7 +1002,8 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
static CoglTexture *
st_theme_node_prerender_background (StThemeNode *node,
float actor_width,
float actor_height)
float actor_height,
float resource_scale)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
@@ -994,6 +1031,8 @@ st_theme_node_prerender_background (StThemeNode *node,
ClutterActorBox paint_box;
cairo_path_t *interior_path = NULL;
float width, height;
int texture_width;
int texture_height;
border_image = st_theme_node_get_border_image (node);
@@ -1021,8 +1060,11 @@ st_theme_node_prerender_background (StThemeNode *node,
width = paint_box.x2 - paint_box.x1;
height = paint_box.y2 - paint_box.y1;
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
data = g_new0 (guchar, height * rowstride);
texture_width = ceilf (width * resource_scale);
texture_height = ceilf (height * resource_scale);
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, texture_width);
data = g_new0 (guchar, texture_height * rowstride);
/* We zero initialize the destination memory, so it's fully transparent
* by default.
@@ -1031,8 +1073,9 @@ st_theme_node_prerender_background (StThemeNode *node,
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
width, height,
texture_width, texture_height,
rowstride);
cairo_surface_set_device_scale (surface, resource_scale, resource_scale);
cr = cairo_create (surface);
/* TODO - support non-uniform border colors */
@@ -1070,7 +1113,9 @@ st_theme_node_prerender_background (StThemeNode *node,
if (background_image != NULL)
{
pattern = create_cairo_pattern_of_background_image (node, width, height,
pattern = create_cairo_pattern_of_background_image (node,
width, height,
resource_scale,
&draw_solid_background);
if (shadow_spec && pattern != NULL)
draw_background_image_shadow = TRUE;
@@ -1258,7 +1303,8 @@ st_theme_node_prerender_background (StThemeNode *node,
has_visible_outline? outline_path : NULL,
actor_box.x1,
actor_box.y1,
width, height);
width, height,
resource_scale);
cairo_append_path (cr, outline_path);
}
@@ -1275,6 +1321,7 @@ st_theme_node_prerender_background (StThemeNode *node,
{
paint_inset_box_shadow_to_cairo_context (node,
box_shadow_spec,
resource_scale,
cr,
interior_path ? interior_path
: outline_path);
@@ -1286,7 +1333,9 @@ st_theme_node_prerender_background (StThemeNode *node,
if (interior_path != NULL)
cairo_path_destroy (interior_path);
texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width, height,
texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx,
texture_width,
texture_height,
CLUTTER_CAIRO_FORMAT_ARGB32,
rowstride,
data,
@@ -1318,7 +1367,8 @@ st_theme_node_invalidate_border_image (StThemeNode *node)
}
static gboolean
st_theme_node_load_border_image (StThemeNode *node)
st_theme_node_load_border_image (StThemeNode *node,
gfloat resource_scale)
{
if (node->border_slices_texture == NULL)
{
@@ -1335,7 +1385,8 @@ st_theme_node_load_border_image (StThemeNode *node)
g_object_get (node->context, "scale-factor", &scale_factor, NULL);
node->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (),
file, scale_factor);
file, scale_factor,
resource_scale);
if (node->border_slices_texture == NULL)
goto out;
@@ -1355,7 +1406,8 @@ st_theme_node_invalidate_background_image (StThemeNode *node)
}
static gboolean
st_theme_node_load_background_image (StThemeNode *node)
st_theme_node_load_background_image (StThemeNode *node,
gfloat resource_scale)
{
if (node->background_texture == NULL)
{
@@ -1371,7 +1423,8 @@ st_theme_node_load_background_image (StThemeNode *node)
background_image_shadow_spec = st_theme_node_get_background_image_shadow (node);
node->background_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (),
background_image, scale_factor);
background_image, scale_factor,
resource_scale);
if (node->background_texture == NULL)
goto out;
@@ -1384,7 +1437,8 @@ st_theme_node_load_background_image (StThemeNode *node)
if (background_image_shadow_spec)
{
node->background_shadow_pipeline = _st_create_shadow_pipeline (background_image_shadow_spec,
node->background_texture);
node->background_texture,
resource_scale);
}
}
@@ -1424,7 +1478,8 @@ static void
st_theme_node_render_resources (StThemeNodePaintState *state,
StThemeNode *node,
float width,
float height)
float height,
float resource_scale)
{
gboolean has_border;
gboolean has_border_radius;
@@ -1443,6 +1498,7 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
st_theme_node_paint_state_set_node (state, node);
state->alloc_width = width;
state->alloc_height = height;
state->resource_scale = resource_scale;
_st_theme_node_ensure_background (node);
_st_theme_node_ensure_geometry (node);
@@ -1488,13 +1544,13 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
}
state->corner_material[ST_CORNER_TOPLEFT] =
st_theme_node_lookup_corner (node, width, height, ST_CORNER_TOPLEFT);
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_TOPLEFT);
state->corner_material[ST_CORNER_TOPRIGHT] =
st_theme_node_lookup_corner (node, width, height, ST_CORNER_TOPRIGHT);
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_TOPRIGHT);
state->corner_material[ST_CORNER_BOTTOMRIGHT] =
st_theme_node_lookup_corner (node, width, height, ST_CORNER_BOTTOMRIGHT);
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_BOTTOMRIGHT);
state->corner_material[ST_CORNER_BOTTOMLEFT] =
st_theme_node_lookup_corner (node, width, height, ST_CORNER_BOTTOMLEFT);
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_BOTTOMLEFT);
/* Use cairo to prerender the node if there is a gradient, or
* background image with borders and/or rounded corners,
@@ -1509,7 +1565,8 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
|| (has_inset_box_shadow && (has_border || node->background_color.alpha > 0))
|| (st_theme_node_get_background_image (node) && (has_border || has_border_radius))
|| has_large_corners)
state->prerendered_texture = st_theme_node_prerender_background (node, width, height);
state->prerendered_texture = st_theme_node_prerender_background (node, width, height,
resource_scale);
if (state->prerendered_texture)
state->prerendered_pipeline = _st_create_texture_pipeline (state->prerendered_texture);
@@ -1518,12 +1575,14 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
if (box_shadow_spec && !has_inset_box_shadow)
{
if (st_theme_node_load_border_image (node))
if (st_theme_node_load_border_image (node, resource_scale))
state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec,
node->border_slices_texture);
node->border_slices_texture,
state->resource_scale);
else if (state->prerendered_texture != NULL)
state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec,
state->prerendered_texture);
state->prerendered_texture,
state->resource_scale);
else if (node->background_color.alpha > 0 || has_border)
st_theme_node_prerender_shadow (state);
}
@@ -1546,7 +1605,8 @@ static void
st_theme_node_update_resources (StThemeNodePaintState *state,
StThemeNode *node,
float width,
float height)
float height,
float resource_scale)
{
gboolean had_prerendered_texture = FALSE;
gboolean had_box_shadow = FALSE;
@@ -1573,12 +1633,13 @@ st_theme_node_update_resources (StThemeNodePaintState *state,
st_theme_node_paint_state_set_node (state, node);
state->alloc_width = width;
state->alloc_height = height;
state->resource_scale = resource_scale;
box_shadow_spec = st_theme_node_get_box_shadow (node);
if (had_prerendered_texture)
{
state->prerendered_texture = st_theme_node_prerender_background (node, width, height);
state->prerendered_texture = st_theme_node_prerender_background (node, width, height, resource_scale);
state->prerendered_pipeline = _st_create_texture_pipeline (state->prerendered_texture);
}
else
@@ -1588,12 +1649,13 @@ st_theme_node_update_resources (StThemeNodePaintState *state,
for (corner_id = 0; corner_id < 4; corner_id++)
if (state->corner_material[corner_id] == NULL)
state->corner_material[corner_id] =
st_theme_node_lookup_corner (node, width, height, corner_id);
st_theme_node_lookup_corner (node, width, height, resource_scale, corner_id);
}
if (had_box_shadow)
state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec,
state->prerendered_texture);
state->prerendered_texture,
state->resource_scale);
}
static void
@@ -2223,6 +2285,7 @@ st_theme_node_prerender_shadow (StThemeNodePaintState *state)
guint border_radius[4];
int max_borders[4];
int center_radius, corner_id;
int fb_width, fb_height;
CoglTexture *buffer;
CoglFramebuffer *offscreen = NULL;
CoglError *error = NULL;
@@ -2264,9 +2327,9 @@ st_theme_node_prerender_shadow (StThemeNodePaintState *state)
}
/* Render offscreen */
buffer = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
state->box_shadow_width,
state->box_shadow_height));
fb_width = ceilf (state->box_shadow_width * state->resource_scale);
fb_height = ceilf (state->box_shadow_height * state->resource_scale);
buffer = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, fb_width, fb_height));
if (buffer == NULL)
return;
@@ -2277,14 +2340,16 @@ st_theme_node_prerender_shadow (StThemeNodePaintState *state)
ClutterActorBox box = { 0, 0, state->box_shadow_width, state->box_shadow_height};
cogl_framebuffer_orthographic (offscreen, 0, 0,
state->box_shadow_width,
state->box_shadow_height, 0, 1.0);
fb_width, fb_height, 0, 1.0);
cogl_framebuffer_scale (offscreen,
state->resource_scale,
state->resource_scale, 1);
cogl_framebuffer_clear4f (offscreen, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 0);
st_theme_node_paint_borders (state, offscreen, &box, 0xFF);
state->box_shadow_pipeline = _st_create_shadow_pipeline (st_theme_node_get_box_shadow (node),
buffer);
buffer, state->resource_scale);
}
else
{
@@ -2457,11 +2522,16 @@ static gboolean
st_theme_node_needs_new_box_shadow_for_size (StThemeNodePaintState *state,
StThemeNode *node,
float width,
float height)
float height,
float resource_scale)
{
if (!node->rendered_once)
return TRUE;
/* The resource scale changed, so need to recompute a new box-shadow */
if (fabsf (state->resource_scale - resource_scale) > FLT_EPSILON)
return TRUE;
/* The allocation hasn't changed, no need to recompute a new
box-shadow. */
if (state->alloc_width == width &&
@@ -2495,7 +2565,8 @@ st_theme_node_paint (StThemeNode *node,
StThemeNodePaintState *state,
CoglFramebuffer *framebuffer,
const ClutterActorBox *box,
guint8 paint_opacity)
guint8 paint_opacity,
float resource_scale)
{
float width, height;
ClutterActorBox allocation;
@@ -2507,7 +2578,7 @@ st_theme_node_paint (StThemeNode *node,
allocation.x2 = width;
allocation.y2 = height;
if (width <= 0 || height <= 0)
if (width <= 0 || height <= 0 || resource_scale <= 0.0f)
return;
/* Check whether we need to recreate the textures of the paint
@@ -2516,22 +2587,25 @@ st_theme_node_paint (StThemeNode *node,
* 2) the allocation size change requires recreating textures
*/
if (state->node != node ||
st_theme_node_needs_new_box_shadow_for_size (state, node, width, height))
st_theme_node_needs_new_box_shadow_for_size (state, node, width, height,
resource_scale))
{
/* If we had the ability to cache textures on the node, then we
can just copy them over to the paint state and avoid all
rendering. We end up sharing textures a cross different
widgets. */
if (node->rendered_once && node->cached_textures &&
width >= node->box_shadow_min_width && height >= node->box_shadow_min_height)
width >= node->box_shadow_min_width && height >= node->box_shadow_min_height &&
fabsf (resource_scale - state->resource_scale) < FLT_EPSILON)
st_theme_node_paint_state_copy (state, &node->cached_state);
else
st_theme_node_render_resources (state, node, width, height);
st_theme_node_render_resources (state, node, width, height, resource_scale);
node->rendered_once = TRUE;
}
else if (state->alloc_width != width || state->alloc_height != height)
st_theme_node_update_resources (state, node, width, height);
else if (state->alloc_width != width || state->alloc_height != height ||
fabsf (state->resource_scale - resource_scale) > FLT_EPSILON)
st_theme_node_update_resources (state, node, width, height, resource_scale);
/* Rough notes about the relationship of borders and backgrounds in CSS3;
* see http://www.w3.org/TR/css3-background/ for more accurate details.
@@ -2576,7 +2650,7 @@ st_theme_node_paint (StThemeNode *node,
}
if (state->prerendered_pipeline != NULL ||
st_theme_node_load_border_image (node))
st_theme_node_load_border_image (node, resource_scale))
{
if (state->prerendered_pipeline != NULL)
{
@@ -2604,7 +2678,7 @@ st_theme_node_paint (StThemeNode *node,
st_theme_node_paint_outline (node, framebuffer, box, paint_opacity);
if (state->prerendered_pipeline == NULL &&
st_theme_node_load_background_image (node))
st_theme_node_load_background_image (node, resource_scale))
{
ClutterActorBox background_box;
ClutterActorBox texture_coords;
@@ -2616,7 +2690,8 @@ st_theme_node_paint (StThemeNode *node,
*/
has_visible_outline = st_theme_node_has_visible_outline (node);
get_background_position (node, &allocation, &background_box, &texture_coords);
get_background_position (node, &allocation, resource_scale,
&background_box, &texture_coords);
if (has_visible_outline || node->background_repeat)
cogl_framebuffer_push_rectangle_clip (framebuffer,
@@ -2707,6 +2782,7 @@ st_theme_node_paint_state_init (StThemeNodePaintState *state)
state->alloc_width = 0;
state->alloc_height = 0;
state->resource_scale = -1;
state->node = NULL;
state->box_shadow_pipeline = NULL;
state->prerendered_texture = NULL;
@@ -2731,6 +2807,7 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state,
state->alloc_width = other->alloc_width;
state->alloc_height = other->alloc_height;
state->resource_scale = other->resource_scale;
state->box_shadow_width = other->box_shadow_width;
state->box_shadow_height = other->box_shadow_height;
@@ -2750,6 +2827,7 @@ st_theme_node_paint_state_invalidate (StThemeNodePaintState *state)
{
state->alloc_width = 0;
state->alloc_height = 0;
state->resource_scale = -1.0f;
}
gboolean

View File

@@ -19,6 +19,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include "st-theme-node-transition.h"
enum {
@@ -117,6 +119,10 @@ st_theme_node_transition_new (StThemeNode *from_node,
return transition;
}
/**
* st_theme_node_transition_get_new_paint_state: (skip)
*
*/
StThemeNodePaintState *
st_theme_node_transition_get_new_paint_state (StThemeNodeTransition *transition)
{
@@ -237,7 +243,8 @@ st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition,
static gboolean
setup_framebuffers (StThemeNodeTransition *transition,
const ClutterActorBox *allocation)
const ClutterActorBox *allocation,
float resource_scale)
{
StThemeNodeTransitionPrivate *priv = transition->priv;
CoglContext *ctx;
@@ -248,8 +255,8 @@ setup_framebuffers (StThemeNodeTransition *transition,
static CoglPipeline *material_template = NULL;
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
width = priv->offscreen_box.x2 - priv->offscreen_box.x1;
height = priv->offscreen_box.y2 - priv->offscreen_box.y1;
width = ceilf ((priv->offscreen_box.x2 - priv->offscreen_box.x1) * resource_scale);
height = ceilf ((priv->offscreen_box.y2 - priv->offscreen_box.y1) * resource_scale);
g_return_val_if_fail (width > 0, FALSE);
g_return_val_if_fail (height > 0, FALSE);
@@ -320,7 +327,7 @@ setup_framebuffers (StThemeNodeTransition *transition,
priv->offscreen_box.y2, 0.0, 1.0);
st_theme_node_paint (priv->old_theme_node, &priv->old_paint_state,
priv->old_offscreen, allocation, 255);
priv->old_offscreen, allocation, 255, resource_scale);
cogl_framebuffer_clear4f (priv->new_offscreen, COGL_BUFFER_BIT_COLOR,
0, 0, 0, 0);
@@ -330,7 +337,7 @@ setup_framebuffers (StThemeNodeTransition *transition,
priv->offscreen_box.x2,
priv->offscreen_box.y2, 0.0, 1.0);
st_theme_node_paint (priv->new_theme_node, &priv->new_paint_state,
priv->new_offscreen, allocation, 255);
priv->new_offscreen, allocation, 255, resource_scale);
return TRUE;
}
@@ -339,7 +346,8 @@ void
st_theme_node_transition_paint (StThemeNodeTransition *transition,
CoglFramebuffer *framebuffer,
ClutterActorBox *allocation,
guint8 paint_opacity)
guint8 paint_opacity,
float resource_scale)
{
StThemeNodeTransitionPrivate *priv = transition->priv;
@@ -360,7 +368,8 @@ st_theme_node_transition_paint (StThemeNodeTransition *transition,
priv->last_allocation = *allocation;
calculate_offscreen_box (transition, allocation);
priv->needs_setup = !setup_framebuffers (transition, allocation);
priv->needs_setup = !setup_framebuffers (transition, allocation,
resource_scale);
if (priv->needs_setup) /* setting up framebuffers failed */
return;

View File

@@ -43,7 +43,8 @@ void st_theme_node_transition_update (StThemeNodeTransition *transition,
void st_theme_node_transition_paint (StThemeNodeTransition *transition,
CoglFramebuffer *framebuffer,
ClutterActorBox *allocation,
guint8 paint_opacity);
guint8 paint_opacity,
float resource_scale);
void st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition,
const ClutterActorBox *allocation,

View File

@@ -104,6 +104,8 @@ struct _StThemeNodePaintState {
float box_shadow_width;
float box_shadow_height;
float resource_scale;
CoglPipeline *box_shadow_pipeline;
CoglPipeline *prerendered_texture;
CoglPipeline *prerendered_pipeline;
@@ -279,7 +281,8 @@ void st_theme_node_paint (StThemeNode *node,
StThemeNodePaintState *state,
CoglFramebuffer *framebuffer,
const ClutterActorBox *box,
guint8 paint_opacity);
guint8 paint_opacity,
float resource_scale);
void st_theme_node_invalidate_background_image (StThemeNode *node);
void st_theme_node_invalidate_border_image (StThemeNode *node);

View File

@@ -80,11 +80,8 @@ struct _StWidgetPrivate
ClutterActor *label_actor;
gchar *accessible_name;
/* Even though Clutter has first_child/last_child properties,
* we need to keep track of the old first/last children so
* that we can remove the pseudo classes on them. */
StWidget *prev_last_child;
StWidget *prev_first_child;
StWidget *last_visible_child;
StWidget *first_visible_child;
StThemeNodePaintState paint_states[2];
int current_paint_state : 2;
@@ -121,6 +118,7 @@ enum
{
STYLE_CHANGED,
POPUP_MENU,
RESOURCE_SCALE_CHANGED,
LAST_SIGNAL
};
@@ -321,8 +319,8 @@ st_widget_dispose (GObject *gobject)
priv->texture_file_changed_id = 0;
}
g_clear_object (&priv->prev_first_child);
g_clear_object (&priv->prev_last_child);
g_clear_object (&priv->first_visible_child);
g_clear_object (&priv->last_visible_child);
G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject);
}
@@ -417,8 +415,12 @@ st_widget_paint_background (StWidget *widget)
CoglFramebuffer *framebuffer;
StThemeNode *theme_node;
ClutterActorBox allocation;
float resource_scale;
guint8 opacity;
if (!st_widget_get_resource_scale (widget, &resource_scale))
return;
framebuffer = cogl_get_draw_framebuffer ();
theme_node = st_widget_get_theme_node (widget);
@@ -430,13 +432,15 @@ st_widget_paint_background (StWidget *widget)
st_theme_node_transition_paint (priv->transition_animation,
framebuffer,
&allocation,
opacity);
opacity,
resource_scale);
else
st_theme_node_paint (theme_node,
current_paint_state (widget),
framebuffer,
&allocation,
opacity);
opacity,
resource_scale);
}
static void
@@ -452,6 +456,7 @@ static void
st_widget_parent_set (ClutterActor *widget,
ClutterActor *old_parent)
{
StWidget *self = ST_WIDGET (widget);
ClutterActorClass *parent_class;
ClutterActor *new_parent;
@@ -463,7 +468,7 @@ st_widget_parent_set (ClutterActor *widget,
/* don't send the style changed signal if we no longer have a parent actor */
if (new_parent)
st_widget_style_changed (ST_WIDGET (widget));
st_widget_style_changed (self);
}
static void
@@ -574,7 +579,11 @@ get_root_theme_node (ClutterStage *stage)
StThemeNode *
st_widget_get_theme_node (StWidget *widget)
{
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
StWidgetPrivate *priv;
g_return_val_if_fail (ST_IS_WIDGET (widget), NULL);
priv = st_widget_get_instance_private (widget);
if (priv->theme_node == NULL)
{
@@ -1019,6 +1028,21 @@ st_widget_class_init (StWidgetClass *klass)
G_STRUCT_OFFSET (StWidgetClass, popup_menu),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* StWidget::resource-scale-changed:
* @widget: the #StWidget
*
* Emitted when the paint scale that the widget will be painted as
* changed.
*/
signals[RESOURCE_SCALE_CHANGED] =
g_signal_new ("resource-scale-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (StWidgetClass, resource_scale_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
/**
@@ -1448,6 +1472,81 @@ st_widget_get_style (StWidget *actor)
return ST_WIDGET_PRIVATE (actor)->inline_style;
}
/**
* st_widget_get_resource_scale:
* @widget: A #StWidget
* @resource_scale: (out): return location for the resource scale
*
* Retrieves the resource scale for this #StWidget, if available.
*
* The resource scale refers to the scale the actor should use for its resources.
*/
gboolean
st_widget_get_resource_scale (StWidget *widget,
float *resource_scale)
{
return clutter_actor_get_resource_scale (CLUTTER_ACTOR (widget),
resource_scale);
}
static void
st_widget_set_first_visible_child (StWidget *widget,
ClutterActor *actor)
{
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
if (priv->first_visible_child == NULL && actor == NULL)
return;
if (priv->first_visible_child != NULL &&
CLUTTER_ACTOR (priv->first_visible_child) == actor)
return;
if (priv->first_visible_child != NULL)
{
st_widget_remove_style_pseudo_class (priv->first_visible_child, "first-child");
g_clear_object (&priv->first_visible_child);
}
if (actor == NULL)
return;
if (ST_IS_WIDGET (actor))
{
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "first-child");
priv->first_visible_child = g_object_ref (ST_WIDGET (actor));
}
}
static void
st_widget_set_last_visible_child (StWidget *widget,
ClutterActor *actor)
{
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
if (priv->last_visible_child == NULL && actor == NULL)
return;
if (priv->last_visible_child != NULL &&
CLUTTER_ACTOR (priv->last_visible_child) == actor)
return;
if (priv->last_visible_child != NULL)
{
st_widget_remove_style_pseudo_class (priv->last_visible_child, "last-child");
g_clear_object (&priv->last_visible_child);
}
if (actor == NULL)
return;
if (ST_IS_WIDGET (actor))
{
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "last-child");
priv->last_visible_child = g_object_ref (ST_WIDGET (actor));
}
}
static void
st_widget_name_notify (StWidget *widget,
GParamSpec *pspec,
@@ -1456,6 +1555,23 @@ st_widget_name_notify (StWidget *widget,
st_widget_style_changed (widget);
}
static void
st_widget_resource_scale_notify (StWidget *widget,
GParamSpec *pspec,
gpointer data)
{
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
int i;
for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++)
st_theme_node_paint_state_invalidate (&priv->paint_states[i]);
g_signal_emit (widget, signals[RESOURCE_SCALE_CHANGED], 0);
if (clutter_actor_is_mapped (CLUTTER_ACTOR (widget)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (widget));
}
static void
st_widget_reactive_notify (StWidget *widget,
GParamSpec *pspec,
@@ -1472,30 +1588,78 @@ st_widget_reactive_notify (StWidget *widget,
st_widget_sync_hover(widget);
}
static ClutterActor *
find_nearest_visible_backwards (ClutterActor *actor)
{
ClutterActor *prev = actor;
while (prev != NULL && !clutter_actor_is_visible (prev))
prev = clutter_actor_get_previous_sibling (prev);
return prev;
}
static ClutterActor *
find_nearest_visible_forward (ClutterActor *actor)
{
ClutterActor *next = actor;
while (next != NULL && !clutter_actor_is_visible (next))
next = clutter_actor_get_next_sibling (next);
return next;
}
static void
st_widget_visible_notify (StWidget *widget,
GParamSpec *pspec,
gpointer data)
{
ClutterActor *actor = CLUTTER_ACTOR (widget);
ClutterActor *parent = clutter_actor_get_parent (actor);
if (parent == NULL || !ST_IS_WIDGET (parent))
return;
if (clutter_actor_is_visible (actor))
{
ClutterActor *before, *after;
before = clutter_actor_get_previous_sibling (actor);
if (find_nearest_visible_backwards (before) == NULL)
st_widget_set_first_visible_child (ST_WIDGET (parent), actor);
after = clutter_actor_get_next_sibling (actor);
if (find_nearest_visible_forward (after) == NULL)
st_widget_set_last_visible_child (ST_WIDGET (parent), actor);
}
else
{
if (st_widget_has_style_pseudo_class (widget, "first-child"))
{
ClutterActor *new_first;
new_first = find_nearest_visible_forward (CLUTTER_ACTOR (widget));
st_widget_set_first_visible_child (ST_WIDGET (parent), new_first);
}
if (st_widget_has_style_pseudo_class (widget, "last-child"))
{
ClutterActor *new_last;
new_last = find_nearest_visible_backwards (CLUTTER_ACTOR (widget));
st_widget_set_last_visible_child (ST_WIDGET (parent), new_last);
}
}
}
static void
st_widget_first_child_notify (StWidget *widget,
GParamSpec *pspec,
gpointer data)
{
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
ClutterActor *first_child;
if (priv->prev_first_child != NULL)
{
st_widget_remove_style_pseudo_class (priv->prev_first_child, "first-child");
g_clear_object (&priv->prev_first_child);
}
first_child = clutter_actor_get_first_child (CLUTTER_ACTOR (widget));
if (first_child == NULL)
return;
if (ST_IS_WIDGET (first_child))
{
st_widget_add_style_pseudo_class (ST_WIDGET (first_child), "first-child");
priv->prev_first_child = g_object_ref (ST_WIDGET (first_child));
}
st_widget_set_first_visible_child (widget, find_nearest_visible_forward (first_child));
}
static void
@@ -1503,25 +1667,10 @@ st_widget_last_child_notify (StWidget *widget,
GParamSpec *pspec,
gpointer data)
{
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
ClutterActor *last_child;
if (priv->prev_last_child != NULL)
{
st_widget_remove_style_pseudo_class (priv->prev_last_child, "last-child");
g_clear_object (&priv->prev_last_child);
}
last_child = clutter_actor_get_last_child (CLUTTER_ACTOR (widget));
if (last_child == NULL)
return;
if (ST_IS_WIDGET (last_child))
{
st_widget_add_style_pseudo_class (ST_WIDGET (last_child), "last-child");
priv->prev_last_child = g_object_ref (ST_WIDGET (last_child));
}
st_widget_set_last_visible_child (widget, find_nearest_visible_backwards (last_child));
}
static void
@@ -1536,8 +1685,10 @@ st_widget_init (StWidget *actor)
/* connect style changed */
g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL);
g_signal_connect (actor, "notify::resource-scale", G_CALLBACK (st_widget_resource_scale_notify), NULL);
g_signal_connect (actor, "notify::reactive", G_CALLBACK (st_widget_reactive_notify), NULL);
g_signal_connect (actor, "notify::visible", G_CALLBACK (st_widget_visible_notify), NULL);
g_signal_connect (actor, "notify::first-child", G_CALLBACK (st_widget_first_child_notify), NULL);
g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL);
priv->texture_file_changed_id = g_signal_connect (st_texture_cache_get_default (), "texture-file-changed",

View File

@@ -63,6 +63,7 @@ struct _StWidgetClass
/* signals */
void (* style_changed) (StWidget *self);
void (* popup_menu) (StWidget *self);
void (* resource_scale_changed) (StWidget *self);
/* vfuncs */
@@ -137,6 +138,8 @@ StThemeNode * st_widget_peek_theme_node (StWidget *widg
GList * st_widget_get_focus_chain (StWidget *widget);
void st_widget_paint_background (StWidget *widget);
gboolean st_widget_get_resource_scale (StWidget *widget,
float *resource_scale);
/* debug methods */
char *st_describe_actor (ClutterActor *actor);

View File

@@ -22,6 +22,7 @@
#include "st-theme.h"
#include "st-theme-context.h"
#include "st-label.h"
#include "st-button.h"
#include <math.h>
#include <string.h>
@@ -37,7 +38,7 @@ static StThemeNode *group3;
static StThemeNode *group4;
static StThemeNode *group5;
static StThemeNode *group6;
static StThemeNode *cairo_texture;
static StThemeNode *button;
static gboolean fail;
static const char *test;
@@ -280,7 +281,7 @@ test_classes (void)
{
test = "classes";
/* .special-text class overrides size and style;
* the ClutterTexture.special-text selector doesn't match */
* the StBin.special-text selector doesn't match */
assert_font (text1, "text1", "sans-serif Italic 32px");
}
@@ -288,12 +289,12 @@ static void
test_type_inheritance (void)
{
test = "type_inheritance";
/* From ClutterTexture element selector */
assert_length ("cairoTexture", "padding-top", 10.,
st_theme_node_get_padding (cairo_texture, ST_SIDE_TOP));
/* From ClutterCairoTexture element selector */
assert_length ("cairoTexture", "padding-right", 20.,
st_theme_node_get_padding (cairo_texture, ST_SIDE_RIGHT));
/* From StBin element selector */
assert_length ("button", "padding-top", 10.,
st_theme_node_get_padding (button, ST_SIDE_TOP));
/* From StButton element selector */
assert_length ("button", "padding-right", 20.,
st_theme_node_get_padding (button, ST_SIDE_RIGHT));
}
static void
@@ -410,15 +411,15 @@ test_background (void)
test = "background";
/* group1 has a background: shortcut property setting color and image */
assert_background_color (group1, "group1", 0xff0000ff);
assert_background_image (group1, "group1", "st/some-background.png");
assert_background_image (group1, "group1", "some-background.png");
/* text1 inherits the background image but not the color */
assert_background_color (text1, "text1", 0x00000000);
assert_background_image (text1, "text1", "st/some-background.png");
assert_background_image (text1, "text1", "some-background.png");
/* text2 inherits both, but then background: none overrides both */
assert_background_color (text2, "text2", 0x00000000);
assert_background_image (text2, "text2", NULL);
/* background-image property */
assert_background_image (group2, "group2", "st/other-background.png");
assert_background_image (group2, "group2", "other-background.png");
}
static void
@@ -541,7 +542,10 @@ main (int argc, char **argv)
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
file = g_file_new_for_path ("st/test-theme.css");
/* Make sure our assumptions about resolution are correct */
g_object_set (clutter_settings_get_default (), "font-dpi", -1, NULL);
file = g_file_new_for_path ("test-theme.css");
theme = st_theme_new (file, NULL, NULL);
g_object_unref (file);
@@ -575,8 +579,8 @@ main (int argc, char **argv)
CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover", NULL);
group3 = st_theme_node_new (context, group2, NULL,
CLUTTER_TYPE_GROUP, "group3", NULL, "hover", NULL);
cairo_texture = st_theme_node_new (context, root, NULL,
CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL, NULL);
button = st_theme_node_new (context, root, NULL,
ST_TYPE_BUTTON, "button", NULL, NULL, NULL);
test_defaults ();
test_lengths ();
@@ -592,7 +596,7 @@ main (int argc, char **argv)
test_pseudo_class ();
test_inline_style ();
g_object_unref (cairo_texture);
g_object_unref (button);
g_object_unref (group1);
g_object_unref (group2);
g_object_unref (group3);

View File

@@ -26,7 +26,7 @@ stage {
font-style: italic;
}
ClutterTexture.special-text {
StBin.special-text {
font-weight: bold;
}
@@ -52,11 +52,11 @@ ClutterTexture.special-text {
font-feature-settings: normal;
}
ClutterTexture {
StBin {
padding: 10px;
}
ClutterCairoTexture {
StButton {
padding-right: 20px;
}

View File

@@ -52,7 +52,9 @@ na_tray_child_realize (GtkWidget *widget)
/* Set a transparent background */
cairo_pattern_t *transparent = cairo_pattern_create_rgba (0, 0, 0, 0);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gdk_window_set_background_pattern (window, transparent);
G_GNUC_END_IGNORE_DEPRECATIONS
cairo_pattern_destroy (transparent);
child->parent_relative_bg = FALSE;
@@ -61,7 +63,9 @@ na_tray_child_realize (GtkWidget *widget)
{
/* Otherwise, if the visual matches the visual of the parent window, we
* can use a parent-relative background and fake transparency. */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gdk_window_set_background_pattern (window, NULL);
G_GNUC_END_IGNORE_DEPRECATIONS
child->parent_relative_bg = TRUE;
}
@@ -242,6 +246,7 @@ na_tray_child_new (GdkScreen *screen,
Window icon_window)
{
XWindowAttributes window_attributes;
GdkDisplay *display;
Display *xdisplay;
NaTrayChild *child;
GdkVisual *visual;
@@ -253,15 +258,16 @@ na_tray_child_new (GdkScreen *screen,
g_return_val_if_fail (icon_window != None, NULL);
xdisplay = GDK_SCREEN_XDISPLAY (screen);
display = gdk_x11_lookup_xdisplay (xdisplay);
/* We need to determine the visual of the window we are embedding and create
* the socket in the same visual.
*/
gdk_error_trap_push ();
gdk_x11_display_error_trap_push (display);
result = XGetWindowAttributes (xdisplay, icon_window,
&window_attributes);
gdk_error_trap_pop_ignored ();
gdk_x11_display_error_trap_pop_ignored (display);
if (!result) /* Window already gone */
return NULL;
@@ -308,7 +314,7 @@ na_tray_child_get_title (NaTrayChild *child)
utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
gdk_error_trap_push ();
gdk_x11_display_error_trap_push (display);
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
child->icon_window,
@@ -318,7 +324,7 @@ na_tray_child_get_title (NaTrayChild *child)
&type, &format, &nitems,
&bytes_after, (guchar **)&val);
if (gdk_error_trap_pop () || result != Success)
if (gdk_x11_display_error_trap_pop (display) || result != Success)
return NULL;
if (type != utf8_string ||
@@ -377,7 +383,8 @@ na_tray_child_force_redraw (NaTrayChild *child)
* icon is expecting the server to clear-to-background before
* the redraw. It should be ok for GtkStatusIcon or EggTrayIcon.
*/
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
GdkDisplay *display = gtk_widget_get_display (widget);
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
XEvent xev;
GdkWindow *plug_window;
GtkAllocation allocation;
@@ -393,12 +400,12 @@ na_tray_child_force_redraw (NaTrayChild *child)
xev.xexpose.height = allocation.height;
xev.xexpose.count = 0;
gdk_error_trap_push ();
gdk_x11_display_error_trap_push (display);
XSendEvent (xdisplay,
xev.xexpose.window,
False, ExposureMask,
&xev);
gdk_error_trap_pop_ignored ();
gdk_x11_display_error_trap_pop_ignored (display);
#else
/* Hiding and showing is the safe way to do it, but can result in more
* flickering.
@@ -435,14 +442,16 @@ _get_wmclass (Display *xdisplay,
char **res_class,
char **res_name)
{
GdkDisplay *display;
XClassHint ch;
ch.res_name = NULL;
ch.res_class = NULL;
gdk_error_trap_push ();
display = gdk_x11_lookup_xdisplay (xdisplay);
gdk_x11_display_error_trap_push (display);
XGetClassHint (xdisplay, xwindow, &ch);
gdk_error_trap_pop_ignored ();
gdk_x11_display_error_trap_pop_ignored (display);
if (res_class)
*res_class = NULL;

View File

@@ -70,7 +70,7 @@ static guint manager_signals[LAST_SIGNAL];
#define SYSTEM_TRAY_ORIENTATION_VERT 1
#ifdef GDK_WINDOWING_X11
static gboolean na_tray_manager_check_running_screen_x11 (GdkScreen *screen);
static gboolean na_tray_manager_check_running_screen_x11 ();
#endif
static void na_tray_manager_finalize (GObject *object);
@@ -682,15 +682,15 @@ na_tray_manager_set_colors_property (NaTrayManager *manager)
#ifdef GDK_WINDOWING_X11
static gboolean
na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
GdkScreen *screen)
na_tray_manager_manage_screen_x11 (NaTrayManager *manager)
{
GdkDisplay *display;
Screen *xscreen;
GtkWidget *invisible;
GdkWindow *window;
char *selection_atom_name;
guint32 timestamp;
GdkScreen *screen;
Screen *xscreen;
GtkWidget *invisible;
GdkWindow *window;
char *selection_atom_name;
guint32 timestamp;
g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), FALSE);
g_return_val_if_fail (manager->screen == NULL, FALSE);
@@ -699,10 +699,11 @@ na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
* we can't create another one.
*/
#if 0
if (na_tray_manager_check_running_screen_x11 (screen))
if (na_tray_manager_check_running_screen_x11 ())
return FALSE;
#endif
screen = gdk_screen_get_default ();
manager->screen = screen;
display = gdk_screen_get_display (screen);
@@ -715,7 +716,7 @@ na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK);
selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
gdk_screen_get_number (screen));
gdk_x11_get_default_screen ());
manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE);
g_free (selection_atom_name);
@@ -793,14 +794,12 @@ na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
#endif
gboolean
na_tray_manager_manage_screen (NaTrayManager *manager,
GdkScreen *screen)
na_tray_manager_manage_screen (NaTrayManager *manager)
{
g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
g_return_val_if_fail (manager->screen == NULL, FALSE);
#ifdef GDK_WINDOWING_X11
return na_tray_manager_manage_screen_x11 (manager, screen);
return na_tray_manager_manage_screen_x11 (manager);
#else
return FALSE;
#endif
@@ -809,15 +808,17 @@ na_tray_manager_manage_screen (NaTrayManager *manager,
#ifdef GDK_WINDOWING_X11
static gboolean
na_tray_manager_check_running_screen_x11 (GdkScreen *screen)
na_tray_manager_check_running_screen_x11 ()
{
GdkDisplay *display;
Atom selection_atom;
char *selection_atom_name;
GdkScreen *screen;
Atom selection_atom;
char *selection_atom_name;
screen = gdk_screen_get_default ();
display = gdk_screen_get_display (screen);
selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
gdk_screen_get_number (screen));
gdk_x11_get_default_screen ());
selection_atom = gdk_x11_get_xatom_by_name_for_display (display,
selection_atom_name);
g_free (selection_atom_name);
@@ -832,12 +833,10 @@ na_tray_manager_check_running_screen_x11 (GdkScreen *screen)
#endif
gboolean
na_tray_manager_check_running (GdkScreen *screen)
na_tray_manager_check_running ()
{
g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
#ifdef GDK_WINDOWING_X11
return na_tray_manager_check_running_screen_x11 (screen);
return na_tray_manager_check_running_screen_x11 ();
#else
return FALSE;
#endif

View File

@@ -88,10 +88,9 @@ struct _NaTrayManagerClass
GType na_tray_manager_get_type (void);
gboolean na_tray_manager_check_running (GdkScreen *screen);
gboolean na_tray_manager_check_running (void);
NaTrayManager *na_tray_manager_new (void);
gboolean na_tray_manager_manage_screen (NaTrayManager *manager,
GdkScreen *screen);
gboolean na_tray_manager_manage_screen (NaTrayManager *manager);
void na_tray_manager_set_orientation (NaTrayManager *manager,
GtkOrientation orientation);
GtkOrientation na_tray_manager_get_orientation (NaTrayManager *manager);

0
test/__init__.py Normal file
View File

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