Compare commits

..

140 Commits

Author SHA1 Message Date
Jasper St. Pierre
0829749049 wayland: Implement support for wl_viewport 2014-11-05 10:14:35 -08:00
Jasper St. Pierre
725d0ad680 shaped-texture: Add API to support a viewport view
This will be used by our Wayland front-end to implement the wl_viewport
extension.
2014-11-05 10:14:35 -08:00
Jonathon Jongsma
e72c6916aa xrandr: ignore hotplug_mode_update value
The important thing is whether this property exists or not, but the value
doesn't matter.
2014-11-05 11:58:34 -06:00
Emmanuele Bassi
8b98cb818c config: Fix compilation errors 2014-11-05 12:30:05 +00:00
Jasper St. Pierre
f8a4d450a5 Makefile: Use $(NULL) trick
This helps make the Makefile look nicer and prevent merge conflicts.
2014-11-04 19:08:07 -08:00
Jasper St. Pierre
681cf95236 monitor-config: Factor out some code to make a default config 2014-11-03 14:40:12 -08:00
Jasper St. Pierre
90d6734f8c cursor-renderer-x11: Include Xfixes headers as well 2014-11-03 10:51:40 -08:00
Jasper St. Pierre
213cd8a334 cursor-tracker: Make sure to include Xfixes headers
We use Xfixes symbols in this file, but under some conditions, we don't
always include the Xfixes headers.
2014-11-03 10:32:13 -08:00
Rui Matos
3b1271d9be monitor-config: Prevent a crash applying config for a closed lid
When a laptop's lid is closed we try to build and apply a temporary
configuration that disables the laptop's display if we have other
outputs.

This isn't enough though, we must also check if at least one of these
other outputs is enabled otherwise we'll try to resize the screen to
0x0 which (rightfully) hits an assertion.

https://bugzilla.gnome.org/show_bug.cgi?id=739450
2014-10-31 17:39:43 +01:00
Bastien Nocera
13b6bd20ca wayland: Don't check for hi-dpi on monitors with broken EDID
If the monitor reports a width/height that looks suspiciously like an
aspect ratio (16/9 or 16/10) don't check for hi-dpi. We can assume that
makers of devices that do support hi-dpi aren't so careless.

See http://cgit.freedesktop.org/~daniels/xserver/commit/?h=lodpi

https://bugzilla.gnome.org/show_bug.cgi?id=734839
2014-10-30 17:37:24 +01:00
Florian Müllner
63e31af476 Bump version to 3.15.1
Update NEWS.
2014-10-30 10:40:17 +00:00
Adel Gadllah
718a89eb2f meta-wayland-surface: Correcly scale the input region
The input region currently only gets scaled by the surface
scale while ignoring the output scale, which causes input events to not get
delivered correctly for clients on hidpi screens. So take the output scale
into account when doing so.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:11:53 +01:00
Adel Gadllah
a43ca7b5b1 Revert "wayland-surface: Apply the surface scale only if needed"
This commit is wrong, it assumes that the scale only applies to the one
set by the client but its not. meta_surface_actor_wayland_scale_texture
also handles the output scale. Revert the commit to fix hidpi for wayland
clients like weston-terminal.

This reverts commit 0364ea9140.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:11:53 +01:00
Florian Müllner
af00ca534a ui: Adapt to GtkStyleContext changes
Since GTK+ commit 3a337156d11a86c7, save()/restore() may only be
used for subelements; in this particular case, the change broke
the backdrop state in decorations. Luckily we don't actually need
the save()/restore() pair anyway, as we only touch the context's
state and always set it explicitly.
2014-10-25 18:16:49 +02:00
Jasper St. Pierre
4b2b431700 config: Combine two exit paths 2014-10-23 16:04:43 -07:00
Jasper St. Pierre
2c1a6b6a12 config: Fix an incorrect unref 2014-10-23 16:04:43 -07:00
Jasper St. Pierre
b3544f8ec1 window: Placate new gcc
It thinks remaining can be used uninitialized. It's wrong, but let's
help it out by initializing the variable.
2014-10-23 16:04:42 -07:00
Carlos Garnacho
df384965c3 core: Unset "pointer emulating" sequence after event processing
The set/unset branches of meta_display_update_pointer_emulating_sequence()
have been split and put directly where it makes sense. The pointer emulated
sequence will be updated before processing the CLUTTER_TOUCH_BEGIN, and
after processing the CLUTTER_TOUCH_END, this way the checks on this hold
true during all the sequence lifetime.

https://bugzilla.gnome.org/show_bug.cgi?id=738411
2014-10-23 17:16:59 +02:00
Carlos Garnacho
700d367937 compositor: Ensure child actors are included in picking
If the actor surface has an input mask, custom picking is implemented
for the portions affected by the mask, although the child actors (most
usually subsurfaces) are left out.

https://bugzilla.gnome.org/show_bug.cgi?id=738890
2014-10-23 16:53:44 +02:00
Carlos Garnacho
7c5989c978 wayland: Avoid MetaWindow call on non window-backed surfaces
Crossing events may also be gotten on subsurfaces.

https://bugzilla.gnome.org/show_bug.cgi?id=738890
2014-10-23 16:53:44 +02:00
Carlos Garnacho
8819d9ce66 core: end-of-grab button releases must be consumed by the window
Returning FALSE here gets the button release event propagated to the
client on wayland, which is unexpected after xdg_surface.move/resize()
have been called.

https://bugzilla.gnome.org/show_bug.cgi?id=738888
2014-10-23 16:53:44 +02:00
Rui Matos
b63413e5b0 Revert "monitor-manager: Remove needless code"
It turns out that this was wrong because MetaWindow->monitor points to
the old monitor infos and they are needed to position windows in the
new configuration which happens in a monitors-changed handler.

This reverts commit e1704acda4.
2014-10-23 16:38:26 +02:00
Jasper St. Pierre
cd1e1d4bf1 config: Fix a few memory leaks
We were forgetting to unref in a few places.
2014-10-22 15:51:22 -07:00
Jasper St. Pierre
9710c013c5 config: Rename ret to config
We don't return this configuration, so don't name it ret.
2014-10-22 15:49:47 -07:00
Jasper St. Pierre
05f8d79323 config: Fix the memory and other management for MetaMonitorConfig
The code in MetaMonitorConfig was really complex and was trying to do
way too much, using multiple different variables to determine where
things were stored, and trying to do fancy tricks to transfer
ownership.

Add a refcounting system to help simplify this, and clean up the logic.
Simply along the way, this fixes multiple bugs in the monitor config
logic, most notably bug #734889, which was my original goal to fix.
2014-10-22 15:25:12 -07:00
Jasper St. Pierre
f2546dfeea config: Refactor the check for the lid special-case out
This also fixes the case where current_is_for_laptop_lid wasn't properly
set in the default case.
2014-10-22 15:04:34 -07:00
Rui Matos
47e339b46e monitor-manager-xrandr: Don't do extra work on RRScreenChangeNotify
The X server sends several RRScreenChangeNotify events in a burst when
something happens which, currently, causes us to rebuild our view of
the world as many times and notify the upper layers about it which
causes a lot of bogus repeated work like rebuilding background actors.

We can avoid this extra work by looking at the timestamp in the
XRRScreenResources struct which is updated when an X client (including
us!) last changed something and comparing it with the previous
timestamp.

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-10-16 20:39:16 +02:00
Rui Matos
016b8f5b4a monitor-manager-xrandr: Use CurrentTime when applying configurations
This is what the xrandr CLI tool does and will allow us to do less
work when we get RRScreenChangeNotify events.

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-10-16 20:39:16 +02:00
Rui Matos
b3821c4f90 monitor-manager: Don't try to match the outputs on hotplug
meta_monitor_config_match_current() only matches the number of outputs
and if the output connector, vendor, product and serial match.

In the X backend, this means that we can't use it to bypass doing any
work because it won't detect cases where we actually want to update
ourselves like e.g. an output being turned off either by us or by
another X client (e.g. xrandr).

In the native backend, unlike the xrandr backend, we only get called
on real hotplug events and thus should always trigger the common
hotplug code to (possibly) apply a new mode so the check is pointless
anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-10-16 20:39:16 +02:00
Rui Matos
29e5c6c363 monitor-manager-xrandr: Re-work xrandr event handling
In randr events, configTimestamp can be considered the hotplug time,
i.e. whenever the server notices hardware changes, this value will be
updated.

Having that in mind, we can re-work the logic to make it clearer.
There are no semantic changes.
2014-10-16 20:39:16 +02:00
Rui Matos
e1704acda4 monitor-manager: Remove needless code
Nothing uses this. Signal handlers have access to the new monitor
infos built by make_logical_config() .

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-10-16 20:39:16 +02:00
Jasper St. Pierre
60cbb41f42 configure: Actually make gbm optional
Whoops, I made the code work without it, but forgot to strip it from the
actual list of requires packages.

Spotted-by: Rico Tzschichholz <ricotz@ubuntu.com>
2014-10-15 11:13:48 -07:00
Jasper St. Pierre
d88c8d9ced Make gbm optional
Now it's only required by the native backend. The cursor code is getting
quite messy, but it was already considerable messy to start with.
2014-10-15 10:40:28 -07:00
Jasper St. Pierre
60ab11ecbf cursor: Clean up code flow slightly
Reverse the set of expressions so testing for gbm is at the top.
2014-10-15 10:36:42 -07:00
Jasper St. Pierre
34516aeab6 display: Fix accidental inversion from 2f9c601
Commit 2f9c601 accidentally changed the logic here, changing the grab
behavior when not using raise-on-click. Fix this.

Spotted-by: Adam Goode <adam@spicenitz.org>
2014-10-14 22:20:33 -07:00
Cosimo Cecchi
a37f632b1b background: use GFiles instead of filenames
We want to use GResources for system backgrounds, so move this to a
GFile.

https://bugzilla.gnome.org/show_bug.cgi?id=736936
2014-10-14 18:54:36 -07:00
Jasper St. Pierre
8a6542c242 theme: Remove COLORIZE feature of images
From a quick code search and grep of gnome-themes-standard, none of
the themes that I inspected used this feature. Since it's the last
thing that uses a lot of old legacy GdkPixbuf code, I'd rather just
consider the feature unsupported at this point and clean up everything
I need to.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2014-10-14 17:45:14 -07:00
Jasper St. Pierre
7e12000d97 theme: Use cairo for drawing uncolorized IMAGEs
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2014-10-14 17:45:14 -07:00
Jasper St. Pierre
23f086da8a theme: Use cairo for TINT operations with alpha
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2014-10-14 17:45:14 -07:00
Jasper St. Pierre
4c2c1c4dd2 theme: Use cairo for drawing ICON
Thanks to Benjamin Otte for helping me clean this up.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2014-10-14 17:45:07 -07:00
Jasper St. Pierre
545f298921 theme: Remove our own gradient stuff
Part one of porting to cairo.

Thanks to Benjamin Otte for helping me clean this up.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2014-10-14 17:37:49 -07:00
Jasper St. Pierre
64295e8cd7 keybindings: Always freeze on the stage window
This is what gnome-shell does, so there's no reason to include this as
part of our API.
2014-10-14 14:36:47 -07:00
Jasper St. Pierre
722d4c6c17 native: Implement monitor hotplug in the native backend
Use gudev to notice when new monitors are hotplugged, and when they are,
update the configuration.
2014-10-14 13:56:48 -07:00
Jasper St. Pierre
cc8462969d monitor-manager: Put the common hotplug code in a common path as well
So we can reuse it in the KMS backend.
2014-10-14 13:56:48 -07:00
Jasper St. Pierre
989bb6ebb1 monitor-manager: Simplify reading the current configuration
Make a wrapper in MetaMonitorManager that handles freeing the existing
configuration for us.
2014-10-14 13:56:48 -07:00
Jasper St. Pierre
1dbda68839 monitor-manager-xrandr: Refactor handle_xevent once more
Make the flow a bit clearer, and inline a method only used once.
2014-10-14 13:56:48 -07:00
Florian Müllner
a460f88b31 Remove unused variable 2014-10-14 21:49:47 +02:00
Florian Müllner
3e511b9591 Bump version to 3.14.1
Update NEWS.
2014-10-14 20:26:31 +02:00
Florian Müllner
5664c703b7 screen: Always consider monitors with fullscreen windows "in-fullscreen"
Fullscreen windows look weird when they are overlapped by system chrome,
which currently happens when another window is stacked above. We used to
auto-minimize fullscreen windows in that case, which proved to be both
unreliable and unpopular. So instead, keep the system chrome hidden even
when the fullscreen window is not stacked at the top.

https://bugzilla.gnome.org/show_bug.cgi?id=693991
2014-10-14 18:42:38 +02:00
Jasper St. Pierre
5c80c4b006 window-x11: Update the input region after setting the client rect
We clip the input region to the client rect, so the client rect should
be up to date before we fetch the input region.

This fixes popup windows not working in GTK+2 under Wayland.

We should also update the shape / input regions when the window is
reconfigured for a complete fix, so that making an O-R window bigger
doesn't confuse mutter, but let's leave that to a future commit.
2014-10-12 16:14:17 -07:00
Jasper St. Pierre
22f91eba8d backend: Fix minor comment 2014-10-12 13:41:03 -07:00
Tom Beckmann
d07e2f4090 workspace: fix crash when creating a new workspace with sticky windows that have struts
The constructor would collect windows that are sticky before initializing its state
which would lead to a crash in the case of windows with struts which trigger a work
area recalculation where mutter would assume, due to uninitialized state, that an
existing work area has to be freed.

https://bugzilla.gnome.org/show_bug.cgi?id=738384
2014-10-12 22:27:02 +02:00
Adel Gadllah
cd32e4a68a meta-surface-actor-x11: Fix unredirect heuristic
Damage coordinates are relative to the drawable not to the screen. So we
have to check whether x and y are 0 and not window_rect.x/y otherwise the
herustic will never trigger for windows on monitors whos x and y are not 0.

https://bugzilla.gnome.org/show_bug.cgi?id=738271
2014-10-12 00:35:47 +02:00
Rui Matos
4040a70781 wayland-keyboard: Send modifiers after the key event
The key event should be interpreted by clients with the modifier state
as it was before the event itself just as in X11 input events.
Achieving this in wayland is a matter of sending the key event first
and the modifiers after (if needed).

This isn't really specified in the wayland protocol but it matches
weston's behavior and should avoid corner cases in clients.

https://bugzilla.gnome.org/show_bug.cgi?id=738238
2014-10-10 18:12:23 +02:00
Rico Tzschichholz
cb084cc841 build: Require clutter-egl-1.0 for native backend only
https://bugzilla.gnome.org/show_bug.cgi?id=738225
2014-10-09 20:03:31 +02:00
Rico Tzschichholz
2deea6e0a3 events: Fix build without wayland
https://bugzilla.gnome.org/show_bug.cgi?id=738225
2014-10-09 20:03:30 +02:00
Adel Gadllah
a116509301 meta-surface-actor-x11: Detatch the pixmap in window_decorated_notify
The window can change its decoration without changing its size.

https://bugzilla.gnome.org/show_bug.cgi?id=738146

Found by Jasper St. Pierre <jstpierre@mecheye.net>
2014-10-08 23:11:47 +02:00
Jasper St. Pierre
ead79f834c Revert "wayland-pointer: Just use the pointer actor instead of doing a full repick"
This reverts commit 33acb5fea0.

The issue here is that the pointer actor does not actually get reset
when the actor's reactivity changes, so we end up with stale picks after
actors are destroyed.

I have a local patch to Clutter for this, but I don't have time to
submit it upstream, so let's just use the ugly code for now.
2014-10-08 13:43:57 -07:00
Jasper St. Pierre
7e431bd6bc Revert "pointer: Repick after the focused surface is destroyed"
This reverts commit e496ed50d6.

This was incorrect. wl_surface_destructor actually does the full repick
-- doing it here is dangerous, because the destroy listeners actually
run *before* the destructor, not after, so the surface is still alive.
2014-10-08 12:38:56 -07:00
Owen W. Taylor
272e1fb296 MetaBackgroundActor: queue a redraw when the background changes
When the MetaBackground changes, queue the actor for redraw.
2014-10-08 15:03:02 -04:00
Rui Matos
c39f18c2d4 wayland-keyboard: Don't send pressed keys on enter
We never want to send pressed keys to wayland clients on enter. The
protocol says that we should send them, presumably so that clients can
trigger their own key repeat routine in case they are given focus and
a key is physically pressed.

Unfortunately this causes some clients, in particular Xwayland, to
register key events that they really shouldn't handle, e.g. on an
Alt+Tab keybinding, where Alt is released before Tab, clients would
see Tab being pressed on enter followed by a key release event for
Tab, meaning that Tab would be processed by the client when it really
shouldn't.

Since the use case for the pressed keys array on enter seems weak to
us, we'll just fake that there are no pressed keys instead which
should be spec compliant even if it might not be true.

https://bugzilla.gnome.org/show_bug.cgi?id=727178
2014-10-08 15:26:28 +02:00
Jasper St. Pierre
33acb5fea0 wayland-pointer: Just use the pointer actor instead of doing a full repick
The full repick is unnecessary -- Clutter already does it for us.
2014-10-07 21:30:15 -07:00
Jasper St. Pierre
591718dc02 wayland: Clump the globals code together 2014-10-07 20:54:28 -07:00
Jasper St. Pierre
b6127eeda4 wayland: Remove old comments 2014-10-07 20:52:57 -07:00
Jasper St. Pierre
eeff1b8b02 wayland: Remove unused variable 2014-10-07 20:51:18 -07:00
Jasper St. Pierre
354cc466af wayland: Make WaylandEventSource private 2014-10-07 20:50:57 -07:00
Jasper St. Pierre
9f5c38d121 wayland: Make the MetaWaylandRegion type opaque 2014-10-07 20:44:19 -07:00
Jasper St. Pierre
ead0e902ed wayland: Move MetaWaylandRegion into a new file as well 2014-10-07 20:44:18 -07:00
Jasper St. Pierre
5d16194b03 wayland: Clean up a bit more 2014-10-07 20:42:27 -07:00
Jasper St. Pierre
a74acf0ec2 wayland: Clean up more includes 2014-10-07 20:42:27 -07:00
Jasper St. Pierre
3044cfb7bf wayland-surface: Clean up includes 2014-10-07 20:42:27 -07:00
Jasper St. Pierre
f658740043 wayland: Move some buffer manipulation functions to meta-wayland-buffer 2014-10-07 20:42:27 -07:00
Jasper St. Pierre
c1613a16c0 wayland: Put the MetaWaylandBuffer implementation in a new file 2014-10-07 20:42:27 -07:00
Jasper St. Pierre
8e85015f91 default: Adjust the default background
Getting a bit tired of green...
2014-10-07 20:42:26 -07:00
Jasper St. Pierre
f127ee3bde wayland-surface: Fix a build coming from a bad rebase 2014-10-07 12:09:52 -07:00
Jasper St. Pierre
acd928044f wayland-surface: Remove MetaWaylandSurfaceExtension
It only contained a pointer to a wl_resource, which isn't much of
value. Just replace it with the wl_resource instead. Any future private
data should be handled by our future role system.
2014-10-07 11:23:45 -07:00
Jasper St. Pierre
4ef2f2ce09 wayland-surface: Remove create_surface_extension and friends
This function has a lot of parameters, and doesn't do much in the way of
boilerplate. It's a lot simpler to hand-code.
2014-10-07 11:23:45 -07:00
Jasper St. Pierre
bc81736e6b wayland-surface: Rename the subsurface extension to wl_subsurface
To match the interface name.
2014-10-07 11:23:45 -07:00
Jasper St. Pierre
49092397f2 wayland-surface: Group MetaWaylandSurface members logically
And add comments so that we know what's what. This cleans up the struct.
2014-10-07 11:23:45 -07:00
Jasper St. Pierre
97705d3cfe wayland-surface: Move wl_surface.frame above role-specific stuff
The role-specific stuff will soon be part of a set_role callback set on
the surface itself.
2014-10-07 11:23:44 -07:00
Jasper St. Pierre
0364ea9140 wayland-surface: Apply the surface scale only if needed
There's no need to call scale_texture on every commit.
2014-10-07 11:23:31 -07:00
Florian Müllner
c0bdb3018b display: Do not include unmanaging windows in list_windows()
There's a small window before a window that is being unmanaged is
unregistered with the display. The MetaScreen::window-left-monitor
and MetaWorkspace::window-removed emissions fall right into that
window, so code that runs in that time may well be out of our
control; we can make sure that the method it can use to get an
updated list of windows no longer contains the destroyed window
though, which is a much better option than expecting everyone to
filter the list themselves.
2014-10-07 20:09:09 +02:00
Rūdolfs Mazurs
924eaac358 Updated Latvian translation 2014-10-07 20:42:42 +03:00
Rūdolfs Mazurs
a9f5a5661f Updated Latvian translation 2014-10-07 20:40:14 +03:00
Carlos Garnacho
9c589b6798 wayland: Ensure drag surface offset changes update the DnD actor 2014-10-06 19:39:43 -07:00
Carlos Garnacho
113be01ce8 wayland: Use a MetaDnDActor for the DnD icon surface
The actor is updated on DnD grab motion events, properly notified
when dragging finishes, and destroyed if the client/surface disappear
below its feet.
2014-10-06 19:39:43 -07:00
Carlos Garnacho
28e59c5a8f compositor: Add MetaDnDActor
This actor is a subclass of MetaFeedbackActor that additionally
implements the "drag failed" animation, snapping back to the drag
origin position in a surface.
2014-10-06 19:39:43 -07:00
Carlos Garnacho
b588baf9f5 compositor: Add MetaFeedbackActor
This actor is a non-reactive container that autoembeds itself into
the feedback window group in the compositor. The API is meant to
help on creating things attached to pointer/touchpoints, with an
X/Y attachment offset, and following the position of certain events.
2014-10-06 19:39:43 -07:00
Carlos Garnacho
9a825d9bee compositor: Add a "feedback" window group
Although not strictly a window group... This ClutterActor is
meant to stay always on top, and only show non-reactive actors
created by Mutter itself. Two possible usecases for this layer
are DnD surfaces, and touch spots.

We might also want to move cursors out of an overlay in MetaStage
into here at some point.
2014-10-06 19:39:43 -07:00
Carlos Garnacho
f211b3ec90 wayland: Store whether the wl_data_source has a target selected
It will be useful to check whether DnD is going to fail or not.
2014-10-06 19:39:43 -07:00
Carlos Garnacho
0510c3a621 wayland: Keep track of the origin surface and drag point on DnD
Keeping track of the surface will be necessary in case it is destroyed
during DnD, and the coordinates will be useful when figuring out the
snap back coordinates.
2014-10-06 19:39:43 -07:00
Carlos Garnacho
18db5d0799 data-device: Store the current drag grab
And bail out if any further start_drag() is attempted.
2014-10-06 19:39:42 -07:00
Jasper St. Pierre
c061e26da5 wayland: Record the offset position
This is needed for DND surfaces. We should probably test to see if it's
used for cursor surfaces at all.
2014-10-06 19:39:42 -07:00
Jasper St. Pierre
166668adc4 window: Remove duplicate case value 2014-10-06 19:39:38 -07:00
Jasper St. Pierre
ec797b055d window: Mark all override-redirect window types as appears-focused 2014-10-06 19:30:12 -07:00
Jasper St. Pierre
082cc9c83a wayland: Immediately give keyboard focus to Wayland popups 2014-10-06 17:05:23 -07:00
Jasper St. Pierre
993bec37d7 window: Ensure that popup window types propagate their focus appearance
In Wayland, popup window types are not override-redirect, and thus can
steal window focus away from their parent window when clicked on.

This means that we need to make sure their appearance is properly
propagated to the parent windows so the parent windows don't lose their
focus while they're propagated.
2014-10-06 17:01:08 -07:00
Jasper St. Pierre
e496ed50d6 pointer: Repick after the focused surface is destroyed
Having a null focus is incorrect -- we want to pick the surface that's
under the new pointer position.
2014-10-06 16:30:09 -07:00
Jasper St. Pierre
a127d05790 pointer: Make sure to update the focus after ending a grab
Otherwise, we might not reset it after the grab has ended.
2014-10-06 16:19:30 -07:00
Jasper St. Pierre
607730e96c pointer: Fix the behavior of the pointer under DND
When grabbing with DND, we need to leave the pointer alone and
under the client's control. The code here was a bit messy before about
when it unset the window cursor -- it did it whenever there was no
current surface after repicking, which is a bit wrong, since it will
fire during a drag grab.

Move the check for this to update_cursor_surface, which is our standard
"sync" API for this, and then call update_cursor_surface after we set
the focus.
2014-10-06 15:48:42 -07:00
Jasper St. Pierre
9203db0655 pointer: Don't fizzle out surface changes too soon
During a DND grab, pointer->focus_surface is NULL, since the wl_pointer
doesn't have any focused surface (it's in drag mode). In this case, the
drag interface has control of the focus, and when dragging into a NULL
surface, drag_grab_focus won't get called, properly detaching it from
the previous surface.

Let the interface->focus implementation do the fizzling out.

In the future, we should split out wl_pointer's implementation
(pointer->focus_surface) from the Wayland side of the generic pointer
wrapper (pointer->current) and use our event routing system to determine
or similar whether it should go to wl_pointer or wl_data_device.
2014-10-06 14:31:16 -07:00
Milo Casagrande
64d40792c4 Updated Italian translation 2014-10-05 13:41:57 +00:00
Jasper St. Pierre
e7356917b0 meta-monitor-manager-xrandr: Simplify handle_xevent
The code here was a bit messy with the addition of
hotplug_mode_update, and the comments were a bit confusing and
inaccurate. Clean it up and comment it a bit better to make the flow and
intention more clear.
2014-10-03 15:12:00 -06:00
Rui Matos
fa58752276 backend-native: Handle keyboard repeat settings
We need to tell clutter's evdev backend about the desktop's key repeat
settings so that our own key bindings event processing and
gnome-shell's chrome widgets get their fake key events for continuous
key press as they expect.

Note that the wayland frontend filters out these events and thus
wayland clients do not see them as specced.

https://bugzilla.gnome.org/show_bug.cgi?id=728055
2014-10-03 18:31:44 +02:00
Rui Matos
478b75e803 backend-x11: Re-upload keymap when new keyboard devices are added
The X server applies a default keymap to hotplugged keyboard
devices. To enforce our current settings we must re-upload the keymap
when a new keyboard shows up.

Note that setting the VCK keymap causes the server to propagate it
to all slave keyboard devices.

https://bugzilla.gnome.org/show_bug.cgi?id=737673
2014-10-02 19:14:03 +02:00
Jasper St. Pierre
492a1b244f Revert "display: Don't put minimized windows at the back of alt-tab"
This reverts commit 7e61ef0936.

https://bugzilla.gnome.org/show_bug.cgi?id=705177
2014-10-01 17:29:15 -06:00
Jasper St. Pierre
5d8ff2e34d screen: Remove auto-minimization "feature"
https://bugzilla.gnome.org/show_bug.cgi?id=705177
2014-10-01 17:29:02 -06:00
Jasper St. Pierre
310083aeb2 keybindings: Remove special-case code for reversing automatically
Since we now directly expose the reverses bindings directly, we
don't have to have this special-case in do_choose_window.

More importantly, if the backwards binding is pressed and has the Shift
key included, this will actually revert it

This doesn't matter for Alt-Tab in gnome-shell, which already replaces
it with a better Alt-Tab replacement, but it does matter for Alt-Esc,
which switches between windows directly.
2014-10-01 16:51:45 -06:00
Jasper St. Pierre
0faa900207 frames: Make sure to initialize button_state
Otherwise, we're comparing with uninitialized memory. Spotted by
valgrind.
2014-09-30 15:16:07 -06:00
Owen W. Taylor
b735571688 MetaBackgroundImage: free the GdkPixbuf after creating a texture
The GdkPixbuf used to load a texture was never freed.
2014-09-29 21:32:48 -04:00
Jasper St. Pierre
5e249ad5eb prefs: Don't leak the variant value for unknown properties 2014-09-29 17:54:20 -06:00
Jasper St. Pierre
21bffe4aef monitor-manager-xrandr: Fix small leak for invalid properties
If the property is invalid, then we leak the allocated buffer. Make sure
to free it in this case.
2014-09-29 17:54:20 -06:00
Florian Müllner
68283df4d9 workspace: Don't relocate sticky windows
Windows are relocated before their workspace is removed, however this
is only necessary for windows that are *only* on that workspace; for
windows on all workspaces, that step is annoying as it will unset the
sticky state requested by the user.

https://bugzilla.gnome.org/show_bug.cgi?id=737625
2014-09-30 00:41:25 +02:00
Florian Müllner
4f3de2ce39 workspace: Correctly initialize MRU list
The workspace MRU lists are updated when windows are managed/unmanaged
or change workspaces. However those updates obviously only apply to
existing workspaces - new workspaces will always start out with an empty
MRU list, despite sticky windows already being "on" that workspace.
As we now assert that the list contains all windows located on the
workspace, we need to initialize it correctly to avoid a crash.

https://bugzilla.gnome.org/show_bug.cgi?id=737581
2014-09-30 00:24:14 +02:00
Florian Müllner
9f8b641472 display: Optionally sort window list
https://bugzilla.gnome.org/show_bug.cgi?id=737581
2014-09-30 00:24:14 +02:00
Rico Tzschichholz
a9a21c801c configure: Require gbm >= 10.3
Needed for 488dd0b402
2014-09-29 23:13:59 +02:00
Florian Müllner
482a97466d window: Fix typo 2014-09-27 07:41:10 +02:00
Florian Müllner
4e14bb9df3 window: Fix corner case in set_demands_attention()
We only grant requests to set the demands-attention hint if the window
is at least partially obscured; so for non-minimized windows on the
active workspace, we check if any other window on the same workspace
that is higher in the stack overlaps.
However in the case of a sticky window, window->workspace is NULL, so
we end up considering any non-sticky window on a different workspace.

At this point we have already established that the window is showing
on the active workspace, so use that to filter for windows that may
overlap.
2014-09-27 06:43:16 +02:00
Florian Müllner
df90545258 window: Fix crash when mapping sticky window
Since the introduction of set_workspace_state(), window->workspace
will always be NULL when on_all_workspaces is set - passing that
to a workspace function that does not validate its input will then
result in a crash.
Use the get_workspace() function instead, which will always return
a valid workspace.
2014-09-27 06:41:35 +02:00
Florian Müllner
c954f9cc24 workspace: Fix typo in META_IS_WORKSPACE macro 2014-09-27 06:37:38 +02:00
Florian Müllner
d06b39d13c window: Fix another case of uninitialized workspace state
Since commit 2eec11b445, windows without a __NET_WM_DESKTOP property
that should be on all workspaces are not added to the active workspace;
this is correct, however not adding them to any workspace is not ...
2014-09-26 11:48:11 +01:00
Jasper St. Pierre
f3595ebd08 monitor-manager: Make sure to emit PropertiesChanged for PowerSaveMode
We overrode the property for PowerSaveMode, which meant that gdbus's
auto-generated PropertiesChanged code wasn't being run.

This really confused gnome-rr and gnome-settings-daemon's power plugin
about the current DPMS state of the display, since they used their
cached PowerSaveMode properties, and never saw a PropertiesChanged being
emitted.

If a display was on, they set it to off, and then set it back on, the
setting back on would never fire, since they thought the display was
already off.

To fix this, remove our custom property override and just respond to
notifications on the object.

Namely, this fixes the DPMS management when receiving notifications so
that it now properly times out.
2014-09-25 20:17:53 -06:00
Florian Müllner
1e1ca47ec1 window: Always set workspace state while constructing
set_workspace_state () returns early when the desired sticky state
and workspace match the current property values, assuming that the
corresponding MRU lists are already correct in that case.
However that might not be the case when we are setting the initial
state, so don't take the shortcut in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=737178
2014-09-25 15:16:09 +01:00
Florian Müllner
2eec11b445 window: Be more careful when setting initial workspace state
A window may either be sticky because it has been requested as such,
or because it is placed on a non-primary monitor (and the corresponding
preference is set). While we do take the latter into account, we
currently override the sticky state later during initialization;
be a bit more careful there to get the initial state right.

https://bugzilla.gnome.org/show_bug.cgi?id=737178
2014-09-25 15:16:09 +01:00
Saibal Ray
8ff4597201 Updated Bengali (India) translation 2014-09-25 08:26:38 +00:00
Alexander Shopov
d5f2468d88 Updated Bulgarian translation 2014-09-25 06:28:04 +03:00
Jasper St. Pierre
488dd0b402 Support for hardware cursor sizes other than 64x64 on wayland
Use the new DRM capabilities to figure out the correct cursor size, and
make sure that matches instead of hardcoding 64x64. This fixes incorrect
rendering on some newer AMD cards that support 256x256 cursors.

Based heavily on a patch by:
Alvaro Fernando García <alvarofernandogarcia@gmail.com>
2014-09-24 15:42:17 -06:00
Jasper St. Pierre
6565bca210 wayland: Send accurate capabilities
mutter now knows whether the app menu should be shown, so expose this
properly under Wayland as well.
2014-09-24 15:42:17 -06:00
Rui Matos
60c22b6236 keybindings: Do a breadth first search in our keysym to keycode code
Commit 1af0033368 made a subtle change
regarding how XKeysymToKeycode behaves. It does a depth first search
while XKeysymToKeycode is documented to do a breadth first search:

"this function looks in each column of the core keyboard mapping in
turn and returns the lowest numbered key that matches in the lowest
numbered group" - from the XKB library documentation

Looping over all keycodes for each layout and level index makes us go
back to the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=737134
2014-09-24 23:20:42 +02:00
Owen W. Taylor
d3111a9f07 Fix stacking of the guard window
With the change to how hidden windows are stacked, the position
of the guard window with respect to the hidden windows got flipped
and the guard window was at the bottom of everything; fix it to
be on top of the hidden windows.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:51:20 -04:00
Owen W. Taylor
cdfb301200 Add a test for stacking vs. minimization
Test that the guard window is in the right place.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:51:20 -04:00
Owen W. Taylor
371560c2b6 tests: Add minimize/unminimize commands
Add commands to request the client to minimize or unminimize the window;
unminimize doesn't currently work for GTK+ because it expects XMapRequest
to be received by the window manager, but the window is already mapped.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
Owen W. Taylor
7616881afa test-runner: represent the guard window as '|' for assert_stacking
Allow putting '|' into the list of windows for assert_stacking to
represent the position of the guard window. Not present is the same
as at the beginning (bottom) of the list.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
Owen W. Taylor
74c37d49c4 test-runner: make test_case_wait() wait for queued-work
Sometimes (for example with minimization) a request from the client
causes queued work rather than immediate work; so make the test client
'wait' command wait for a full frame cycle.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
Мирослав Николић
d3142b92f0 Updated Serbian translation 2014-09-24 11:10:30 +02:00
Krishnababu Krothapalli
ae2afa7c5e Updated Telugu translation 2014-09-23 14:48:16 +00:00
Florian Müllner
4a71621fbc keybindings: Fix indentation 2014-09-22 22:01:37 +02:00
Florian Müllner
565b9d73d5 keybindings: Do not depend on linux headers for above-tab key
Commit 2f229c3928 removed the code to compute the above-tab
keycode and replaced it with a simple constant from linux/input.h.
We obviously cannot depend on linux headers on non-linux systems,
so provide a fallback definition in that case (which is expected
to work assuming the system is using the Xorg xf86-input-keyboard
driver).

https://bugzilla.gnome.org/show_bug.cgi?id=737135
2014-09-22 21:54:48 +02:00
Florian Müllner
90bd02ff4d constraints: Fix update_onscreen_requirements()
Another missing translation into screen coordinates ...

https://bugzilla.gnome.org/show_bug.cgi?id=736915
2014-09-22 20:12:08 +02:00
Florian Müllner
73ca0efaeb window: Fix titlebar_is_onscreen() test
The titlebar rect is in window coordinates, while screen regions are
obviously not. Fix by translating into screen coordinates before
testing for overlaps.

https://bugzilla.gnome.org/show_bug.cgi?id=736915
2014-09-22 20:12:08 +02:00
89 changed files with 7793 additions and 8826 deletions

2
.gitignore vendored
View File

@@ -66,6 +66,8 @@ src/meta-dbus-idle-monitor.[ch]
src/meta-dbus-login1.[ch]
src/gtk-shell-protocol.c
src/gtk-shell-server-protocol.h
src/scaler-protocol.c
src/scaler-server-protocol.h
src/xdg-shell-protocol.c
src/xdg-shell-server-protocol.h
src/xserver-protocol.c

38
NEWS
View File

@@ -1,3 +1,41 @@
3.15.1
======
* Use GResources for theme loading [Cosimo; #736936]
* Fix headerbar drag getting stuck on xwayland [Carlos; #738411]
* Fix wayland hiDPI regressions [Adel; #739161]
* Misc bug fixes and cleanups [Jasper, Rui, Carlos; #662962, #738630, #738888,
#738890]
Contributors:
Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre
3.14.1
======
* Fix move-titlebar-onscreen function [Florian; #736915]
* Fix stacking of the guard window [Owen; #737233]
* Fix keycode lookup for non-default layouts [Rui; #737134]
* Fix workspaces-only-on-primary handling [Florian; #737178]
* Don't unstick sticky windows on workspace removal [Florian; #737625]
* Do not auto-minimize fullscreen windows [Jasper; #705177]
* Upload keymap to newly added keyboard devices [Rui; #737673]
* Apply keyboard repeat settings [Rui; #728055]
* Don't send pressed keys on enter [Rui; #727178]
* Fix build without wayland/native [Rico; #738225]
* Send modifiers after the key event [Rui; #738238]
* Fix unredirect heuristic [Adel; #738271]
* Do not show system chrome over fullscreen windows [Florian; #693991]
* Misc. bug fixes [Florian, Adel, Tom; #737135, #737581, #738146, #738384]
Contributors:
Tom Beckmann, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre, Rico Tzschichholz, Owen W. Taylor
Translations:
Krishnababu Krothapalli [te], Мирослав Николић [sr, sr@latin],
Alexander Shopov [bg], Saibal Ray [bn_IN], Milo Casagrande [it],
Rūdolfs Mazurs [lv]
3.14.0
======
* Fix placement of popup windows on wayland [Jasper; #736812]

View File

@@ -1,8 +1,8 @@
AC_PREREQ(2.62)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [14])
m4_define([mutter_micro_version], [0])
m4_define([mutter_minor_version], [15])
m4_define([mutter_micro_version], [1])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -77,9 +77,7 @@ MUTTER_PC_MODULES="
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
$CLUTTER_PACKAGE >= 1.19.5
clutter-egl-1.0
cogl-1.0 >= 1.17.1
gbm
upower-glib >= 0.99.0
gnome-desktop-3.0
xcomposite >= 0.2
@@ -202,7 +200,7 @@ AC_SUBST(XWAYLAND_PATH)
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [libdrm libsystemd libinput], [have_native_backend=yes], [have_native_backend=no])
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gudev-1.0 gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
if test $have_native_backend = yes; then
AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
fi

View File

@@ -259,8 +259,6 @@ Overview of Theme Format Version 1
<!-- color obtained by a 0.5 alpha composite of the second color onto the first -->
<color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/>
</gradient>
<!-- image has an optional colorize="#color" attribute to give the
image a certain color -->
<image filename="foo.png" alpha="0.7"
x="10" y="30" width="width / 3" height="height / 4"/>
<gtk_arrow state="normal" shadow="in" arrow="up"

1503
po/bg.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1346
po/it.po

File diff suppressed because it is too large Load Diff

1301
po/lv.po

File diff suppressed because it is too large Load Diff

1300
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1865
po/te.po

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ stackingdir = $(pkgdatadir)/tests/stacking
dist_stacking_DATA = \
tests/stacking/basic-x11.metatest \
tests/stacking/basic-wayland.metatest \
tests/stacking/minimized.metatest \
tests/stacking/mixed-windows.metatest \
tests/stacking/override-redirect.metatest
@@ -40,11 +41,9 @@ endif
# Some random test programs for bits of the code
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
noinst_PROGRAMS+=testboxes testgradient testasyncgetprop
noinst_PROGRAMS+=testboxes testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la

View File

@@ -6,6 +6,7 @@ lib_LTLIBRARIES = libmutter.la
SUBDIRS=compositor/plugins
EXTRA_DIST =
NULL =
AM_CPPFLAGS = \
-DCLUTTER_ENABLE_COMPOSITOR_API \
@@ -31,26 +32,32 @@ AM_CPPFLAGS = \
-DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \
-DMUTTER_PLUGIN_DIR=\"$(MUTTER_PLUGIN_DIR)\" \
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
-DXWAYLAND_PATH=\"$(XWAYLAND_PATH)\"
-DXWAYLAND_PATH=\"$(XWAYLAND_PATH)\" \
$(NULL)
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_display_config_built_sources) \
$(dbus_login1_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c
mutter-enum-types.c \
$(NULL)
if HAVE_WAYLAND
mutter_built_sources += \
gtk-shell-protocol.c \
gtk-shell-server-protocol.h \
xdg-shell-protocol.c \
xdg-shell-server-protocol.h
xdg-shell-server-protocol.h \
scaler-protocol.c \
scaler-server-protocol.h \
$(NULL)
endif
wayland_protocols = \
wayland_protocols = \
wayland/protocol/gtk-shell.xml \
wayland/protocol/xdg-shell.xml
wayland/protocol/xdg-shell.xml \
$(NULL)
libmutter_la_SOURCES = \
backends/meta-backend.c \
@@ -109,6 +116,10 @@ libmutter_la_SOURCES = \
compositor/meta-background-group.c \
compositor/meta-cullable.c \
compositor/meta-cullable.h \
compositor/meta-dnd-actor.c \
compositor/meta-dnd-actor-private.h \
compositor/meta-feedback-actor.c \
compositor/meta-feedback-actor-private.h \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
@@ -158,8 +169,6 @@ libmutter_la_SOURCES = \
meta/errors.h \
core/frame.c \
core/frame.h \
ui/gradient.c \
meta/gradient.h \
core/meta-gesture-tracker.c \
core/meta-gesture-tracker-private.h \
core/keybindings.c \
@@ -218,7 +227,8 @@ libmutter_la_SOURCES = \
x11/window-x11-private.h \
x11/xprops.c \
x11/xprops.h \
x11/mutter-Xatomtype.h
x11/mutter-Xatomtype.h \
$(NULL)
if HAVE_WAYLAND
libmutter_la_SOURCES += \
@@ -230,6 +240,10 @@ libmutter_la_SOURCES += \
wayland/meta-xwayland.c \
wayland/meta-xwayland.h \
wayland/meta-xwayland-private.h \
wayland/meta-wayland-buffer.c \
wayland/meta-wayland-buffer.h \
wayland/meta-wayland-region.c \
wayland/meta-wayland-region.h \
wayland/meta-wayland-data-device.c \
wayland/meta-wayland-data-device.h \
wayland/meta-wayland-keyboard.c \
@@ -247,7 +261,8 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-outputs.c \
wayland/meta-wayland-outputs.h \
wayland/window-wayland.c \
wayland/window-wayland.h
wayland/window-wayland.h \
$(NULL)
endif
if HAVE_NATIVE_BACKEND
@@ -263,11 +278,11 @@ libmutter_la_SOURCES += \
backends/native/meta-launcher.c \
backends/native/meta-launcher.h \
backends/native/dbus-utils.c \
backends/native/dbus-utils.h
backends/native/dbus-utils.h \
$(NULL)
endif
nodist_libmutter_la_SOURCES = \
$(mutter_built_sources)
nodist_libmutter_la_SOURCES = $(mutter_built_sources)
libmutter_la_LDFLAGS = -no-undefined
libmutter_la_LIBADD = $(MUTTER_LIBS) $(MUTTER_NATIVE_BACKEND_LIBS)
@@ -282,7 +297,6 @@ libmutterinclude_headers = \
meta/compositor.h \
meta/display.h \
meta/errors.h \
meta/gradient.h \
meta/group.h \
meta/keybindings.h \
meta/main.h \
@@ -303,7 +317,8 @@ libmutterinclude_headers = \
meta/types.h \
meta/util.h \
meta/window.h \
meta/workspace.h
meta/workspace.h \
$(NULL)
libmutterinclude_built_headers = \
meta/meta-version.h
@@ -384,14 +399,15 @@ DISTCLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
org.gnome.Mutter.DisplayConfig.xml \
org.gnome.Mutter.IdleMonitor.xml
org.gnome.Mutter.IdleMonitor.xml \
$(NULL)
BUILT_SOURCES = \
$(mutter_built_sources) \

View File

@@ -29,8 +29,11 @@
typedef struct {
CoglTexture2D *texture;
struct gbm_bo *bo;
int hot_x, hot_y;
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *bo;
#endif
} MetaCursorImage;
struct _MetaCursorReference {
@@ -44,8 +47,10 @@ CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor
int *hot_x,
int *hot_y);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
int *hot_y);
#endif
#endif /* META_CURSOR_PRIVATE_H */

View File

@@ -27,7 +27,9 @@
* pointer abstraction"
*/
#include <config.h>
#include "config.h"
#include "meta-cursor-tracker-private.h"
#include <string.h>
#include <meta/main.h>
#include <meta/util.h>
@@ -38,11 +40,10 @@
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/extensions/Xfixes.h>
#include "meta-backend-private.h"
#include "meta-cursor-private.h"
#include "meta-cursor-tracker-private.h"
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);

View File

@@ -56,8 +56,11 @@ static void
meta_cursor_image_free (MetaCursorImage *image)
{
cogl_object_unref (image->texture);
#ifdef HAVE_NATIVE_BACKEND
if (image->bo)
gbm_bo_destroy (image->bo);
#endif
}
static void
@@ -139,70 +142,90 @@ load_cursor_on_client (MetaCursor cursor)
meta_prefs_get_cursor_size ());
}
#ifdef HAVE_NATIVE_BACKEND
static void
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
{
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
{
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
return;
}
g_assert_not_reached ();
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static void
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
MetaCursorImage *image,
uint8_t *pixels,
int width,
int height,
uint width,
uint height,
int rowstride,
uint32_t gbm_format)
{
if (width > 64 || height > 64)
uint64_t cursor_width, cursor_height;
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (width > cursor_width || height > cursor_height)
{
meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
(unsigned int)cursor_width, (unsigned int)cursor_height);
return;
}
if (gbm_device_is_format_supported (gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{
uint8_t buf[4 * 64 * 64];
int i;
uint8_t buf[4 * cursor_width * cursor_height];
uint i;
image->bo = gbm_bo_create (gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
image->bo = gbm_bo_create (gbm, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4);
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
gbm_bo_write (image->bo, buf, 64 * 64 * 4);
gbm_bo_write (image->bo, buf, cursor_width * cursor_height * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static struct gbm_device *
get_gbm_device (void)
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
#endif
return NULL;
else
return NULL;
}
#endif
static void
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
XcursorImage *xc_image)
{
int width, height, rowstride;
uint width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
struct gbm_device *gbm;
width = xc_image->width;
height = xc_image->height;
rowstride = width * 4;
gbm_format = GBM_FORMAT_ARGB8888;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
#else
@@ -221,13 +244,15 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
(uint8_t *) xc_image->pixels,
NULL);
gbm = get_gbm_device ();
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) xc_image->pixels,
width, height, rowstride,
gbm_format);
GBM_FORMAT_ARGB8888);
#endif
}
MetaCursorReference *
@@ -256,13 +281,8 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
int hot_x,
int hot_y)
{
struct gbm_device *gbm = get_gbm_device ();
ClutterBackend *backend;
CoglContext *cogl_context;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
int width, height;
image->hot_x = hot_x;
image->hot_y = hot_y;
@@ -272,13 +292,19 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
{
if (gbm)
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
uint width, height;
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
@@ -310,29 +336,28 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
width, height, rowstride,
gbm_format);
}
}
else
{
/* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
that, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
if (width != 64 || height != 64)
else
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
size, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (gbm)
{
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (width != cursor_width || height != cursor_height)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER, buffer, GBM_BO_USE_CURSOR);
if (!image->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
}
#endif
}
MetaCursorReference *
@@ -362,6 +387,7 @@ meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
return COGL_TEXTURE (cursor->image.texture);
}
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
@@ -373,6 +399,7 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
*hot_y = cursor->image.hot_y;
return cursor->image.bo;
}
#endif
MetaCursor
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)

View File

@@ -67,6 +67,7 @@ typedef struct {
} MetaOutputConfig;
typedef struct {
guint refcount;
MetaOutputKey *keys;
MetaOutputConfig *outputs;
unsigned int n_outputs;
@@ -77,7 +78,6 @@ struct _MetaMonitorConfig {
GHashTable *configs;
MetaConfiguration *current;
gboolean current_is_stored;
gboolean current_is_for_laptop_lid;
MetaConfiguration *previous;
@@ -124,11 +124,29 @@ config_clear (MetaConfiguration *config)
g_free (config->outputs);
}
static void
config_free (gpointer config)
static MetaConfiguration *
config_ref (MetaConfiguration *config)
{
config_clear (config);
g_slice_free (MetaConfiguration, config);
config->refcount++;
return config;
}
static void
config_unref (MetaConfiguration *config)
{
if (--config->refcount == 0)
{
config_clear (config);
g_slice_free (MetaConfiguration, config);
}
}
static MetaConfiguration *
config_new (void)
{
MetaConfiguration *config = g_slice_new0 (MetaConfiguration);
config->refcount = 1;
return config;
}
static unsigned long
@@ -220,7 +238,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
const char *filename;
char *path;
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, config_free);
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref);
filename = g_getenv ("MUTTER_MONITOR_FILENAME");
if (filename == NULL)
@@ -796,27 +814,6 @@ make_config_key (MetaConfiguration *key,
key->n_outputs = o;
}
gboolean
meta_monitor_config_match_current (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
MetaOutput *outputs;
unsigned n_outputs;
MetaConfiguration key;
gboolean ok;
if (self->current == NULL)
return FALSE;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
make_config_key (&key, outputs, n_outputs, -1);
ok = config_equal (&key, self->current);
config_clear (&key);
return ok;
}
gboolean
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
{
@@ -851,73 +848,45 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
return stored;
}
static void
set_current (MetaMonitorConfig *self,
MetaConfiguration *config)
{
g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
self->previous = self->current;
self->current = config_ref (config);
}
static gboolean
apply_configuration (MetaMonitorConfig *self,
MetaConfiguration *config,
MetaMonitorManager *manager,
gboolean stored)
MetaMonitorManager *manager)
{
GPtrArray *crtcs, *outputs;
gboolean ret = FALSE;
crtcs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_crtc_info_free);
outputs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_output_info_free);
if (!meta_monitor_config_assign_crtcs (config, manager, crtcs, outputs))
{
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
if (!stored)
config_free (config);
return FALSE;
}
goto out;
meta_monitor_manager_apply_configuration (manager,
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
(MetaOutputInfo**)outputs->pdata, outputs->len);
/* Stored (persistent) configurations override the previous one always.
Also, we clear the previous configuration if the current one (which is
about to become previous) is stored, or if the current one has
different outputs.
*/
if (stored ||
(self->current && self->current_is_stored))
{
if (self->previous)
config_free (self->previous);
self->previous = NULL;
}
else
{
/* Despite the name, config_equal() only checks the set of outputs,
not their modes
*/
if (self->current && config_equal (self->current, config))
{
self->previous = self->current;
}
else
{
if (self->current)
config_free (self->current);
self->previous = NULL;
}
}
set_current (self, config);
self->current = config;
self->current_is_stored = stored;
/* If true, we'll be overridden at the end of this call
inside turn_off_laptop_display()
*/
* inside turn_off_laptop_display / apply_configuration_with_lid */
self->current_is_for_laptop_lid = FALSE;
if (self->current == self->previous)
self->previous = NULL;
ret = TRUE;
out:
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
return TRUE;
return ret;
}
static gboolean
@@ -945,6 +914,19 @@ laptop_display_is_on (MetaConfiguration *config)
return FALSE;
}
static gboolean
multiple_outputs_are_enabled (MetaConfiguration *config)
{
unsigned int i, enabled;
enabled = 0;
for (i = 0; i < config->n_outputs; i++)
if (config->outputs[i].enabled)
enabled++;
return enabled > 1;
}
static MetaConfiguration *
make_laptop_lid_config (MetaConfiguration *reference)
{
@@ -954,9 +936,9 @@ make_laptop_lid_config (MetaConfiguration *reference)
int x_after, y_after;
int x_offset, y_offset;
g_assert (reference->n_outputs > 1);
g_assert (multiple_outputs_are_enabled (reference));
new = g_slice_new0 (MetaConfiguration);
new = config_new ();
new->n_outputs = reference->n_outputs;
new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
@@ -1011,6 +993,32 @@ make_laptop_lid_config (MetaConfiguration *reference)
return new;
}
static gboolean
apply_configuration_with_lid (MetaMonitorConfig *self,
MetaConfiguration *config,
MetaMonitorManager *manager)
{
if (self->lid_is_closed &&
multiple_outputs_are_enabled (config) &&
laptop_display_is_on (config))
{
MetaConfiguration *laptop_lid_config = make_laptop_lid_config (config);
if (apply_configuration (self, laptop_lid_config, manager))
{
self->current_is_for_laptop_lid = TRUE;
config_unref (laptop_lid_config);
return TRUE;
}
else
{
config_unref (laptop_lid_config);
return FALSE;
}
}
else
return apply_configuration (self, config, manager);
}
gboolean
meta_monitor_config_apply_stored (MetaMonitorConfig *self,
MetaMonitorManager *manager)
@@ -1023,23 +1031,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
stored = meta_monitor_config_get_stored (self, outputs, n_outputs);
if (stored)
{
if (self->lid_is_closed &&
stored->n_outputs > 1 &&
laptop_display_is_on (stored))
{
if (apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE))
{
self->current_is_for_laptop_lid = TRUE;
return TRUE;
}
else
return FALSE;
}
else
return apply_configuration (self, stored, manager, TRUE);
}
return apply_configuration_with_lid (self, stored, manager);
else
return FALSE;
}
@@ -1089,6 +1081,21 @@ find_primary_output (MetaOutput *outputs,
return best;
}
static void
init_config_from_preferred_mode (MetaOutputConfig *config,
MetaOutput *output)
{
config->enabled = TRUE;
config->rect.x = 0;
config->rect.y = 0;
config->rect.width = output->preferred_mode->width;
config->rect.height = output->preferred_mode->height;
config->refresh_rate = output->preferred_mode->refresh_rate;
config->transform = META_MONITOR_TRANSFORM_NORMAL;
config->is_primary = FALSE;
config->is_presentation = FALSE;
}
static MetaConfiguration *
make_default_config (MetaMonitorConfig *self,
MetaOutput *outputs,
@@ -1101,7 +1108,7 @@ make_default_config (MetaMonitorConfig *self,
MetaConfiguration *ret;
MetaOutput *primary;
ret = g_slice_new (MetaConfiguration);
ret = config_new ();
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
@@ -1109,15 +1116,8 @@ make_default_config (MetaMonitorConfig *self,
nothing else to do */
if (n_outputs == 1)
{
ret->outputs[0].enabled = TRUE;
ret->outputs[0].rect.x = 0;
ret->outputs[0].rect.y = 0;
ret->outputs[0].rect.width = outputs[0].preferred_mode->width;
ret->outputs[0].rect.height = outputs[0].preferred_mode->height;
ret->outputs[0].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[0].transform = META_MONITOR_TRANSFORM_NORMAL;
init_config_from_preferred_mode (&ret->outputs[0], &outputs[0]);
ret->outputs[0].is_primary = TRUE;
return ret;
}
@@ -1161,15 +1161,7 @@ make_default_config (MetaMonitorConfig *self,
}
else
{
ret->outputs[j].enabled = TRUE;
ret->outputs[j].rect.x = 0;
ret->outputs[j].rect.y = 0;
ret->outputs[j].rect.width = outputs[0].preferred_mode->width;
ret->outputs[j].rect.height = outputs[0].preferred_mode->height;
ret->outputs[j].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[j].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[j].is_primary = FALSE;
ret->outputs[j].is_presentation = FALSE;
init_config_from_preferred_mode (&ret->outputs[j], &outputs[0]);
}
}
@@ -1194,22 +1186,24 @@ make_default_config (MetaMonitorConfig *self,
x = primary->preferred_mode->width;
for (i = 0; i < n_outputs; i++)
{
MetaOutput *output = &outputs[i];
gboolean is_primary = (&outputs[i] == primary);
ret->outputs[i].enabled = TRUE;
ret->outputs[i].rect.x = (output == primary) ? 0 : x;
ret->outputs[i].rect.y = 0;
ret->outputs[i].rect.width = output->preferred_mode->width;
ret->outputs[i].rect.height = output->preferred_mode->height;
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[i].is_primary = (output == primary);
init_config_from_preferred_mode (&ret->outputs[i], &outputs[i]);
ret->outputs[i].is_primary = is_primary;
if (is_primary)
{
ret->outputs[i].rect.x = 0;
}
else
{
ret->outputs[i].rect.x = x;
x += ret->outputs[i].rect.width;
}
/* Disable outputs that would go beyond framebuffer limits */
if (ret->outputs[i].rect.x + ret->outputs[i].rect.width > max_width)
ret->outputs[i].enabled = FALSE;
else if (output != primary)
x += output->preferred_mode->width;
}
return ret;
@@ -1221,7 +1215,7 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
MetaOutput *outputs,
unsigned n_outputs)
{
MetaConfiguration *ret;
MetaConfiguration *config;
MetaOutput *primary;
unsigned i;
@@ -1232,34 +1226,29 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
/* Oh no, we don't! Activate the primary one and disable everything else */
ret = g_slice_new (MetaConfiguration);
make_config_key (ret, outputs, n_outputs, -1);
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
config = config_new ();
make_config_key (config, outputs, n_outputs, -1);
config->outputs = g_new0 (MetaOutputConfig, n_outputs);
primary = find_primary_output (outputs, n_outputs);
for (i = 0; i < n_outputs; i++)
{
MetaOutput *output = &outputs[i];
gboolean is_primary = (&outputs[i] == primary);
if (output == primary)
if (is_primary)
{
ret->outputs[i].enabled = TRUE;
ret->outputs[i].rect.x = 0;
ret->outputs[i].rect.y = 0;
ret->outputs[i].rect.width = output->preferred_mode->width;
ret->outputs[i].rect.height = output->preferred_mode->height;
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
ret->outputs[i].is_primary = TRUE;
init_config_from_preferred_mode (&config->outputs[i], &outputs[0]);
config->outputs[i].is_primary = TRUE;
}
else
{
ret->outputs[i].enabled = FALSE;
config->outputs[i].enabled = FALSE;
}
}
apply_configuration (self, ret, manager, FALSE);
apply_configuration (self, config, manager);
config_unref (config);
return FALSE;
}
@@ -1270,7 +1259,7 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
MetaOutput *outputs;
MetaConfiguration *default_config;
unsigned n_outputs;
gboolean ok;
gboolean ok = FALSE;
int max_width, max_height;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
@@ -1283,22 +1272,11 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
}
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
if (default_config != NULL)
{
if (self->lid_is_closed &&
default_config->n_outputs > 1 &&
laptop_display_is_on (default_config))
{
ok = apply_configuration (self, make_laptop_lid_config (default_config),
manager, FALSE);
config_free (default_config);
}
else
ok = apply_configuration (self, default_config, manager, FALSE);
ok = apply_configuration_with_lid (self, default_config, manager);
config_unref (default_config);
}
else
ok = FALSE;
if (!ok)
{
@@ -1335,7 +1313,7 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
current = g_slice_new (MetaConfiguration);
current = config_new ();
current->n_outputs = n_outputs;
current->outputs = g_new0 (MetaOutputConfig, n_outputs);
current->keys = g_new0 (MetaOutputKey, n_outputs);
@@ -1348,15 +1326,11 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
if (self->current && config_equal_full (current, self->current))
{
config_free (current);
config_unref (current);
return;
}
if (self->current && !self->current_is_stored)
config_free (self->current);
self->current = current;
self->current_is_stored = FALSE;
set_current (self, current);
}
void
@@ -1364,7 +1338,17 @@ meta_monitor_config_restore_previous (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
if (self->previous)
apply_configuration (self, self->previous, manager, FALSE);
{
/* The user chose to restore the previous configuration. In this
* case, restore the previous configuration. */
MetaConfiguration *prev_config = config_ref (self->previous);
apply_configuration (self, prev_config, manager);
config_unref (prev_config);
/* After this, self->previous contains the rejected configuration.
* Since it was rejected, nuke it. */
g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
}
else
{
if (!meta_monitor_config_apply_stored (self, manager))
@@ -1378,11 +1362,12 @@ turn_off_laptop_display (MetaMonitorConfig *self,
{
MetaConfiguration *new;
if (self->current->n_outputs == 1)
if (!multiple_outputs_are_enabled (self->current))
return;
new = make_laptop_lid_config (self->current);
apply_configuration (self, new, manager, FALSE);
apply_configuration (self, new, manager);
config_unref (new);
self->current_is_for_laptop_lid = TRUE;
}
@@ -1541,16 +1526,7 @@ meta_monitor_config_save (MetaMonitorConfig *self)
void
meta_monitor_config_make_persistent (MetaMonitorConfig *self)
{
if (self->current_is_stored)
return;
self->current_is_stored = TRUE;
g_hash_table_replace (self->configs, self->current, self->current);
if (self->previous)
config_free (self->previous);
self->previous = NULL;
g_hash_table_replace (self->configs, self->current, config_ref (self->current));
meta_monitor_config_save (self);
}

View File

@@ -36,9 +36,6 @@ GType meta_monitor_config_get_type (void) G_GNUC_CONST;
MetaMonitorConfig *meta_monitor_config_new (void);
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
MetaMonitorManager *manager);

View File

@@ -44,12 +44,6 @@ enum {
SIGNALS_LAST
};
enum {
PROP_0,
PROP_POWER_SAVE_MODE,
PROP_LAST
};
static int signals[SIGNALS_LAST];
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
@@ -64,14 +58,6 @@ meta_monitor_manager_init (MetaMonitorManager *manager)
{
}
static void
read_current_config (MetaMonitorManager *manager)
{
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
}
/*
* make_logical_config:
*
@@ -167,16 +153,44 @@ make_logical_config (MetaMonitorManager *manager)
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
}
static void
power_save_mode_changed (MetaMonitorManager *manager,
GParamSpec *pspec,
gpointer user_data)
{
MetaMonitorManagerClass *klass;
int mode = meta_dbus_display_config_get_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager));
if (mode == META_POWER_SAVE_UNSUPPORTED)
return;
/* If DPMS is unsupported, force the property back. */
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
{
meta_dbus_display_config_set_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager), META_POWER_SAVE_UNSUPPORTED);
return;
}
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->set_power_save_mode)
klass->set_power_save_mode (manager, mode);
manager->power_save_mode = mode;
}
static void
meta_monitor_manager_constructed (GObject *object)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
g_signal_connect_object (manager, "notify::power-save-mode",
G_CALLBACK (power_save_mode_changed), manager, 0);
manager->in_init = TRUE;
manager->config = meta_monitor_config_new ();
read_current_config (manager);
meta_monitor_manager_read_current_config (manager);
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
@@ -189,24 +203,7 @@ meta_monitor_manager_constructed (GObject *object)
so this is not needed.
*/
if (META_IS_MONITOR_MANAGER_XRANDR (manager))
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
meta_monitor_manager_read_current_config (manager);
make_logical_config (manager);
initialize_dbus_interface (manager);
@@ -215,23 +212,6 @@ meta_monitor_manager_constructed (GObject *object)
}
static void
meta_monitor_manager_set_power_save_mode (MetaMonitorManager *manager,
MetaPowerSave mode)
{
MetaMonitorManagerClass *klass;
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED ||
mode == META_POWER_SAVE_UNSUPPORTED)
return;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->set_power_save_mode)
klass->set_power_save_mode (manager, mode);
manager->power_save_mode = mode;
}
void
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
{
@@ -254,7 +234,7 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
g_free (old_outputs);
}
void
static void
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes)
{
@@ -298,44 +278,6 @@ meta_monitor_manager_dispose (GObject *object)
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
}
static void
meta_monitor_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
switch (prop_id)
{
case PROP_POWER_SAVE_MODE:
meta_monitor_manager_set_power_save_mode (self, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_monitor_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
switch (prop_id)
{
case PROP_POWER_SAVE_MODE:
g_value_set_int (value, self->power_save_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GBytes *
meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
MetaOutput *output)
@@ -356,8 +298,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = meta_monitor_manager_constructed;
object_class->get_property = meta_monitor_manager_get_property;
object_class->set_property = meta_monitor_manager_set_property;
object_class->dispose = meta_monitor_manager_dispose;
object_class->finalize = meta_monitor_manager_finalize;
@@ -371,8 +311,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_object_class_override_property (object_class, PROP_POWER_SAVE_MODE, "power-save-mode");
}
static const double known_diagonals[] = {
@@ -1199,6 +1137,31 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
*height = manager->max_screen_height;
}
void
meta_monitor_manager_read_current_config (MetaMonitorManager *manager)
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
/* Some implementations of read_current use the existing information
* we have available, so don't free the old configuration until after
* read_current finishes. */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
void
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
{
@@ -1216,3 +1179,22 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
g_free (old_monitor_infos);
}
void
meta_monitor_manager_on_hotplug (MetaMonitorManager *manager)
{
gboolean applied_config = FALSE;
/* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
* applying our stored configuration, because it's likely the user just resizing
* the window.
*/
if (!meta_monitor_manager_has_hotplug_mode_update (manager))
{
if (meta_monitor_config_apply_stored (manager->config, manager))
applied_config = TRUE;
}
/* If we haven't applied any configuration, apply the default configuration. */
if (!applied_config)
meta_monitor_config_make_default (manager->config, manager);
}

View File

@@ -339,11 +339,9 @@ void meta_monitor_manager_confirm_configuration (MetaMonitorManag
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes);
gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
void meta_monitor_manager_read_current_config (MetaMonitorManager *manager);
void meta_monitor_manager_on_hotplug (MetaMonitorManager *manager);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */

View File

@@ -36,11 +36,24 @@
struct _MetaBackendNativePrivate
{
MetaLauncher *launcher;
GSettings *keyboard_settings;
};
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendNative, meta_backend_native, META_TYPE_BACKEND);
static void
meta_backend_native_finalize (GObject *object)
{
MetaBackendNative *native = META_BACKEND_NATIVE (object);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
g_clear_object (&priv->keyboard_settings);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
}
/*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
@@ -142,15 +155,46 @@ pointer_constrain_callback (ClutterInputDevice *device,
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
}
static void
set_keyboard_repeat (MetaBackendNative *native)
{
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
gboolean repeat;
unsigned int delay, interval;
repeat = g_settings_get_boolean (priv->keyboard_settings, "repeat");
delay = g_settings_get_uint (priv->keyboard_settings, "delay");
interval = g_settings_get_uint (priv->keyboard_settings, "repeat-interval");
clutter_evdev_set_keyboard_repeat (manager, repeat, delay, interval);
}
static void
keyboard_settings_changed (GSettings *settings,
const char *key,
gpointer data)
{
MetaBackendNative *native = data;
set_keyboard_repeat (native);
}
static void
meta_backend_native_post_init (MetaBackend *backend)
{
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
NULL, NULL);
priv->keyboard_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.keyboard");
g_signal_connect (priv->keyboard_settings, "changed",
G_CALLBACK (keyboard_settings_changed), native);
set_keyboard_repeat (native);
}
static MetaIdleMonitor *
@@ -236,6 +280,9 @@ static void
meta_backend_native_class_init (MetaBackendNativeClass *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_backend_native_finalize;
backend_class->post_init = meta_backend_native_post_init;
backend_class->create_idle_monitor = meta_backend_native_create_idle_monitor;
@@ -271,7 +318,7 @@ meta_activate_vt (int vt, GError **error)
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* Wayland compositor, this tells logind to switch over to
* display server, this tells logind to switch over to
* the new session.
*/
gboolean

View File

@@ -27,16 +27,27 @@
#include "meta-cursor-renderer-native.h"
#include <gbm.h>
#include <xf86drm.h>
#include "meta-cursor-private.h"
#include "meta-monitor-manager.h"
#ifndef DRM_CAP_CURSOR_WIDTH
#define DRM_CAP_CURSOR_WIDTH 0x8
#endif
#ifndef DRM_CAP_CURSOR_HEIGHT
#define DRM_CAP_CURSOR_HEIGHT 0x9
#endif
struct _MetaCursorRendererNativePrivate
{
gboolean has_hw_cursor;
int drm_fd;
struct gbm_device *gbm;
uint64_t cursor_width;
uint64_t cursor_height;
};
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
@@ -71,17 +82,13 @@ set_crtc_cursor (MetaCursorRendererNative *native,
{
struct gbm_bo *bo;
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
bo = meta_cursor_reference_get_gbm_bo (cursor, &hot_x, &hot_y);
handle = gbm_bo_get_handle (bo);
width = gbm_bo_get_width (bo);
height = gbm_bo_get_height (bo);
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
}
else
{
@@ -186,6 +193,19 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
priv->gbm = gbm_create_device (priv->drm_fd);
uint64_t width, height;
if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{
priv->cursor_width = width;
priv->cursor_height = height;
}
else
{
priv->cursor_width = 64;
priv->cursor_height = 64;
}
}
#endif
}
@@ -198,6 +218,16 @@ meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
return priv->gbm;
}
void
meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native,
uint64_t *width, uint64_t *height)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
*width = priv->cursor_width;
*height = priv->cursor_height;
}
void
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
{

View File

@@ -50,6 +50,7 @@ struct _MetaCursorRendererNativeClass
GType meta_cursor_renderer_native_get_type (void) G_GNUC_CONST;
struct gbm_device * meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *renderer);
void meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native, uint64_t *width, uint64_t *height);
void meta_cursor_renderer_native_force_update (MetaCursorRendererNative *renderer);
#endif /* META_CURSOR_RENDERER_NATIVE_H */

View File

@@ -24,6 +24,7 @@
#include "config.h"
#include "meta-monitor-manager-kms.h"
#include "meta-monitor-config.h"
#include <string.h>
#include <stdlib.h>
@@ -40,6 +41,8 @@
#include <meta/errors.h>
#include "edid.h"
#include <gudev/gudev.h>
typedef struct {
drmModeConnector *connector;
@@ -68,6 +71,8 @@ struct _MetaMonitorManagerKms
unsigned int n_encoders;
drmModeEncoder *current_encoder;
GUdevClient *udev;
};
struct _MetaMonitorManagerKmsClass
@@ -893,6 +898,23 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
}
static void
on_uevent (GUdevClient *client,
const char *action,
GUdevDevice *device,
gpointer user_data)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (user_data);
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
if (!g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
return;
meta_monitor_manager_read_current_config (manager);
meta_monitor_manager_on_hotplug (manager);
}
static void
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
{
@@ -907,6 +929,21 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
cogl_renderer = cogl_display_get_renderer (cogl_display);
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
const char *subsystems[2] = { "drm", NULL };
manager_kms->udev = g_udev_client_new (subsystems);
g_signal_connect (manager_kms->udev, "uevent",
G_CALLBACK (on_uevent), manager_kms);
}
static void
meta_monitor_manager_kms_dispose (GObject *object)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
g_clear_object (&manager_kms->udev);
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
}
static void
@@ -925,6 +962,7 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_monitor_manager_kms_dispose;
object_class->finalize = meta_monitor_manager_kms_finalize;
manager_class->read_current = meta_monitor_manager_kms_read_current;

View File

@@ -65,9 +65,14 @@ struct _MetaBackendX11Private
uint8_t xkb_error_base;
struct xkb_keymap *keymap;
gchar *keymap_layouts;
gchar *keymap_variants;
gchar *keymap_options;
};
typedef struct _MetaBackendX11Private MetaBackendX11Private;
static void apply_keymap (MetaBackendX11 *x11);
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11, meta_backend_x11, META_TYPE_BACKEND);
static void
@@ -326,6 +331,17 @@ take_touch_grab (MetaBackend *backend)
False, &mask, 1, &mods);
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (user_data);
if (clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE)
apply_keymap (x11);
}
static void
meta_backend_x11_post_init (MetaBackend *backend)
{
@@ -376,6 +392,9 @@ meta_backend_x11_post_init (MetaBackend *backend)
meta_fatal ("X server doesn't have the XKB extension, version %d.%d or newer\n",
XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION);
g_signal_connect_object (clutter_device_manager_get_default (), "device-added",
G_CALLBACK (on_device_added), backend, 0);
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
}
@@ -560,21 +579,22 @@ upload_xkb_description (Display *xdisplay,
}
static void
meta_backend_x11_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
apply_keymap (MetaBackendX11 *x11)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
XkbRF_RulesRec *xkb_rules;
XkbRF_VarDefsRec xkb_var_defs = { 0 };
gchar *rules_file_path;
if (!priv->keymap_layouts ||
!priv->keymap_variants ||
!priv->keymap_options)
return;
get_xkbrf_var_defs (priv->xdisplay,
layouts,
variants,
options,
priv->keymap_layouts,
priv->keymap_variants,
priv->keymap_options,
&rules_file_path,
&xkb_var_defs);
@@ -598,6 +618,25 @@ meta_backend_x11_set_keymap (MetaBackend *backend,
g_free (rules_file_path);
}
static void
meta_backend_x11_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
g_free (priv->keymap_layouts);
priv->keymap_layouts = g_strdup (layouts);
g_free (priv->keymap_variants);
priv->keymap_variants = g_strdup (variants);
g_free (priv->keymap_options);
priv->keymap_options = g_strdup (options);
apply_keymap (x11);
}
static struct xkb_keymap *
meta_backend_x11_get_keymap (MetaBackend *backend)
{

View File

@@ -26,6 +26,8 @@
#include "meta-cursor-renderer-x11.h"
#include <X11/extensions/Xfixes.h>
#include "meta-backend-x11.h"
#include "meta-stage.h"

View File

@@ -57,7 +57,6 @@ struct _MetaMonitorManagerXrandr
Display *xdisplay;
XRRScreenResources *resources;
int time;
int rr_event_base;
int rr_error_base;
};
@@ -140,11 +139,35 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation)
return ret;
}
static gboolean
output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
{
gboolean exists = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
atom,
0, G_MAXLONG, False, False, AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
exists = (actual_type != None);
XFree (buffer);
return exists;
}
static gboolean
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
{
gboolean value;
gboolean value = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
@@ -158,12 +181,12 @@ output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_CARDINAL || actual_format != 32 ||
nitems < 1)
return FALSE;
if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1)
goto out;
value = ((int*)buffer)[0];
out:
XFree (buffer);
return value;
}
@@ -187,7 +210,7 @@ static int
output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
gboolean value;
int value = -1;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
@@ -201,14 +224,17 @@ output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_INTEGER || actual_format != 32 ||
nitems < 1)
return -1;
if (actual_type != XA_INTEGER || actual_format != 32 || nitems < 1)
goto out;
value = ((int*)buffer)[0];
out:
XFree (buffer);
return normalize_backlight (output, value);
if (value > 0)
return normalize_backlight (output, value);
else
return -1;
}
static void
@@ -327,7 +353,7 @@ static gboolean
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
return output_get_boolean_property (manager_xrandr, output, "hotplug_mode_update");
return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update");
}
static char *
@@ -410,7 +436,6 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
return;
manager_xrandr->resources = resources;
manager_xrandr->time = resources->configTimestamp;
manager->n_outputs = resources->noutput;
manager->n_crtcs = resources->ncrtc;
manager->n_modes = resources->nmode;
@@ -744,7 +769,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
manager_xrandr->time,
CurrentTime,
0, 0,
None,
RR_Rotate_0,
@@ -774,7 +799,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
manager_xrandr->time,
CurrentTime,
0, 0,
None,
RR_Rotate_0,
@@ -857,7 +882,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
manager_xrandr->time,
CurrentTime,
crtc_info->x, crtc_info->y,
(XID)mode->mode_id,
meta_monitor_transform_to_xrandr (crtc_info->transform),
@@ -998,16 +1023,6 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
XRRFreeGamma (gamma);
}
static void
meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
{
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
static void
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
{
@@ -1067,63 +1082,30 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
XEvent *event)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
gboolean new_config;
gboolean hotplug;
Time old_timestamp;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE;
XRRUpdateConfiguration (event);
/* Save the old structures, so they stay valid during the update */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
old_timestamp = manager_xrandr->resources->timestamp;
manager->serial++;
meta_monitor_manager_xrandr_read_current (manager);
new_config = manager_xrandr->resources->timestamp >=
manager_xrandr->resources->configTimestamp;
if (meta_monitor_manager_has_hotplug_mode_update (manager))
meta_monitor_manager_read_current_config (manager);
hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
if (hotplug)
{
/* Check if the current intended configuration is a result of an
XRandR call. Otherwise, hotplug_mode_update tells us to get
a new preferred mode on hotplug events to handle dynamic
guest resizing. */
if (new_config)
meta_monitor_manager_xrandr_rebuild_derived (manager);
else
meta_monitor_config_make_default (manager->config, manager);
/* This is a hotplug event, so go ahead and build a new configuration. */
meta_monitor_manager_on_hotplug (manager);
}
else
{
/* Check if the current intended configuration has the same outputs
as the new real one, or if the event is a result of an XRandR call.
If so, we can go straight to rebuild the logical config and tell
the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with new
configTimestamps (bug 702804), and the driver may have changed
the EDID for some other reason (old qxl and vbox drivers). */
if (new_config || meta_monitor_config_match_current (manager->config, manager))
meta_monitor_manager_xrandr_rebuild_derived (manager);
else if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
/* If something else changed -- tell the world about it. */
if (old_timestamp < manager_xrandr->resources->timestamp)
meta_monitor_manager_rebuild_derived (manager);
}
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
return TRUE;
}

View File

@@ -23,7 +23,7 @@ struct _MetaCompositor
guint server_time_is_monotonic_time : 1;
guint no_mipmaps : 1;
ClutterActor *stage, *window_group, *top_window_group;
ClutterActor *stage, *window_group, *top_window_group, *feedback_group;
ClutterActor *background_actor;
GList *windows;
Window output;

View File

@@ -185,6 +185,19 @@ meta_get_top_window_group_for_screen (MetaScreen *screen)
return compositor->top_window_group;
}
/**
* meta_get_feedback_group_for_screen:
* @screen: a #MetaScreen
*
* Returns: (transfer none): The feedback group corresponding to @screen
*/
ClutterActor *
meta_get_feedback_group_for_screen (MetaScreen *screen)
{
MetaCompositor *compositor = get_compositor_for_screen (screen);
return compositor->feedback_group;
}
/**
* meta_get_window_actors:
* @screen: a #MetaScreen
@@ -478,9 +491,11 @@ meta_compositor_manage (MetaCompositor *compositor)
compositor->window_group = meta_window_group_new (screen);
compositor->top_window_group = meta_window_group_new (screen);
compositor->feedback_group = meta_window_group_new (screen);
clutter_actor_add_child (compositor->stage, compositor->window_group);
clutter_actor_add_child (compositor->stage, compositor->top_window_group);
clutter_actor_add_child (compositor->stage, compositor->feedback_group);
if (meta_is_wayland_compositor ())
{

View File

@@ -708,6 +708,7 @@ on_background_changed (MetaBackground *background,
MetaBackgroundActor *self)
{
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void

View File

@@ -53,7 +53,7 @@ struct _MetaBackgroundImageCacheClass
struct _MetaBackgroundImage
{
GObject parent_instance;
char *filename;
GFile *file;
MetaBackgroundImageCache *cache;
gboolean in_cache;
gboolean loaded;
@@ -70,7 +70,7 @@ G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJ
static void
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
{
cache->images = g_hash_table_new (g_str_hash, g_str_equal);
cache->images = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
}
static void
@@ -124,9 +124,17 @@ load_file (GTask *task,
{
GError *error = NULL;
GdkPixbuf *pixbuf;
GFileInputStream *stream;
pixbuf = gdk_pixbuf_new_from_file (image->filename,
&error);
stream = g_file_read (image->file, NULL, &error);
if (stream == NULL)
{
g_task_return_error (task, error);
return;
}
pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error);
g_object_unref (stream);
if (pixbuf == NULL)
{
@@ -156,9 +164,11 @@ file_loaded (GObject *source_object,
if (pixbuf == NULL)
{
char *uri = g_file_get_uri (image->file);
g_warning ("Failed to load background '%s': %s",
image->filename, error->message);
uri, error->message);
g_clear_error (&error);
g_free (uri);
goto out;
}
@@ -185,6 +195,9 @@ file_loaded (GObject *source_object,
image->texture = texture;
out:
if (pixbuf != NULL)
g_object_unref (pixbuf);
image->loaded = TRUE;
g_signal_emit (image, signals[LOADED], 0);
}
@@ -192,7 +205,7 @@ out:
/**
* meta_background_image_cache_load:
* @cache: a #MetaBackgroundImageCache
* @filename: filename to load
* @file: #GFile to load
*
* Loads an image to use as a background, or returns a reference to an
* image that is already in the process of loading or loaded. In either
@@ -206,23 +219,23 @@ out:
*/
MetaBackgroundImage *
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
const char *filename)
GFile *file)
{
MetaBackgroundImage *image;
GTask *task;
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (file != NULL, NULL);
image = g_hash_table_lookup (cache->images, filename);
image = g_hash_table_lookup (cache->images, file);
if (image != NULL)
return g_object_ref (image);
image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
image->cache = cache;
image->in_cache = TRUE;
image->filename = g_strdup (filename);
g_hash_table_insert (cache->images, image->filename, image);
image->file = g_object_ref (file);
g_hash_table_insert (cache->images, image->file, image);
task = g_task_new (image, NULL, file_loaded, NULL);
@@ -235,25 +248,25 @@ meta_background_image_cache_load (MetaBackgroundImageCache *cache,
/**
* meta_background_image_cache_purge:
* @cache: a #MetaBackgroundImageCache
* @filename: filename to remove from the cache
* @file: file to remove from the cache
*
* Remove an entry from the cache; this would be used if monitoring
* showed that the file changed.
*/
void
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
const char *filename)
GFile *file)
{
MetaBackgroundImage *image;
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
g_return_if_fail (filename != NULL);
g_return_if_fail (file != NULL);
image = g_hash_table_lookup (cache->images, filename);
image = g_hash_table_lookup (cache->images, file);
if (image == NULL)
return;
g_hash_table_remove (cache->images, image->filename);
g_hash_table_remove (cache->images, image->file);
image->in_cache = FALSE;
}
@@ -270,12 +283,12 @@ meta_background_image_finalize (GObject *object)
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
if (image->in_cache)
g_hash_table_remove (image->cache->images, image->filename);
g_hash_table_remove (image->cache->images, image->file);
if (image->texture)
cogl_object_unref (image->texture);
if (image->filename)
g_free (image->filename);
if (image->file)
g_object_unref (image->file);
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
}

View File

@@ -50,9 +50,9 @@ struct _MetaBackgroundPrivate
ClutterColor color;
ClutterColor second_color;
char *filename1;
GFile *file1;
MetaBackgroundImage *background_image1;
char *filename2;
GFile *file2;
MetaBackgroundImage *background_image2;
CoglTexture *color_texture;
@@ -241,16 +241,28 @@ on_background_loaded (MetaBackgroundImage *image,
mark_changed (self);
}
static void
set_filename (MetaBackground *self,
char **filenamep,
MetaBackgroundImage **imagep,
const char *filename)
static gboolean
file_equal0 (GFile *file1,
GFile *file2)
{
if (g_strcmp0 (filename, *filenamep) != 0)
if (file1 == file2)
return TRUE;
if ((file1 == NULL) || (file2 == NULL))
return FALSE;
return g_file_equal (file1, file2);
}
static void
set_file (MetaBackground *self,
GFile **filep,
MetaBackgroundImage **imagep,
GFile *file)
{
if (!file_equal0 (*filep, file))
{
g_free (*filenamep);
*filenamep = g_strdup (filename);
g_clear_object (filep);
if (*imagep)
{
@@ -261,10 +273,12 @@ set_filename (MetaBackground *self,
*imagep = NULL;
}
if (filename)
if (file)
{
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
*imagep = meta_background_image_cache_load (cache, filename);
*filep = g_object_ref (file);
*imagep = meta_background_image_cache_load (cache, file);
g_signal_connect (*imagep, "loaded",
G_CALLBACK (on_background_loaded), self);
}
@@ -280,8 +294,8 @@ meta_background_dispose (GObject *object)
free_color_texture (self);
free_wallpaper_texture (self);
set_filename (self, &priv->filename1, &priv->background_image1, NULL);
set_filename (self, &priv->filename2, &priv->background_image2, NULL);
set_file (self, &priv->file1, &priv->background_image1, NULL);
set_file (self, &priv->file2, &priv->background_image2, NULL);
set_screen (self, NULL);
@@ -867,19 +881,19 @@ meta_background_set_gradient (MetaBackground *self,
}
void
meta_background_set_filename (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style)
meta_background_set_file (MetaBackground *self,
GFile *file,
GDesktopBackgroundStyle style)
{
g_return_if_fail (META_IS_BACKGROUND (self));
meta_background_set_blend (self, filename, NULL, 0.0, style);
meta_background_set_blend (self, file, NULL, 0.0, style);
}
void
meta_background_set_blend (MetaBackground *self,
const char *filename1,
const char *filename2,
GFile *file1,
GFile *file2,
double blend_factor,
GDesktopBackgroundStyle style)
{
@@ -890,8 +904,8 @@ meta_background_set_blend (MetaBackground *self,
priv = self->priv;
set_filename (self, &priv->filename1, &priv->background_image1, filename1);
set_filename (self, &priv->filename2, &priv->background_image2, filename2);
set_file (self, &priv->file1, &priv->background_image1, file1);
set_file (self, &priv->file2, &priv->background_image2, file2);
priv->blend_factor = blend_factor;
priv->style = style;

View File

@@ -0,0 +1,64 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-dnd-actor-private.h: Actor for painting the DnD surface
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_DND_ACTOR_PRIVATE_H
#define META_DND_ACTOR_PRIVATE_H
#include "meta-feedback-actor-private.h"
/**
* MetaDnDActor:
*
* This class handles the rendering of the DnD surface
*/
#define META_TYPE_DND_ACTOR (meta_dnd_actor_get_type ())
#define META_DND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DND_ACTOR, MetaDnDActor))
#define META_DND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DND_ACTOR, MetaDnDActorClass))
#define META_IS_DND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_DND_ACTOR))
#define META_IS_DND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DND_ACTOR))
#define META_DND_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DND_ACTOR, MetaDnDActorClass))
typedef struct _MetaDnDActor MetaDnDActor;
typedef struct _MetaDnDActorClass MetaDnDActorClass;
struct _MetaDnDActorClass
{
/*< private >*/
MetaFeedbackActorClass parent_class;
};
struct _MetaDnDActor
{
MetaFeedbackActor parent;
};
GType meta_dnd_actor_get_type (void);
ClutterActor *meta_dnd_actor_new (ClutterActor *drag_origin,
int start_x,
int start_y);
void meta_dnd_actor_drag_finish (MetaDnDActor *self,
gboolean success);
#endif /* META_DND_ACTOR_PRIVATE_H */

View File

@@ -0,0 +1,231 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:meta-dnd-actor
* @title: MetaDnDActor
* @short_description: Actor for painting the drag and drop surface
*
*/
#include <config.h>
#include <clutter/clutter.h>
#include "meta-dnd-actor-private.h"
#define DRAG_FAILED_DURATION 500
enum {
PROP_DRAG_ORIGIN = 1,
PROP_DRAG_START_X,
PROP_DRAG_START_Y
};
typedef struct _MetaDnDActorPrivate MetaDnDActorPrivate;
struct _MetaDnDActorPrivate
{
ClutterActor *drag_origin;
int drag_start_x;
int drag_start_y;
};
G_DEFINE_TYPE_WITH_PRIVATE (MetaDnDActor, meta_dnd_actor, META_TYPE_FEEDBACK_ACTOR)
static void
meta_dnd_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaDnDActor *self = META_DND_ACTOR (object);
MetaDnDActorPrivate *priv = meta_dnd_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_DRAG_ORIGIN:
priv->drag_origin = g_value_get_object (value);
break;
case PROP_DRAG_START_X:
priv->drag_start_x = g_value_get_int (value);
break;
case PROP_DRAG_START_Y:
priv->drag_start_y = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dnd_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaDnDActor *self = META_DND_ACTOR (object);
MetaDnDActorPrivate *priv = meta_dnd_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_DRAG_ORIGIN:
g_value_set_object (value, priv->drag_origin);
break;
case PROP_DRAG_START_X:
g_value_set_int (value, priv->drag_start_x);
break;
case PROP_DRAG_START_Y:
g_value_set_int (value, priv->drag_start_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dnd_actor_class_init (MetaDnDActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->set_property = meta_dnd_actor_set_property;
object_class->get_property = meta_dnd_actor_get_property;
pspec = g_param_spec_object ("drag-origin",
"Drag origin",
"The origin of the DnD operation",
CLUTTER_TYPE_ACTOR,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_ORIGIN,
pspec);
pspec = g_param_spec_int ("drag-start-x",
"Drag start X",
"The X axis of the drag start point",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_START_X,
pspec);
pspec = g_param_spec_int ("drag-start-y",
"Drag start Y",
"The Y axis of the drag start point",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_START_Y,
pspec);
}
static void
meta_dnd_actor_init (MetaDnDActor *self)
{
}
/**
* meta_dnd_actor_new:
*
* Creates a new actor to draw the current drag and drop surface.
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_dnd_actor_new (ClutterActor *drag_origin,
int drag_start_x,
int drag_start_y)
{
MetaDnDActor *self;
self = g_object_new (META_TYPE_DND_ACTOR,
"drag-origin", drag_origin,
"drag-start-x", drag_start_x,
"drag-start-y", drag_start_y,
NULL);
return CLUTTER_ACTOR (self);
}
static void
drag_failed_complete (ClutterTimeline *timeline,
gboolean is_finished,
gpointer user_data)
{
ClutterActor *self = user_data;
clutter_actor_remove_all_children (self);
clutter_actor_destroy (self);
}
void
meta_dnd_actor_drag_finish (MetaDnDActor *self,
gboolean success)
{
MetaDnDActorPrivate *priv;
ClutterActor *actor;
g_return_if_fail (META_IS_DND_ACTOR (self));
actor = CLUTTER_ACTOR (self);
priv = meta_dnd_actor_get_instance_private (self);
if (success)
{
clutter_actor_remove_all_children (CLUTTER_ACTOR (self));
clutter_actor_destroy (CLUTTER_ACTOR (self));
}
else
{
ClutterTransition *transition;
clutter_actor_save_easing_state (actor);
clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
clutter_actor_set_easing_duration (actor, DRAG_FAILED_DURATION);
clutter_actor_set_opacity (actor, 0);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->drag_origin))
{
int anchor_x, anchor_y;
ClutterPoint dest;
clutter_actor_get_transformed_position (priv->drag_origin,
&dest.x, &dest.y);
meta_feedback_actor_get_anchor (META_FEEDBACK_ACTOR (self),
&anchor_x, &anchor_y);
dest.x += priv->drag_start_x - anchor_x;
dest.y += priv->drag_start_y - anchor_y;
clutter_actor_set_position (actor, dest.x, dest.y);
}
transition = clutter_actor_get_transition (actor, "opacity");
g_signal_connect (transition, "stopped",
G_CALLBACK (drag_failed_complete), self);
clutter_actor_restore_easing_state (actor);
}
}

View File

@@ -0,0 +1,74 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-feedback-actor-private.h: Actor for painting user interaction feedback
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_FEEDBACK_ACTOR_PRIVATE_H
#define META_FEEDBACK_ACTOR_PRIVATE_H
#include <clutter/clutter.h>
/**
* MetaFeedbackActor:
*
* This class handles the rendering of user interaction feedback
*/
#define META_TYPE_FEEDBACK_ACTOR (meta_feedback_actor_get_type ())
#define META_FEEDBACK_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActor))
#define META_FEEDBACK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActorClass))
#define META_IS_FEEDBACK_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_FEEDBACK_ACTOR))
#define META_IS_FEEDBACK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_FEEDBACK_ACTOR))
#define META_FEEDBACK_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActorClass))
typedef struct _MetaFeedbackActor MetaFeedbackActor;
typedef struct _MetaFeedbackActorClass MetaFeedbackActorClass;
struct _MetaFeedbackActorClass
{
/*< private >*/
ClutterActorClass parent_class;
};
struct _MetaFeedbackActor
{
ClutterActor parent;
};
GType meta_feedback_actor_get_type (void);
ClutterActor *meta_feedback_actor_new (int anchor_x,
int anchor_y);
void meta_feedback_actor_set_anchor (MetaFeedbackActor *actor,
int anchor_x,
int anchor_y);
void meta_feedback_actor_get_anchor (MetaFeedbackActor *actor,
int *anchor_x,
int *anchor_y);
void meta_feedback_actor_set_position (MetaFeedbackActor *self,
int x,
int y);
void meta_feedback_actor_update (MetaFeedbackActor *self,
const ClutterEvent *event);
#endif /* META_FEEDBACK_ACTOR_PRIVATE_H */

View File

@@ -0,0 +1,249 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:meta-feedback-actor
* @title: MetaFeedbackActor
* @short_description: Actor for painting user interaction feedback
*/
#include <config.h>
#include "display-private.h"
#include "compositor-private.h"
#include "meta-feedback-actor-private.h"
enum {
PROP_ANCHOR_X = 1,
PROP_ANCHOR_Y
};
typedef struct _MetaFeedbackActorPrivate MetaFeedbackActorPrivate;
struct _MetaFeedbackActorPrivate
{
int anchor_x;
int anchor_y;
int pos_x;
int pos_y;
};
G_DEFINE_TYPE_WITH_PRIVATE (MetaFeedbackActor, meta_feedback_actor, CLUTTER_TYPE_ACTOR)
static void
meta_feedback_actor_constructed (GObject *object)
{
MetaDisplay *display;
display = meta_get_display ();
clutter_actor_add_child (display->compositor->feedback_group,
CLUTTER_ACTOR (object));
}
static void
meta_feedback_actor_update_position (MetaFeedbackActor *self)
{
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
clutter_actor_set_position (CLUTTER_ACTOR (self),
priv->pos_x - priv->anchor_x,
priv->pos_y - priv->anchor_y);
}
static void
meta_feedback_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object);
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_ANCHOR_X:
priv->anchor_x = g_value_get_int (value);
meta_feedback_actor_update_position (self);
break;
case PROP_ANCHOR_Y:
priv->anchor_y = g_value_get_int (value);
meta_feedback_actor_update_position (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_feedback_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object);
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_ANCHOR_X:
g_value_set_int (value, priv->anchor_x);
break;
case PROP_ANCHOR_Y:
g_value_set_int (value, priv->anchor_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_feedback_actor_class_init (MetaFeedbackActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->constructed = meta_feedback_actor_constructed;
object_class->set_property = meta_feedback_actor_set_property;
object_class->get_property = meta_feedback_actor_get_property;
pspec = g_param_spec_int ("anchor-x",
"Anchor X",
"The X axis of the anchor point",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_ANCHOR_X,
pspec);
pspec = g_param_spec_int ("anchor-y",
"Anchor Y",
"The Y axis of the anchor point",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_ANCHOR_Y,
pspec);
}
static void
meta_feedback_actor_init (MetaFeedbackActor *self)
{
clutter_actor_set_reactive (CLUTTER_ACTOR (self), FALSE);
}
/**
* meta_feedback_actor_new:
*
* Creates a new actor to draw the current drag and drop surface.
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_feedback_actor_new (int anchor_x,
int anchor_y)
{
MetaFeedbackActor *self;
self = g_object_new (META_TYPE_FEEDBACK_ACTOR,
"anchor-x", anchor_x,
"anchor-y", anchor_y,
NULL);
return CLUTTER_ACTOR (self);
}
void
meta_feedback_actor_set_anchor (MetaFeedbackActor *self,
int anchor_x,
int anchor_y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
if (priv->anchor_x == anchor_x && priv->anchor_y == anchor_y)
return;
if (priv->anchor_x != anchor_y)
{
priv->anchor_x = anchor_x;
g_object_notify (G_OBJECT (self), "anchor-x");
}
if (priv->anchor_y != anchor_y)
{
priv->anchor_y = anchor_y;
g_object_notify (G_OBJECT (self), "anchor-y");
}
meta_feedback_actor_update_position (self);
}
void
meta_feedback_actor_get_anchor (MetaFeedbackActor *self,
int *anchor_x,
int *anchor_y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
if (anchor_x)
*anchor_x = priv->anchor_x;
if (anchor_y)
*anchor_y = priv->anchor_y;
}
void
meta_feedback_actor_set_position (MetaFeedbackActor *self,
int x,
int y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
priv->pos_x = x;
priv->pos_y = y;
meta_feedback_actor_update_position (self);
}
void
meta_feedback_actor_update (MetaFeedbackActor *self,
const ClutterEvent *event)
{
ClutterPoint point;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
g_return_if_fail (event != NULL);
clutter_event_get_position (event, &point);
meta_feedback_actor_set_position (self, point.x, point.y);
}

View File

@@ -34,4 +34,9 @@ void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
void meta_shaped_texture_set_viewport (MetaShapedTexture *stex,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height);
#endif

View File

@@ -85,7 +85,12 @@ struct _MetaShapedTexturePrivate
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
/* Viewport stuff */
cairo_rectangle_int_t viewport_src_rect;
guint viewport_dest_width, viewport_dest_height;
guint tex_width, tex_height;
guint dest_width, dest_height;
guint create_mipmaps : 1;
};
@@ -136,7 +141,7 @@ set_unobscured_region (MetaShapedTexture *self,
g_clear_pointer (&priv->unobscured_region, (GDestroyNotify) cairo_region_destroy);
if (unobscured_region)
{
cairo_rectangle_int_t bounds = { 0, 0, priv->tex_width, priv->tex_height };
cairo_rectangle_int_t bounds = { 0, 0, priv->dest_width, priv->dest_height };
priv->unobscured_region = cairo_region_copy (unobscured_region);
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
}
@@ -212,24 +217,45 @@ get_unblended_pipeline (CoglContext *ctx)
return cogl_pipeline_copy (template);
}
static void
scale_coords_by_src (cairo_rectangle_int_t *coords,
int dest_width, int dest_height,
cairo_rectangle_int_t *src_rect)
{
if (src_rect->width == 0 && src_rect->height == 0)
return;
coords->x = ((coords->x / dest_width) * src_rect->width) + src_rect->x;
coords->y = ((coords->y / dest_height) * src_rect->height) + src_rect->y;
coords->width = ((coords->width / dest_width) * src_rect->width);
coords->height = ((coords->height / dest_height) * src_rect->height);
}
static void
paint_clipped_rectangle (CoglFramebuffer *fb,
CoglPipeline *pipeline,
cairo_rectangle_int_t *rect,
ClutterActorBox *alloc)
ClutterActorBox *alloc,
cairo_rectangle_int_t *src_rect)
{
cairo_rectangle_int_t pixel_coords;
float coords[8];
float x1, y1, x2, y2;
float dest_width = alloc->x2 - alloc->x1;
float dest_height = alloc->y2 - alloc->y1;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
coords[0] = rect->x / (alloc->x2 - alloc->x1);
coords[1] = rect->y / (alloc->y2 - alloc->y1);
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
pixel_coords = *rect;
scale_coords_by_src (&pixel_coords, dest_width, dest_height, src_rect);
coords[0] = pixel_coords.x / dest_width;
coords[1] = pixel_coords.y / dest_height;
coords[2] = (pixel_coords.x + pixel_coords.width) / dest_width;
coords[3] = (pixel_coords.y + pixel_coords.height) / dest_height;
coords[4] = coords[0];
coords[5] = coords[1];
@@ -241,6 +267,32 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
&coords[0], 8);
}
static void
update_size (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
guint dest_width, dest_height;
if (priv->viewport_dest_width > 0)
dest_width = priv->viewport_dest_width;
else
dest_width = priv->tex_width;
if (priv->viewport_dest_height > 0)
dest_height = priv->viewport_dest_height;
else
dest_height = priv->tex_height;
if (priv->dest_width != dest_width ||
priv->dest_height != dest_height)
{
priv->dest_width = dest_width;
priv->dest_height = dest_height;
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
}
}
static void
set_cogl_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex)
@@ -274,8 +326,7 @@ set_cogl_texture (MetaShapedTexture *stex,
{
priv->tex_width = width;
priv->tex_height = height;
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
update_size (stex);
}
/* NB: We don't queue a redraw of the actor here because we don't
@@ -292,7 +343,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
guint tex_width, tex_height;
guint dest_width, dest_height;
guchar opacity;
CoglContext *ctx;
CoglFramebuffer *fb;
@@ -329,13 +380,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (paint_tex == NULL)
return;
tex_width = priv->tex_width;
tex_height = priv->tex_height;
dest_width = priv->dest_width;
dest_height = priv->dest_height;
if (tex_width == 0 || tex_height == 0) /* no contents yet */
if (dest_width == 0 || dest_height == 0) /* no contents yet */
return;
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
cairo_rectangle_int_t tex_rect = { 0, 0, dest_width, dest_height };
/* Use nearest-pixel interpolation if the texture is unscaled. This
* improves performance, especially with software rendering.
@@ -418,7 +469,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc, &priv->viewport_src_rect);
}
cogl_object_unref (opaque_pipeline);
@@ -473,16 +524,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
continue;
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc);
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc, &priv->viewport_src_rect);
}
}
else
{
/* 3) blended_region is NULL. Do a full paint. */
cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
paint_clipped_rectangle (fb, blended_pipeline, &tex_rect, &alloc, &priv->viewport_src_rect);
}
cogl_object_unref (blended_pipeline);
@@ -505,10 +553,10 @@ meta_shaped_texture_get_preferred_width (ClutterActor *self,
priv = META_SHAPED_TEXTURE (self)->priv;
if (min_width_p)
*min_width_p = priv->tex_width;
*min_width_p = priv->dest_width;
if (natural_width_p)
*natural_width_p = priv->tex_width;
*natural_width_p = priv->dest_width;
}
static void
@@ -524,10 +572,10 @@ meta_shaped_texture_get_preferred_height (ClutterActor *self,
priv = META_SHAPED_TEXTURE (self)->priv;
if (min_height_p)
*min_height_p = priv->tex_height;
*min_height_p = priv->dest_height;
if (natural_height_p)
*natural_height_p = priv->tex_height;
*natural_height_p = priv->dest_height;
}
static cairo_region_t *
@@ -762,6 +810,22 @@ meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
priv->opaque_region = NULL;
}
void
meta_shaped_texture_set_viewport (MetaShapedTexture *stex,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height)
{
MetaShapedTexturePrivate *priv = stex->priv;
priv->viewport_src_rect = *src_rect;
priv->viewport_dest_width = dest_width;
priv->viewport_dest_height = dest_height;
update_size (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
/**
* meta_shaped_texture_get_image:
* @stex: A #MetaShapedTexture

View File

@@ -193,8 +193,8 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
MetaRectangle window_rect;
meta_window_get_frame_rect (priv->window, &window_rect);
if (window_rect.x == x &&
window_rect.y == y &&
if (x == 0 &&
y == 0 &&
window_rect.width == width &&
window_rect.height == height)
priv->full_damage_frames_count++;
@@ -383,6 +383,7 @@ window_decorated_notify (MetaWindow *window,
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
detach_pixmap (self);
free_damage (self);
create_damage (self);
}

View File

@@ -65,6 +65,8 @@ meta_surface_actor_pick (ClutterActor *actor,
CoglContext *ctx;
CoglFramebuffer *fb;
CoglColor cogl_color;
ClutterActorIter iter;
ClutterActor *child;
n_rects = cairo_region_num_rectangles (priv->input_region);
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
@@ -91,6 +93,11 @@ meta_surface_actor_pick (ClutterActor *actor,
cogl_pipeline_set_color (pipeline, &cogl_color);
cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
cogl_object_unref (pipeline);
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
clutter_actor_paint (child);
}
}
@@ -228,6 +235,16 @@ meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
meta_shaped_texture_set_opaque_region (priv->texture, region);
}
void
meta_surface_actor_set_viewport (MetaSurfaceActor *self,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height)
{
MetaSurfaceActorPrivate *priv = self->priv;
meta_shaped_texture_set_viewport (priv->texture, src_rect, dest_width, dest_height);
}
static gboolean
is_frozen (MetaSurfaceActor *self)
{

View File

@@ -61,6 +61,11 @@ void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
cairo_region_t *region);
void meta_surface_actor_set_viewport (MetaSurfaceActor *self,
cairo_rectangle_int_t *src_rect,
int dest_width,
int dest_height);
void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);

View File

@@ -295,7 +295,7 @@ on_monitors_changed (MetaScreen *screen,
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
int i, n;
GRand *rand = g_rand_new_with_seed (12345);
GRand *rand = g_rand_new_with_seed (123456);
clutter_actor_destroy_all_children (self->priv->background_group);

View File

@@ -612,9 +612,14 @@ update_onscreen_requirements (MetaWindow *window,
*/
if (window->frame && window->decorated)
{
MetaRectangle titlebar_rect;
MetaRectangle titlebar_rect, frame_rect;
meta_window_get_titlebar_rect (window, &titlebar_rect);
meta_window_get_frame_rect (window, &frame_rect);
/* translate into screen coordinates */
titlebar_rect.x = frame_rect.x;
titlebar_rect.y = frame_rect.y;
old = window->require_titlebar_visible;
window->require_titlebar_visible =

View File

@@ -57,6 +57,7 @@ typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef enum {
META_LIST_DEFAULT = 0, /* normal windows */
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
META_LIST_SORTED = 1 << 1, /* sort list by mru */
} MetaListWindowsFlags;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */

View File

@@ -150,6 +150,9 @@ static void update_cursor_theme (void);
static void prefs_changed_callback (MetaPreference pref,
void *data);
static int mru_cmp (gconstpointer a,
gconstpointer b);
static void
meta_display_get_property(GObject *object,
guint prop_id,
@@ -1004,7 +1007,7 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window))
if (!META_IS_WINDOW (window) || window->unmanaging)
continue;
if (!window->override_redirect ||
@@ -1017,7 +1020,7 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window))
if (!META_IS_WINDOW (window) || window->unmanaging)
continue;
if (!window->override_redirect ||
@@ -1061,6 +1064,9 @@ meta_display_list_windows (MetaDisplay *display,
tmp = next;
}
if (flags & META_LIST_SORTED)
winlist = g_slist_sort (winlist, mru_cmp);
return winlist;
}
@@ -1959,7 +1965,7 @@ meta_display_end_grab_op (MetaDisplay *display,
* beginning of the grab_op.
*/
if (!meta_prefs_get_raise_on_click () &&
display->grab_threshold_movement_reached)
!display->grab_threshold_movement_reached)
meta_window_raise (display->grab_window);
meta_window_grab_op_ended (grab_window, grab_op);
@@ -2434,13 +2440,22 @@ meta_display_get_tab_list (MetaDisplay *display,
mru_list = workspace ? workspace->mru_list : global_mru_list;
/* Windows sellout mode - MRU order.
/* Windows sellout mode - MRU order. Collect unminimized windows
* then minimized so minimized windows aren't in the way so much.
*/
for (tmp = mru_list; tmp; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
if (IN_TAB_CHAIN (window, type))
if (!window->minimized && IN_TAB_CHAIN (window, type))
tab_list = g_list_prepend (tab_list, window);
}
for (tmp = mru_list; tmp; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
if (window->minimized && IN_TAB_CHAIN (window, type))
tab_list = g_list_prepend (tab_list, window);
}

View File

@@ -28,6 +28,7 @@
#include "display-private.h"
#include "window-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/meta-cursor-tracker-private.h"
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
@@ -35,7 +36,6 @@
#endif
#ifdef HAVE_WAYLAND
#include "backends/meta-cursor-tracker-private.h"
#include "wayland/meta-wayland-private.h"
#endif
#include "meta-surface-actor.h"
@@ -151,23 +151,6 @@ sequence_is_pointer_emulated (MetaDisplay *display,
return FALSE;
}
static void
meta_display_update_pointer_emulating_sequence (MetaDisplay *display,
const ClutterEvent *event)
{
ClutterEventSequence *sequence;
sequence = clutter_event_get_event_sequence (event);
if (event->type == CLUTTER_TOUCH_BEGIN &&
!display->pointer_emulating_sequence &&
sequence_is_pointer_emulated (display, event))
display->pointer_emulating_sequence = sequence;
else if (event->type == CLUTTER_TOUCH_END &&
display->pointer_emulating_sequence == sequence)
display->pointer_emulating_sequence = NULL;
}
static gboolean
meta_display_handle_event (MetaDisplay *display,
const ClutterEvent *event)
@@ -176,8 +159,15 @@ meta_display_handle_event (MetaDisplay *display,
gboolean bypass_clutter = FALSE;
G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
MetaGestureTracker *tracker;
ClutterEventSequence *sequence;
meta_display_update_pointer_emulating_sequence (display, event);
sequence = clutter_event_get_event_sequence (event);
/* Set the pointer emulating sequence on touch begin, if eligible */
if (event->type == CLUTTER_TOUCH_BEGIN &&
!display->pointer_emulating_sequence &&
sequence_is_pointer_emulated (display, event))
display->pointer_emulating_sequence = sequence;
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *compositor = NULL;
@@ -314,6 +304,11 @@ meta_display_handle_event (MetaDisplay *display,
}
#endif
/* Unset the pointer emulating sequence after its end event is processed */
if (event->type == CLUTTER_TOUCH_END &&
display->pointer_emulating_sequence == sequence)
display->pointer_emulating_sequence = NULL;
display->current_time = CurrentTime;
return bypass_clutter;
}

View File

@@ -101,6 +101,8 @@ typedef struct
MetaKeyCombo *iso_next_group_combos;
int n_iso_next_group_combos;
xkb_level_index_t keymap_num_levels;
/* Alt+click button grabs */
ClutterModifierType window_grab_modifiers;
} MetaKeyBindingManager;

View File

@@ -40,7 +40,11 @@
#include <meta/prefs.h>
#include "meta-accel-parse.h"
#ifdef __linux__
#include <linux/input.h>
#elif !defined KEY_GRAVE
#define KEY_GRAVE 0x29 /* assume the use of xf86-input-keyboard */
#endif
#include "backends/x11/meta-backend-x11.h"
#include "x11/window-x11.h"
@@ -236,29 +240,19 @@ reload_modmap (MetaKeyBindingManager *keys)
static gboolean
is_keycode_for_keysym (struct xkb_keymap *keymap,
xkb_layout_index_t layout,
xkb_level_index_t level,
xkb_keycode_t keycode,
xkb_keysym_t keysym)
{
xkb_layout_index_t num_layouts, i;
const xkb_keysym_t *syms;
int num_syms, k;
num_layouts = xkb_keymap_num_layouts_for_key (keymap, keycode);
for (i = 0; i < num_layouts; i++)
num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, layout, level, &syms);
for (k = 0; k < num_syms; k++)
{
xkb_level_index_t num_levels, j;
num_levels = xkb_keymap_num_levels_for_key (keymap, keycode, i);
for (j = 0; j < num_levels; j++)
{
const xkb_keysym_t *syms;
int num_syms, k;
num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, i, j, &syms);
for (k = 0; k < num_syms; k++)
{
if (syms[k] == keysym)
return TRUE;
}
}
if (syms[k] == keysym)
return TRUE;
}
return FALSE;
@@ -268,6 +262,8 @@ typedef struct
{
GArray *keycodes;
xkb_keysym_t keysym;
xkb_layout_index_t layout;
xkb_level_index_t level;
} FindKeysymData;
static void
@@ -278,8 +274,10 @@ get_keycodes_for_keysym_iter (struct xkb_keymap *keymap,
FindKeysymData *search_data = data;
GArray *keycodes = search_data->keycodes;
xkb_keysym_t keysym = search_data->keysym;
xkb_layout_index_t layout = search_data->layout;
xkb_level_index_t level = search_data->level;
if (is_keycode_for_keysym (keymap, keycode, keysym))
if (is_keycode_for_keysym (keymap, layout, level, keycode, keysym))
g_array_append_val (keycodes, keycode);
}
@@ -307,8 +305,15 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
{
MetaBackend *backend = meta_get_backend ();
struct xkb_keymap *keymap = meta_backend_get_keymap (backend);
FindKeysymData search_data = { retval, keysym };
xkb_keymap_key_for_each (keymap, get_keycodes_for_keysym_iter, &search_data);
xkb_layout_index_t i;
xkb_level_index_t j;
for (i = 0; i < xkb_keymap_num_layouts (keymap); i++)
for (j = 0; j < keys->keymap_num_levels; j++)
{
FindKeysymData search_data = { retval, keysym, i, j };
xkb_keymap_key_for_each (keymap, get_keycodes_for_keysym_iter, &search_data);
}
}
out:
@@ -319,7 +324,7 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
static guint
get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
guint keysym)
guint keysym)
{
int *keycodes;
int n_keycodes;
@@ -336,6 +341,32 @@ get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
return keycode;
}
static void
determine_keymap_num_levels_iter (struct xkb_keymap *keymap,
xkb_keycode_t keycode,
void *data)
{
xkb_level_index_t *num_levels = data;
xkb_layout_index_t i;
for (i = 0; i < xkb_keymap_num_layouts_for_key (keymap, keycode); i++)
{
xkb_level_index_t level = xkb_keymap_num_levels_for_key (keymap, keycode, i);
if (level > *num_levels)
*num_levels = level;
}
}
static void
determine_keymap_num_levels (MetaKeyBindingManager *keys)
{
MetaBackend *backend = meta_get_backend ();
struct xkb_keymap *keymap = meta_backend_get_keymap (backend);
keys->keymap_num_levels = 0;
xkb_keymap_key_for_each (keymap, determine_keymap_num_levels_iter, &keys->keymap_num_levels);
}
static void
reload_iso_next_group_combos (MetaKeyBindingManager *keys)
{
@@ -484,6 +515,8 @@ reload_keycodes (MetaKeyBindingManager *keys)
meta_topic (META_DEBUG_KEYBINDINGS,
"Reloading keycodes for binding tables\n");
determine_keymap_num_levels (keys);
if (keys->overlay_key_combo.keysym != 0)
{
keys->overlay_key_combo.keycode =
@@ -1627,13 +1660,14 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
}
void
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
meta_display_freeze_keyboard (MetaDisplay *display, guint32 timestamp)
{
MetaBackend *backend = meta_get_backend ();
if (!META_IS_BACKEND_X11 (backend))
return;
Window window = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
grab_keyboard (window, timestamp, XIGrabModeSync);
}
@@ -2922,10 +2956,6 @@ do_choose_window (MetaDisplay *display,
meta_topic (META_DEBUG_KEYBINDINGS,
"Tab list = %u\n", type);
/* reverse direction if shift is down */
if (event->modifier_state & CLUTTER_SHIFT_MASK)
backward = !backward;
window = meta_display_get_tab_next (display,
type,
screen->active_workspace,

View File

@@ -1187,7 +1187,6 @@ settings_changed (GSettings *settings,
{
/* Unknown preference type. This quite likely simply isn't
* a preference we track changes to. */
return;
}
g_variant_unref (value);

View File

@@ -3021,38 +3021,32 @@ static gboolean
check_fullscreen_func (gpointer data)
{
MetaScreen *screen = data;
GSList *windows;
GSList *tmp;
MetaWindow *window;
GSList *fullscreen_monitors = NULL;
GSList *obscured_monitors = NULL;
gboolean in_fullscreen_changed = FALSE;
int i;
screen->check_fullscreen_later = 0;
windows = meta_display_list_windows (screen->display,
META_LIST_INCLUDE_OVERRIDE_REDIRECT);
for (tmp = windows; tmp != NULL; tmp = tmp->next)
/* We consider a monitor in fullscreen if it contains a fullscreen window;
* however we make an exception for maximized windows above the fullscreen
* one, as in that case window+chrome fully obscure the fullscreen window.
*/
for (window = meta_stack_get_top (screen->stack);
window;
window = meta_stack_get_below (screen->stack, window, FALSE))
{
MetaWindow *window = tmp->data;
gboolean covers_monitors = FALSE;
if (window->screen != screen || window->hidden)
continue;
if (window->fullscreen)
/* The checks for determining a fullscreen window's layer are quite
* elaborate, and we do a poor job at keeping it dynamically up-to-date.
* (It depends, for example, on whether the focus window is on the
* same monitor as the fullscreen window.) But because we minimize
* fullscreen windows not in LAYER_FULLSCREEN (see below), if the
* layer is stale here, it's really bad, so just force recomputation for
* here. This is expensive, but hopefully this function won't be
* called too often.
*/
meta_window_update_layer (window);
if (window->override_redirect)
{
covers_monitors = TRUE;
}
else if (window->override_redirect)
{
/* We want to handle the case where an application is creating an
* override-redirect window the size of the screen (monitor) and treat
@@ -3062,10 +3056,14 @@ check_fullscreen_func (gpointer data)
if (meta_window_is_monitor_sized (window))
covers_monitors = TRUE;
}
else
else if (window->maximized_horizontally &&
window->maximized_vertically)
{
if (window->layer == META_LAYER_FULLSCREEN)
covers_monitors = TRUE;
int monitor_index = meta_window_get_monitor (window);
/* + 1 to avoid NULL */
gpointer monitor_p = GINT_TO_POINTER(monitor_index + 1);
if (!g_slist_find (obscured_monitors, monitor_p))
obscured_monitors = g_slist_prepend (obscured_monitors, monitor_p);
}
if (covers_monitors)
@@ -3079,30 +3077,16 @@ check_fullscreen_func (gpointer data)
{
/* + 1 to avoid NULL */
gpointer monitor_p = GINT_TO_POINTER(monitors[j] + 1);
if (!g_slist_find (fullscreen_monitors, monitor_p))
if (!g_slist_find (fullscreen_monitors, monitor_p) &&
!g_slist_find (obscured_monitors, monitor_p))
fullscreen_monitors = g_slist_prepend (fullscreen_monitors, monitor_p);
}
g_free (monitors);
}
/* If we find a window that is fullscreen but not in the FULLSCREEN
* layer, it means that we've kicked it out of the layer because
* we've focused another window on the same monitor. In this case
* it would be confusing to keep the window fullscreen and visible,
* so minimize it. We can't do the same thing for override-redirect
* windows, so we just hope the application does the right thing.
*/
if (!covers_monitors && window->fullscreen)
{
meta_window_minimize (window);
meta_topic (META_DEBUG_WINDOW_OPS,
"Minimizing %s: was fullscreen but in a lower layer\n",
window->desc);
}
}
g_slist_free (windows);
g_slist_free (obscured_monitors);
for (i = 0; i < screen->n_monitor_infos; i++)
{

View File

@@ -1056,10 +1056,6 @@ stack_sync_to_xserver (MetaStack *stack)
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
x11_hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window);
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
meta_push_no_msg_prefix ();
@@ -1107,6 +1103,10 @@ stack_sync_to_xserver (MetaStack *stack)
meta_topic (META_DEBUG_STACK, "\n");
meta_pop_no_msg_prefix ();
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window);
/* Sync to server */
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",

View File

@@ -1062,8 +1062,8 @@ _meta_window_shared_new (MetaDisplay *display,
if (window->initial_workspace_set)
{
gboolean on_all_workspaces;
MetaWorkspace *workspace;
gboolean on_all_workspaces = window->on_all_workspaces;
MetaWorkspace *workspace = NULL;
if (window->initial_workspace == (int) 0xFFFFFFFF)
{
@@ -1077,15 +1077,13 @@ _meta_window_shared_new (MetaDisplay *display,
window->on_all_workspaces_requested = TRUE;
on_all_workspaces = TRUE;
workspace = NULL;
}
else
else if (!on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Window %s is initially on space %d\n",
window->desc, window->initial_workspace);
on_all_workspaces = FALSE;
workspace = meta_screen_get_workspace_by_index (window->screen,
window->initial_workspace);
}
@@ -1099,9 +1097,9 @@ _meta_window_shared_new (MetaDisplay *display,
* but appear on other workspaces. override-redirect windows are part
* of no workspace.
*/
if (!window->override_redirect)
if (!window->override_redirect && window->workspace == NULL)
{
if (window->workspace == NULL && window->transient_for != NULL)
if (window->transient_for != NULL)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on same workspace as parent %s\n",
@@ -1112,7 +1110,15 @@ _meta_window_shared_new (MetaDisplay *display,
window->transient_for->workspace);
}
if (window->workspace == NULL)
if (window->on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on all workspaces\n",
window->desc);
set_workspace_state (window, TRUE, NULL);
}
else
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on active workspace\n",
@@ -2089,7 +2095,7 @@ windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
static gboolean
window_would_be_covered (const MetaWindow *newbie)
{
MetaWorkspace *workspace = newbie->workspace;
MetaWorkspace *workspace = meta_window_get_workspace ((MetaWindow *)newbie);
GList *tmp, *windows;
windows = meta_workspace_list_windows (workspace);
@@ -2616,6 +2622,9 @@ meta_window_maximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]);
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_VERTICALLY]);
@@ -3060,6 +3069,8 @@ meta_window_unmaximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (!window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen);
}
g_object_freeze_notify (G_OBJECT (window));
@@ -4291,7 +4302,7 @@ meta_window_focus (MetaWindow *window,
* - workspace->windows is a list of windows that is located on
* that workspace.
*
* - If the window is on_all_workspaces, then then
* - If the window is on_all_workspaces, then
* window->workspace == NULL, but workspace->windows contains
* the window.
*/
@@ -4313,7 +4324,8 @@ set_workspace_state (MetaWindow *window,
g_return_if_fail ((window->constructing && on_all_workspaces) || window->unmanaging);
if (on_all_workspaces == window->on_all_workspaces &&
workspace == window->workspace)
workspace == window->workspace &&
!window->constructing)
return;
if (window->workspace)
@@ -4645,6 +4657,32 @@ meta_window_appears_focused_changed (MetaWindow *window)
meta_frame_queue_draw (window->frame);
}
static gboolean
should_propagate_focus_appearance (MetaWindow *window)
{
/* Parents of attached modal dialogs should appear focused. */
if (meta_window_is_attached_dialog (window))
return TRUE;
/* Parents of these sorts of override-redirect windows should
* appear focused. */
switch (window->type)
{
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_COMBO:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_DND:
case META_WINDOW_OVERRIDE_OTHER:
return TRUE;
default:
break;
}
return FALSE;
}
/**
* meta_window_propagate_focus_appearance:
* @window: the window to start propagating from
@@ -4668,7 +4706,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
child = window;
parent = meta_window_get_transient_for (child);
while (parent && (!focused || meta_window_is_attached_dialog (child)))
while (parent && (!focused || should_propagate_focus_appearance (child)))
{
gboolean child_focus_state_changed;
@@ -5385,7 +5423,7 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
gboolean
meta_window_titlebar_is_onscreen (MetaWindow *window)
{
MetaRectangle titlebar_rect;
MetaRectangle titlebar_rect, frame_rect;
GList *onscreen_region;
gboolean is_onscreen;
@@ -5400,6 +5438,11 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
/* Get the rectangle corresponding to the titlebar */
meta_window_get_titlebar_rect (window, &titlebar_rect);
/* Translate into screen coordinates */
meta_window_get_frame_rect (window, &frame_rect);
titlebar_rect.x = frame_rect.x;
titlebar_rect.y = frame_rect.y;
/* Run through the spanning rectangles for the screen and see if one of
* them overlaps with the titlebar sufficiently to consider it onscreen.
*/
@@ -5808,7 +5851,7 @@ update_resize (MetaWindow *window,
int new_w, new_h;
int gravity;
MetaRectangle old;
double remaining;
double remaining = 0;
MetaMaximizeFlags new_unmaximize;
window->display->grab_latest_motion_x = x;
@@ -6067,10 +6110,8 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
case CLUTTER_BUTTON_RELEASE:
if (event->button.button == 1 ||
event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ())
{
end_grab_op (window, event);
return FALSE;
}
end_grab_op (window, event);
return TRUE;
case CLUTTER_TOUCH_BEGIN:
@@ -6719,7 +6760,7 @@ meta_window_set_demands_attention (MetaWindow *window)
other_window = stack->data;
stack = stack->next;
if (meta_window_located_on_workspace (other_window, window->workspace))
if (meta_window_located_on_workspace (other_window, workspace))
{
meta_window_get_frame_rect (other_window, &other_rect);

View File

@@ -170,6 +170,7 @@ MetaWorkspace*
meta_workspace_new (MetaScreen *screen)
{
MetaWorkspace *workspace;
GSList *windows, *l;
workspace = g_object_new (META_TYPE_WORKSPACE, NULL);
@@ -197,6 +198,13 @@ meta_workspace_new (MetaScreen *screen)
workspace->showing_desktop = FALSE;
/* make sure sticky windows are in our mru_list */
windows = meta_display_list_windows (screen->display, META_LIST_SORTED);
for (l = windows; l; l = l->next)
if (meta_window_located_on_workspace (l->data, workspace))
meta_workspace_add_window (workspace, l->data);
g_slist_free (windows);
return workspace;
}
@@ -358,7 +366,7 @@ meta_workspace_relocate_windows (MetaWorkspace *workspace,
{
MetaWindow *window = l->data;
if (!window->override_redirect)
if (!window->on_all_workspaces)
meta_window_change_workspace (window, new_home);
}

View File

@@ -37,6 +37,7 @@ Window meta_get_overlay_window (MetaScreen *screen);
GList *meta_get_window_actors (MetaScreen *screen);
ClutterActor *meta_get_window_group_for_screen (MetaScreen *screen);
ClutterActor *meta_get_top_window_group_for_screen (MetaScreen *screen);
ClutterActor *meta_get_feedback_group_for_screen (MetaScreen *screen);
void meta_disable_unredirect_for_screen (MetaScreen *screen);
void meta_enable_unredirect_for_screen (MetaScreen *screen);

View File

@@ -173,7 +173,6 @@ void meta_display_unmanage_screen (MetaDisplay *display,
void meta_display_clear_mouse_mode (MetaDisplay *display);
void meta_display_freeze_keyboard (MetaDisplay *display,
Window window,
guint32 timestamp);
void meta_display_ungrab_keyboard (MetaDisplay *display,
guint32 timestamp);

View File

@@ -1,71 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient rendering */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
#ifndef META_GRADIENT_H
#define META_GRADIENT_H
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdk.h>
/**
* MetaGradientType:
* @META_GRADIENT_VERTICAL: Vertical gradient
* @META_GRADIENT_HORIZONTAL: Horizontal gradient
* @META_GRADIENT_DIAGONAL: Diagonal gradient
* @META_GRADIENT_LAST: Marks the end of the #MetaGradientType enumeration
*
*/
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
GdkPixbuf* meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2);
/* Generate an alpha gradient and multiply it with the existing alpha
* channel of the given pixbuf
*/
void meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type);
#endif

View File

@@ -69,8 +69,8 @@ MetaBackgroundImageCache *meta_background_image_cache_get_default (void);
GType meta_background_image_cache_get_type (void);
MetaBackgroundImage *meta_background_image_cache_load (MetaBackgroundImageCache *cache,
const char *filename);
GFile *file);
void meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
const char *filename);
GFile *file);
#endif /* __META_BACKGROUND_IMAGE_H__ */

View File

@@ -67,12 +67,12 @@ void meta_background_set_gradient (MetaBackground *self,
GDesktopBackgroundShading shading_direction,
ClutterColor *color,
ClutterColor *second_color);
void meta_background_set_filename (MetaBackground *self,
const char *filename,
void meta_background_set_file (MetaBackground *self,
GFile *file,
GDesktopBackgroundStyle style);
void meta_background_set_blend (MetaBackground *self,
const char *filename1,
const char *filename2,
GFile *file1,
GFile *file2,
double blend_factor,
GDesktopBackgroundStyle style);

View File

@@ -28,7 +28,7 @@
#define META_TYPE_WORKSPACE (meta_workspace_get_type ())
#define META_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WORKSPACE, MetaWorkspace))
#define META_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WORKSPACE, MetaWorkspaceClass))
#define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_WORKSPACE_TYPE))
#define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WORKSPACE))
#define META_IS_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WORKSPACE))
#define META_WORKSPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WORKSPACE, MetaWorkspaceClass))

View File

@@ -71,6 +71,11 @@ lower <client-id>/<window-id>
for Wayland clients. (It's also considered discouraged, but supported, for
non-override-redirect X11 clients.)
minimize <client-id>/<window-id>
unminimize <client-id>/<window-id>
Ask the client to minimize or unminimize the given window ID. This older
term for this operation is "iconify".
destroy <client-id>/<window-id>
Destroy the given window
@@ -80,7 +85,10 @@ wait
assert_stacking <client-id>/<window-id> <client-id>/<window-id> ...
Assert that the list of client windows known to Mutter is as given and in
the given order, bottom to top.
the given order, bottom to top. The character '|' can be present in the
list of windows to indicate the guard window that separates hidden and
visible windows. If '|' isn't present, the guard window is asserted to
be below all client windows.
This function also queries the X server stack and verifies that Mutter's
expectation of the X server stack matches reality.

View File

@@ -0,0 +1,18 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2
show 1/2
wait
assert_stacking 1/1 1/2
minimize 1/2
wait
assert_stacking 1/2 | 1/1
# unminimize doesn't work for GTK+ currently, because GTK+ expects
# to be able to de-iconify with MapWindow, but the window is already
# mapped.
activate 1/2
wait
assert_stacking 1/1 1/2

View File

@@ -12,7 +12,7 @@ assert_stacking 1/1 1/2
lower 1/2
wait
assert_stacking 1/2 1/1
assert_stacking 1/2 | 1/1
raise 1/2
wait

View File

@@ -263,6 +263,34 @@ process_line (const char *line)
XSyncSetCounter (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
counter, sync_value);
}
else if (strcmp (argv[0], "minimize") == 0)
{
if (argc != 2)
{
g_print ("usage: minimize <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_iconify (GTK_WINDOW (window));
}
else if (strcmp (argv[0], "unminimize") == 0)
{
if (argc != 2)
{
g_print ("usage: unminimize <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_deiconify (GTK_WINDOW (window));
}
else
{
g_print ("Unknown command %s", argv[0]);

View File

@@ -413,6 +413,7 @@ typedef struct {
AsyncWaiter *waiter;
guint log_handler_id;
GString *warning_messages;
GMainLoop *loop;
} TestCase;
static gboolean
@@ -483,10 +484,21 @@ test_case_new (void)
test->clients = g_hash_table_new (g_str_hash, g_str_equal);
test->waiter = async_waiter_new ();
test->loop = g_main_loop_new (NULL, FALSE);
return test;
}
static gboolean
test_case_before_redraw (gpointer data)
{
TestCase *test = data;
g_main_loop_quit (test->loop);
return FALSE;
}
static gboolean
test_case_wait (TestCase *test,
GError **error)
@@ -494,11 +506,30 @@ test_case_wait (TestCase *test,
GHashTableIter iter;
gpointer key, value;
/* First have each client set a XSync counter, and wait until
* we receive the resulting event - so we know we've received
* everything that the client have sent us.
*/
g_hash_table_iter_init (&iter, test->clients);
while (g_hash_table_iter_next (&iter, &key, &value))
if (!test_client_wait (value, error))
return FALSE;
/* Then wait until we've done any outstanding queued up work.
* Though we add this as BEFORE_REDRAW, the iteration that runs the
* BEFORE_REDRAW idles will proceed on and do the redraw, so we're
* waiting until after *all* frame processing.
*/
meta_later_add (META_LATER_BEFORE_REDRAW,
test_case_before_redraw,
test,
NULL);
g_main_loop_run (test->loop);
/* Then set an XSync counter ourselves and and wait until
* we receive the resulting event - this makes sure that we've
* received back any X events we generated.
*/
async_waiter_set_and_wait (test->waiter);
return TRUE;
}
@@ -579,6 +610,13 @@ test_case_assert_stacking (TestCase *test,
else
g_string_append_printf (stack_string, "(%s)", window->title);
}
else if (windows[i] == display->screen->guard_window)
{
if (stack_string->len > 0)
g_string_append_c (stack_string, ' ');
g_string_append_c (stack_string, '|');
}
}
for (i = 0; i < n_expected_windows; i++)
@@ -589,6 +627,16 @@ test_case_assert_stacking (TestCase *test,
g_string_append (expected_string, expected_windows[i]);
}
/* Don't require '| ' as a prefix if there are no hidden windows - we
* remove the prefix from the actual string instead of adding it to the
* expected string for clarity of the error message
*/
if (index (expected_string->str, '|') == NULL && stack_string->str[0] == '|')
{
g_string_erase (stack_string,
0, stack_string->str[1] == ' ' ? 2 : 1);
}
if (strcmp (expected_string->str, stack_string->str) != 0)
{
g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED,
@@ -725,6 +773,8 @@ test_case_do (TestCase *test,
strcmp (argv[0], "activate") == 0 ||
strcmp (argv[0], "raise") == 0 ||
strcmp (argv[0], "lower") == 0 ||
strcmp (argv[0], "minimize") == 0 ||
strcmp (argv[0], "unminimize") == 0 ||
strcmp (argv[0], "destroy") == 0)
{
if (argc != 2)
@@ -766,6 +816,7 @@ test_case_do (TestCase *test,
{
if (!test_case_assert_stacking (test, argv + 1, argc - 1, error))
return FALSE;
if (!test_case_check_xserver_stacking (test, error))
return FALSE;
}

View File

@@ -573,6 +573,7 @@ meta_frames_manage_window (MetaFrames *frames,
frame->title = NULL;
frame->shape_applied = FALSE;
frame->prelit_control = META_FRAME_CONTROL_NONE;
frame->button_state = META_BUTTON_STATE_NORMAL;
meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);

View File

@@ -1,902 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
/**
* SECTION:gradient
* @title: Gradients
* @short_description: Metacity gradient rendering
*/
#include <meta/gradient.h>
#include <meta/util.h>
#include <string.h>
/* This is all Alfredo's and Dan's usual very nice WindowMaker code,
* slightly GTK-ized
*/
static GdkPixbuf* meta_gradient_create_horizontal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_vertical (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_diagonal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_multi_horizontal (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_vertical (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_diagonal (int width,
int height,
const GdkRGBA *colors,
int count);
/* Used as the destroy notification function for gdk_pixbuf_new() */
static void
free_buffer (guchar *pixels, gpointer data)
{
g_free (pixels);
}
static GdkPixbuf*
blank_pixbuf (int width, int height)
{
guchar *buf;
int rowstride;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
/* Always align rows to 32-bit boundaries */
rowstride = 4 * ((4 * width + 4) / 4);
buf = g_try_malloc (height * rowstride);
if (!buf)
return NULL;
return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
TRUE, 8,
width, height, rowstride,
free_buffer, NULL);
}
/**
* meta_gradient_create_simple:
* @width: Width in pixels
* @height: Height in pixels
* @from: Starting color
* @to: Ending color
* @style: Gradient style
*
* Returns: (transfer full): A new linear gradient
*/
GdkPixbuf*
meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_horizontal (width, height,
from, to);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_vertical (width, height,
from, to);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_diagonal (width, height,
from, to);
case META_GRADIENT_LAST:
break;
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_multi:
* @width: Width in pixels
* @height: Height in pixels
* @colors: (array length=n_colors): Array of colors
* @n_colors: Number of colors
* @style: Gradient style
*
* Returns: (transfer full): A new multi-step linear gradient
*/
GdkPixbuf*
meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style)
{
if (n_colors > 2)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_multi_horizontal (width, height, colors, n_colors);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_multi_vertical (width, height, colors, n_colors);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_multi_diagonal (width, height, colors, n_colors);
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}
else if (n_colors > 1)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[1],
style);
}
else if (n_colors > 0)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[0],
style);
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_interwoven: (skip)
* @width: Width in pixels
* @height: Height in pixels
* @colors1: Array of colors
* @thickness1: Thickness
* @colors2: Array of colors
* @thickness2: Thickness
*
* Interwoven essentially means we have two vertical gradients,
* cut into horizontal strips of the given thickness, and then the strips
* are alternated. I'm not sure what it's good for, just copied since
* WindowMaker had it.
*/
GdkPixbuf*
meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2)
{
int i, j, k, l, ll;
long r1, g1, b1, a1, dr1, dg1, db1, da1;
long r2, g2, b2, a2, dr2, dg2, db2, da2;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r1 = (long)(colors1[0].red*0xffffff);
g1 = (long)(colors1[0].green*0xffffff);
b1 = (long)(colors1[0].blue*0xffffff);
a1 = (long)(colors1[0].alpha*0xffffff);
r2 = (long)(colors2[0].red*0xffffff);
g2 = (long)(colors2[0].green*0xffffff);
b2 = (long)(colors2[0].blue*0xffffff);
a2 = (long)(colors2[0].alpha*0xffffff);
dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height;
dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height;
db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height;
da1 = ((colors1[1].alpha-colors1[0].alpha)*0xffffff)/(int)height;
dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height;
dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height;
db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height;
da2 = ((colors2[1].alpha-colors2[0].alpha)*0xffffff)/(int)height;
for (i=0,k=0,l=0,ll=thickness1; i<height; i++)
{
ptr = pixels + i * rowstride;
if (k == 0)
{
ptr[0] = (unsigned char) (r1>>16);
ptr[1] = (unsigned char) (g1>>16);
ptr[2] = (unsigned char) (b1>>16);
ptr[3] = (unsigned char) (a1>>16);
}
else
{
ptr[0] = (unsigned char) (r2>>16);
ptr[1] = (unsigned char) (g2>>16);
ptr[2] = (unsigned char) (b2>>16);
ptr[3] = (unsigned char) (a2>>16);
}
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*4]), ptr, j*4);
memcpy (&(ptr[j*4]), ptr, (width - j)*4);
if (++l == ll)
{
if (k == 0)
{
k = 1;
ll = thickness2;
}
else
{
k = 0;
ll = thickness1;
}
l = 0;
}
r1+=dr1;
g1+=dg1;
b1+=db1;
a1+=da1;
r2+=dr2;
g2+=dg2;
b2+=db2;
a2+=da2;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_horizontal--
* Renders a horizontal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_horizontal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int r0, g0, b0, a0;
int rf, gf, bf, af;
int rowstride;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
ptr = pixels;
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
a0 = (guchar) (from->alpha * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
af = (guchar) (to->alpha * 0xff);
r = r0 << 16;
g = g0 << 16;
b = b0 << 16;
a = a0 << 16;
dr = ((rf-r0)<<16)/(int)width;
dg = ((gf-g0)<<16)/(int)width;
db = ((bf-b0)<<16)/(int)width;
da = ((af-a0)<<16)/(int)width;
/* render the first line */
for (i=0; i<width; i++)
{
*(ptr++) = (unsigned char)(r>>16);
*(ptr++) = (unsigned char)(g>>16);
*(ptr++) = (unsigned char)(b>>16);
*(ptr++) = (unsigned char)(a>>16);
r += dr;
g += dg;
b += db;
a += da;
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_vertical--
* Renders a vertical linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_vertical (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i, j;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
int r0, g0, b0, a0;
int rf, gf, bf, af;
int rowstride;
unsigned char *pixels;
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
a0 = (guchar) (from->alpha * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
af = (guchar) (to->alpha * 0xff);
r = r0<<16;
g = g0<<16;
b = b0<<16;
a = a0<<16;
dr = ((rf-r0)<<16)/(int)height;
dg = ((gf-g0)<<16)/(int)height;
db = ((bf-b0)<<16)/(int)height;
da = ((af-a0)<<16)/(int)height;
for (i=0; i<height; i++)
{
ptr = pixels + i * rowstride;
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
ptr[3] = (unsigned char)(a>>16);
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*4]), ptr, j*4);
memcpy (&(ptr[j*4]), ptr, (width - j)*4);
r+=dr;
g+=dg;
b+=db;
a+=da;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_diagonal--
* Renders a diagonal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_diagonal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
GdkPixbuf *pixbuf, *tmp;
int j;
float a, offset;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
if (width == 1)
return meta_gradient_create_vertical (width, height, from, to);
else if (height == 1)
return meta_gradient_create_horizontal (width, height, from, to);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 4;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0.0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[4*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_horizontal (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int width2;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > width)
count = width;
if (count > 1)
width2 = width/(count-1);
else
width2 = width;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
a = (long)(colors[0].alpha * 0xffffff);
/* render the first line */
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)width2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)width2;
da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)width2;
for (j=0; j<width2; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
*ptr++ = (unsigned char)(a>>16);
r += dr;
g += dg;
b += db;
a += da;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
a = (long)(colors[i].alpha * 0xffffff);
}
for (j=k; j<width; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
*ptr++ = (unsigned char)(a>>16);
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_vertical (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, a, dr, dg, db, da;
GdkPixbuf *pixbuf;
unsigned char *ptr, *tmp, *pixels;
int height2;
int x;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > height)
count = height;
if (count > 1)
height2 = height/(count-1);
else
height2 = height;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
a = (long)(colors[0].alpha * 0xffffff);
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)height2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)height2;
da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)height2;
for (j=0; j<height2; j++)
{
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
ptr[3] = (unsigned char)(a>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*4]), ptr, x*4);
memcpy (&(ptr[x*4]), ptr, (width - x)*4);
ptr += rowstride;
r += dr;
g += dg;
b += db;
a += da;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
a = (long)(colors[i].alpha * 0xffffff);
}
if (k<height)
{
tmp = ptr;
ptr[0] = (unsigned char) (r>>16);
ptr[1] = (unsigned char) (g>>16);
ptr[2] = (unsigned char) (b>>16);
ptr[3] = (unsigned char) (a>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*4]), ptr, x*4);
memcpy (&(ptr[x*4]), ptr, (width - x)*4);
ptr += rowstride;
for (j=k+1; j<height; j++)
{
memcpy (ptr, tmp, rowstride);
ptr += rowstride;
}
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_diagonal (int width, int height,
const GdkRGBA *colors,
int count)
{
GdkPixbuf *pixbuf, *tmp;
float a, offset;
int j;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
if (width == 1)
return meta_gradient_create_multi_vertical (width, height, colors, count);
else if (height == 1)
return meta_gradient_create_multi_horizontal (width, height, colors, count);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
if (count > width)
count = width;
if (count > height)
count = height;
if (count > 2)
tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count);
else
/* wrlib multiplies these colors by 256 before passing them in, but
* I think it's a bug in wrlib, so changed here. I could be wrong
* though, if we notice two-color multi diagonals not working.
*/
tmp = meta_gradient_create_horizontal (2*width-1, 1,
&colors[0], &colors[1]);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 3;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static void
simple_multiply_alpha (GdkPixbuf *pixbuf,
guchar alpha)
{
guchar *pixels;
int rowstride;
int height;
int row;
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (alpha == 255)
return;
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row = 0;
while (row < height)
{
guchar *p;
guchar *end;
p = pixels + row * rowstride;
end = p + rowstride;
while (p != end)
{
p += 3; /* skip RGB */
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) alpha) / (int) 255);
++p; /* skip A */
}
++row;
}
}
static void
meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf,
const unsigned char *alphas,
int n_alphas)
{
int i, j;
long a, da;
unsigned char *p;
unsigned char *pixels;
int width2;
int rowstride;
int width, height;
unsigned char *gradient;
unsigned char *gradient_p;
unsigned char *gradient_end;
g_return_if_fail (n_alphas > 0);
if (n_alphas == 1)
{
/* Optimize this */
simple_multiply_alpha (pixbuf, alphas[0]);
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gradient = g_new (unsigned char, width);
gradient_end = gradient + width;
if (n_alphas > width)
n_alphas = width;
if (n_alphas > 1)
width2 = width / (n_alphas - 1);
else
width2 = width;
a = alphas[0] << 8;
gradient_p = gradient;
/* render the gradient into an array */
for (i = 1; i < n_alphas; i++)
{
da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2;
for (j = 0; j < width2; j++)
{
*gradient_p++ = (a >> 8);
a += da;
}
a = alphas[i] << 8;
}
/* get leftover pixels */
while (gradient_p != gradient_end)
{
*gradient_p++ = a >> 8;
}
/* Now for each line of the pixbuf, fill in with the gradient */
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
p = pixels;
i = 0;
while (i < height)
{
unsigned char *row_end = p + rowstride;
gradient_p = gradient;
p += 3;
while (gradient_p != gradient_end)
{
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255);
p += 4;
++gradient_p;
}
p = row_end;
++i;
}
g_free (gradient);
}
void
meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type)
{
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf));
g_return_if_fail (n_alphas > 0);
switch (type)
{
case META_GRADIENT_HORIZONTAL:
meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas);
break;
case META_GRADIENT_VERTICAL:
g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_DIAGONAL:
g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}

View File

@@ -1,315 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient test program */
/*
* Copyright (C) 2002 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <meta/gradient.h>
#include <gtk/gtk.h>
typedef void (* RenderGradientFunc) (cairo_t *cr,
int width,
int height);
static void
draw_checkerboard (cairo_t *cr,
int width,
int height)
{
gint i, j, xcount, ycount;
GdkRGBA color1, color2;
#define CHECK_SIZE 10
#define SPACING 2
color1.red = 30000. / 65535.;
color1.green = 30000. / 65535.;
color1.blue = 30000. / 65535.;
color1.alpha = 1.0;
color2.red = 50000. / 65535.;
color2.green = 50000. / 65535.;
color2.blue = 50000. / 65535.;
color2.alpha = 1.0;
xcount = 0;
i = SPACING;
while (i < width)
{
j = SPACING;
ycount = xcount % 2; /* start with even/odd depending on row */
while (j < height)
{
if (ycount % 2)
gdk_cairo_set_source_rgba (cr, &color1);
else
gdk_cairo_set_source_rgba (cr, &color2);
/* If we're outside event->area, this will do nothing.
* It might be mildly more efficient if we handled
* the clipping ourselves, but again we're feeling lazy.
*/
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
cairo_fill (cr);
j += CHECK_SIZE + SPACING;
++ycount;
}
i += CHECK_SIZE + SPACING;
++xcount;
}
}
static void
render_simple (cairo_t *cr,
int width, int height,
MetaGradientType type,
gboolean with_alpha)
{
GdkPixbuf *pixbuf;
GdkRGBA from, to;
gdk_rgba_parse (&from, "blue");
gdk_rgba_parse (&to, "green");
pixbuf = meta_gradient_create_simple (width, height,
&from, &to,
type);
if (with_alpha)
{
const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff };
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
GdkPixbuf *new_pixbuf;
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
meta_gradient_add_alpha (pixbuf,
alphas, G_N_ELEMENTS (alphas),
META_GRADIENT_HORIZONTAL);
draw_checkerboard (cr , width, height);
}
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static void
render_vertical_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE);
}
static void
render_horizontal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
}
static void
render_diagonal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
}
static void
render_diagonal_alpha_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
}
static void
render_multi (cairo_t *cr,
int width, int height,
MetaGradientType type)
{
GdkPixbuf *pixbuf;
#define N_COLORS 5
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "orange");
gdk_rgba_parse (&colors[3], "pink");
gdk_rgba_parse (&colors[4], "green");
pixbuf = meta_gradient_create_multi (width, height,
colors, N_COLORS,
type);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
#undef N_COLORS
}
static void
render_vertical_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_VERTICAL);
}
static void
render_horizontal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_HORIZONTAL);
}
static void
render_diagonal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_DIAGONAL);
}
static void
render_interwoven_func (cairo_t *cr,
int width, int height)
{
GdkPixbuf *pixbuf;
#define N_COLORS 4
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "pink");
gdk_rgba_parse (&colors[3], "green");
pixbuf = meta_gradient_create_interwoven (width, height,
colors, height / 10,
colors + 2, height / 14);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static gboolean
draw_callback (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
RenderGradientFunc func = data;
GtkStyleContext *style;
GdkRGBA color;
style = gtk_widget_get_style_context (widget);
gtk_style_context_save (style);
gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (style, "foreground-color", &color);
gtk_style_context_restore (style);
gdk_cairo_set_source_rgba (cr, &color);
(* func) (cr,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
return FALSE;
}
static GtkWidget*
create_gradient_window (const char *title,
RenderGradientFunc func)
{
GtkWidget *window;
GtkWidget *drawing_area;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), title);
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 1, 1);
gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
g_signal_connect (G_OBJECT (drawing_area),
"draw",
G_CALLBACK (draw_callback),
func);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_show_all (window);
return window;
}
static void
meta_gradient_test (void)
{
create_gradient_window ("Simple vertical",
render_vertical_func);
create_gradient_window ("Simple horizontal",
render_horizontal_func);
create_gradient_window ("Simple diagonal",
render_diagonal_func);
create_gradient_window ("Multi vertical",
render_vertical_multi_func);
create_gradient_window ("Multi horizontal",
render_horizontal_multi_func);
create_gradient_window ("Multi diagonal",
render_diagonal_multi_func);
create_gradient_window ("Interwoven",
render_interwoven_func);
create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
}
int
main (int argc, char **argv)
{
gtk_init (&argc, &argv);
meta_gradient_test ();
gtk_main ();
return 0;
}

View File

@@ -774,9 +774,6 @@ parse_alpha (const char *str,
n_alphas = i;
/* FIXME allow specifying horizontal/vertical/diagonal in theme format,
* once we implement vertical/diagonal in gradient.c
*/
spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
n_alphas);
@@ -2150,11 +2147,9 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *width;
const char *height;
const char *alpha;
const char *colorize;
const char *fill_type;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf;
MetaColorSpec *colorize_spec = NULL;
MetaImageFillType fill_type_val;
int h, w, c;
int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
@@ -2165,7 +2160,6 @@ parse_draw_op_element (GMarkupParseContext *context,
"!x", &x, "!y", &y,
"!width", &width, "!height", &height,
"alpha", &alpha, "!filename", &filename,
"colorize", &colorize,
"fill_type", &fill_type,
NULL))
return;
@@ -2211,18 +2205,6 @@ parse_draw_op_element (GMarkupParseContext *context,
return;
}
if (colorize)
{
colorize_spec = parse_color (info->theme, colorize, error);
if (colorize_spec == NULL)
{
add_context_to_error (error, context);
g_object_unref (G_OBJECT (pixbuf));
return;
}
}
alpha_spec = NULL;
if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
{
@@ -2233,7 +2215,6 @@ parse_draw_op_element (GMarkupParseContext *context,
op = meta_draw_op_new (META_DRAW_IMAGE);
op->data.image.pixbuf = pixbuf;
op->data.image.colorize_spec = colorize_spec;
op->data.image.x = meta_draw_spec_new (info->theme, x, NULL);
op->data.image.y = meta_draw_spec_new (info->theme, y, NULL);

View File

@@ -23,7 +23,6 @@
#define META_THEME_PRIVATE_H
#include <meta/boxes.h>
#include <meta/gradient.h>
#include <meta/theme.h>
#include <meta/common.h>
#include <gtk/gtk.h>
@@ -273,6 +272,14 @@ typedef enum
META_IMAGE_FILL_TILE
} MetaImageFillType;
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
typedef enum
{
META_COLOR_SPEC_BASIC,
@@ -538,7 +545,6 @@ struct _MetaDrawOp
} gradient;
struct {
MetaColorSpec *colorize_spec;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf;
MetaDrawSpec *x;
@@ -546,8 +552,6 @@ struct _MetaDrawOp
MetaDrawSpec *width;
MetaDrawSpec *height;
guint32 colorize_cache_pixel;
GdkPixbuf *colorize_cache_pixbuf;
MetaImageFillType fill_type;
unsigned int vertical_stripes : 1;
unsigned int horizontal_stripes : 1;
@@ -972,8 +976,12 @@ gboolean meta_draw_op_list_contains (MetaDrawOpList *op_list,
MetaGradientSpec* meta_gradient_spec_new (MetaGradientType type);
void meta_gradient_spec_free (MetaGradientSpec *desc);
GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc,
GtkStyleContext *gtk_style,
void meta_gradient_spec_render (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
cairo_t *cr,
GtkStyleContext *style,
int x,
int y,
int width,
int height);
gboolean meta_gradient_spec_validate (MetaGradientSpec *spec,

View File

@@ -38,7 +38,6 @@
#include "theme-private.h"
#include "frames.h" /* for META_TYPE_FRAMES */
#include "util-private.h"
#include <meta/gradient.h>
#include <meta/prefs.h>
#include <gtk/gtk.h>
#include <string.h>
@@ -75,84 +74,6 @@ static void hls_to_rgb (gdouble *h,
*/
static MetaTheme *meta_current_theme = NULL;
static GdkPixbuf *
colorize_pixbuf (GdkPixbuf *orig,
GdkRGBA *new_color)
{
GdkPixbuf *pixbuf;
double intensity;
int x, y;
const guchar *src;
guchar *dest;
int orig_rowstride;
int dest_rowstride;
int width, height;
gboolean has_alpha;
const guchar *src_pixels;
guchar *dest_pixels;
pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
gdk_pixbuf_get_bits_per_sample (orig),
gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
if (pixbuf == NULL)
return NULL;
orig_rowstride = gdk_pixbuf_get_rowstride (orig);
dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
has_alpha = gdk_pixbuf_get_has_alpha (orig);
src_pixels = gdk_pixbuf_get_pixels (orig);
dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
for (y = 0; y < height; y++)
{
src = src_pixels + y * orig_rowstride;
dest = dest_pixels + y * dest_rowstride;
for (x = 0; x < width; x++)
{
double dr, dg, db;
intensity = INTENSITY (src[0], src[1], src[2]) / 255.0;
if (intensity <= 0.5)
{
/* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
dr = new_color->red * intensity * 2.0;
dg = new_color->green * intensity * 2.0;
db = new_color->blue * intensity * 2.0;
}
else
{
/* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
}
dest[0] = CLAMP_UCHAR (255 * dr);
dest[1] = CLAMP_UCHAR (255 * dg);
dest[2] = CLAMP_UCHAR (255 * db);
if (has_alpha)
{
dest[3] = src[3];
src += 4;
dest += 4;
}
else
{
src += 3;
dest += 3;
}
}
}
return pixbuf;
}
static void
color_composite (const GdkRGBA *bg,
const GdkRGBA *fg,
@@ -1010,42 +931,84 @@ meta_gradient_spec_free (MetaGradientSpec *spec)
g_free (spec);
}
GdkPixbuf*
meta_gradient_spec_render (const MetaGradientSpec *spec,
GtkStyleContext *style,
int width,
int height)
static cairo_pattern_t *
meta_gradient_spec_pattern (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
GtkStyleContext *style)
{
cairo_pattern_t *pattern;
int n_colors;
GdkRGBA *colors;
GSList *tmp;
GSList *l;
int i;
GdkPixbuf *pixbuf;
if (spec->type == META_GRADIENT_HORIZONTAL)
pattern = cairo_pattern_create_linear (0, 0, 1, 0);
if (spec->type == META_GRADIENT_VERTICAL)
pattern = cairo_pattern_create_linear (0, 0, 0, 1);
else if (spec->type == META_GRADIENT_DIAGONAL)
pattern = cairo_pattern_create_linear (0, 0, 1, 1);
else
g_assert_not_reached ();
n_colors = g_slist_length (spec->color_specs);
if (n_colors == 0)
return NULL;
colors = g_new (GdkRGBA, n_colors);
if (alpha_spec != NULL)
g_assert (n_colors == alpha_spec->n_alphas);
i = 0;
tmp = spec->color_specs;
while (tmp != NULL)
for (l = spec->color_specs; l != NULL; l = l->next)
{
meta_color_spec_render (tmp->data, style, &colors[i]);
MetaColorSpec *color_spec = l->data;
GdkRGBA color;
tmp = tmp->next;
meta_color_spec_render (color_spec, style, &color);
if (alpha_spec != NULL)
color.alpha *= alpha_spec->alphas[i];
cairo_pattern_add_color_stop_rgba (pattern,
i / (float) n_colors,
color.red,
color.green,
color.blue,
color.alpha);
++i;
}
pixbuf = meta_gradient_create_multi (width, height,
colors, n_colors,
spec->type);
return pattern;
}
g_free (colors);
void
meta_gradient_spec_render (const MetaGradientSpec *spec,
const MetaAlphaGradientSpec *alpha_spec,
cairo_t *cr,
GtkStyleContext *style,
int x,
int y,
int width,
int height)
{
cairo_pattern_t *pattern;
return pixbuf;
cairo_save (cr);
pattern = meta_gradient_spec_pattern (spec, alpha_spec, style);
if (pattern == NULL)
return;
cairo_rectangle (cr, x, y, width, height);
cairo_translate (cr, x, y);
cairo_scale (cr, width, height);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
}
gboolean
@@ -3052,12 +3015,6 @@ meta_draw_op_free (MetaDrawOp *op)
if (op->data.image.pixbuf)
g_object_unref (G_OBJECT (op->data.image.pixbuf));
if (op->data.image.colorize_spec)
meta_color_spec_free (op->data.image.colorize_spec);
if (op->data.image.colorize_cache_pixbuf)
g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
meta_draw_spec_free (op->data.image.x);
meta_draw_spec_free (op->data.image.y);
meta_draw_spec_free (op->data.image.width);
@@ -3132,413 +3089,6 @@ meta_draw_op_free (MetaDrawOp *op)
g_free (op);
}
static GdkPixbuf*
apply_alpha (GdkPixbuf *pixbuf,
MetaAlphaGradientSpec *spec,
gboolean force_copy)
{
GdkPixbuf *new_pixbuf;
gboolean needs_alpha;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
needs_alpha = spec && (spec->n_alphas > 1 ||
spec->alphas[0] != 0xff);
if (!needs_alpha)
return pixbuf;
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
else if (force_copy)
{
new_pixbuf = gdk_pixbuf_copy (pixbuf);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
return pixbuf;
}
static GdkPixbuf*
pixbuf_tile (GdkPixbuf *tile,
int width,
int height)
{
GdkPixbuf *pixbuf;
int tile_width;
int tile_height;
int i, j;
tile_width = gdk_pixbuf_get_width (tile);
tile_height = gdk_pixbuf_get_height (tile);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
gdk_pixbuf_get_has_alpha (tile),
8, width, height);
i = 0;
while (i < width)
{
j = 0;
while (j < height)
{
int w, h;
w = MIN (tile_width, width - i);
h = MIN (tile_height, height - j);
gdk_pixbuf_copy_area (tile,
0, 0,
w, h,
pixbuf,
i, j);
j += tile_height;
}
i += tile_width;
}
return pixbuf;
}
static GdkPixbuf *
replicate_rows (GdkPixbuf *src,
int src_x,
int src_y,
int width,
int height)
{
unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
* n_channels);
unsigned char *dest_pixels;
GdkPixbuf *result;
unsigned int dest_rowstride;
int i;
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
width, height);
dest_rowstride = gdk_pixbuf_get_rowstride (result);
dest_pixels = gdk_pixbuf_get_pixels (result);
for (i = 0; i < height; i++)
memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
return result;
}
static GdkPixbuf *
replicate_cols (GdkPixbuf *src,
int src_x,
int src_y,
int width,
int height)
{
unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
* n_channels);
unsigned char *dest_pixels;
GdkPixbuf *result;
unsigned int dest_rowstride;
int i, j;
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
width, height);
dest_rowstride = gdk_pixbuf_get_rowstride (result);
dest_pixels = gdk_pixbuf_get_pixels (result);
for (i = 0; i < height; i++)
{
unsigned char *p = dest_pixels + dest_rowstride * i;
unsigned char *q = pixels + src_rowstride * i;
unsigned char r = *(q++);
unsigned char g = *(q++);
unsigned char b = *(q++);
if (n_channels == 4)
{
unsigned char a;
a = *(q++);
for (j = 0; j < width; j++)
{
*(p++) = r;
*(p++) = g;
*(p++) = b;
*(p++) = a;
}
}
else
{
for (j = 0; j < width; j++)
{
*(p++) = r;
*(p++) = g;
*(p++) = b;
}
}
}
return result;
}
static GdkPixbuf*
scale_and_alpha_pixbuf (GdkPixbuf *src,
MetaAlphaGradientSpec *alpha_spec,
MetaImageFillType fill_type,
int width,
int height,
gboolean vertical_stripes,
gboolean horizontal_stripes)
{
GdkPixbuf *pixbuf;
GdkPixbuf *temp_pixbuf;
pixbuf = NULL;
pixbuf = src;
if (gdk_pixbuf_get_width (pixbuf) == width &&
gdk_pixbuf_get_height (pixbuf) == height)
{
g_object_ref (G_OBJECT (pixbuf));
}
else
{
if (fill_type == META_IMAGE_FILL_TILE)
{
pixbuf = pixbuf_tile (pixbuf, width, height);
}
else
{
int src_h, src_w, dest_h, dest_w;
src_h = gdk_pixbuf_get_height (src);
src_w = gdk_pixbuf_get_width (src);
/* prefer to replicate_cols if possible, as that
* is faster (no memory reads)
*/
if (horizontal_stripes)
{
dest_w = gdk_pixbuf_get_width (src);
dest_h = height;
}
else if (vertical_stripes)
{
dest_w = width;
dest_h = gdk_pixbuf_get_height (src);
}
else
{
dest_w = width;
dest_h = height;
}
if (dest_w == src_w && dest_h == src_h)
{
temp_pixbuf = src;
g_object_ref (G_OBJECT (temp_pixbuf));
}
else
{
temp_pixbuf = gdk_pixbuf_scale_simple (src,
dest_w, dest_h,
GDK_INTERP_BILINEAR);
}
/* prefer to replicate_cols if possible, as that
* is faster (no memory reads)
*/
if (horizontal_stripes)
{
pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
g_object_unref (G_OBJECT (temp_pixbuf));
}
else if (vertical_stripes)
{
pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
g_object_unref (G_OBJECT (temp_pixbuf));
}
else
{
pixbuf = temp_pixbuf;
}
}
}
if (pixbuf)
pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
return pixbuf;
}
static GdkPixbuf*
draw_op_as_pixbuf (const MetaDrawOp *op,
GtkStyleContext *context,
const MetaDrawInfo *info,
int width,
int height)
{
/* Try to get the op as a pixbuf, assuming w/h in the op
* matches the width/height passed in. return NULL
* if the op can't be converted to an equivalent pixbuf.
*/
GdkPixbuf *pixbuf;
pixbuf = NULL;
switch (op->type)
{
case META_DRAW_TINT:
{
GdkRGBA color;
guint32 rgba;
gboolean has_alpha;
meta_color_spec_render (op->data.rectangle.color_spec,
context,
&color);
has_alpha =
op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
has_alpha,
8, width, height);
if (!has_alpha)
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
}
else if (op->data.tint.alpha_spec->n_alphas == 1)
{
rgba = GDK_COLOR_RGBA (color);
rgba &= ~0xff;
rgba |= op->data.tint.alpha_spec->alphas[0];
gdk_pixbuf_fill (pixbuf, rgba);
}
else
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
meta_gradient_add_alpha (pixbuf,
op->data.tint.alpha_spec->alphas,
op->data.tint.alpha_spec->n_alphas,
op->data.tint.alpha_spec->type);
}
}
break;
case META_DRAW_GRADIENT:
{
pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec,
context, width, height);
pixbuf = apply_alpha (pixbuf,
op->data.gradient.alpha_spec,
FALSE);
}
break;
case META_DRAW_IMAGE:
{
if (op->data.image.colorize_spec)
{
GdkRGBA color;
meta_color_spec_render (op->data.image.colorize_spec,
context, &color);
if (op->data.image.colorize_cache_pixbuf == NULL ||
op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color))
{
if (op->data.image.colorize_cache_pixbuf)
g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
/* const cast here */
((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
colorize_pixbuf (op->data.image.pixbuf,
&color);
((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
GDK_COLOR_RGB (color);
}
if (op->data.image.colorize_cache_pixbuf)
{
pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
op->data.image.alpha_spec,
op->data.image.fill_type,
width, height,
op->data.image.vertical_stripes,
op->data.image.horizontal_stripes);
}
}
else
{
pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
op->data.image.alpha_spec,
op->data.image.fill_type,
width, height,
op->data.image.vertical_stripes,
op->data.image.horizontal_stripes);
}
break;
}
case META_DRAW_ICON:
if (info->mini_icon &&
width <= gdk_pixbuf_get_width (info->mini_icon) &&
height <= gdk_pixbuf_get_height (info->mini_icon))
pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
op->data.icon.alpha_spec,
op->data.icon.fill_type,
width, height,
FALSE, FALSE);
else if (info->icon)
pixbuf = scale_and_alpha_pixbuf (info->icon,
op->data.icon.alpha_spec,
op->data.icon.fill_type,
width, height,
FALSE, FALSE);
break;
case META_DRAW_LINE:
case META_DRAW_RECTANGLE:
case META_DRAW_ARC:
case META_DRAW_CLIP:
case META_DRAW_GTK_ARROW:
case META_DRAW_GTK_BOX:
case META_DRAW_GTK_VLINE:
case META_DRAW_TITLE:
case META_DRAW_OP_LIST:
case META_DRAW_TILE:
break;
}
return pixbuf;
}
static void
fill_env (MetaPositionExprEnv *env,
const MetaDrawInfo *info,
@@ -3578,6 +3128,86 @@ fill_env (MetaPositionExprEnv *env,
env->theme = meta_current_theme;
}
static cairo_pattern_t *
meta_alpha_gradient_spec_pattern (const MetaAlphaGradientSpec *alpha_spec)
{
/* Hardcoded in theme-parser.c */
g_assert (alpha_spec->type == META_GRADIENT_HORIZONTAL);
int n_alphas = alpha_spec->n_alphas;
if (n_alphas == 0)
return NULL;
else if (n_alphas == 1)
return cairo_pattern_create_rgba (0, 0, 0, alpha_spec->alphas[0]);
else
{
cairo_pattern_t *pattern = cairo_pattern_create_linear (0, 0, 1, 0);
int i;
for (i = 0; i < n_alphas; i++)
cairo_pattern_add_color_stop_rgba (pattern,
i / (float) n_alphas,
0, 0, 0, alpha_spec->alphas[i]);
return pattern;
}
}
static void
draw_image (cairo_t *cr,
GdkPixbuf *src,
MetaImageFillType fill_type,
MetaAlphaGradientSpec *alpha_spec,
int x,
int y,
int width,
int height)
{
cairo_save (cr);
cairo_rectangle (cr, x, y, width, height);
if (fill_type == META_IMAGE_FILL_TILE)
{
gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
cairo_pattern_set_extend (cairo_get_source (cr),
CAIRO_EXTEND_REPEAT);
}
else
{
float pixbuf_width, pixbuf_height;
pixbuf_width = gdk_pixbuf_get_width (src);
pixbuf_height = gdk_pixbuf_get_height (src);
cairo_save (cr);
cairo_translate (cr, x, y);
cairo_scale (cr,
pixbuf_width / width,
pixbuf_height / height);
gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
cairo_restore (cr);
}
if (alpha_spec)
{
cairo_translate (cr, x, y);
cairo_scale (cr, width, height);
cairo_pattern_t *pattern = meta_alpha_gradient_spec_pattern (alpha_spec);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
}
else
{
cairo_fill (cr);
}
cairo_restore (cr);
}
/* This code was originally rendering anti-aliased using X primitives, and
* now has been switched to draw anti-aliased using cairo. In general, the
@@ -3601,7 +3231,6 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
GdkRGBA color;
cairo_save (cr);
gtk_style_context_save (style_gtk);
cairo_set_line_width (cr, 1.0);
@@ -3759,94 +3388,63 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_TINT:
{
int rx, ry, rwidth, rheight;
gboolean needs_alpha;
needs_alpha = op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
rx = parse_x_position_unchecked (op->data.tint.x, env);
ry = parse_y_position_unchecked (op->data.tint.y, env);
rwidth = parse_size_unchecked (op->data.tint.width, env);
rheight = parse_size_unchecked (op->data.tint.height, env);
if (!needs_alpha)
{
meta_color_spec_render (op->data.tint.color_spec,
style_gtk, &color);
gdk_cairo_set_source_rgba (cr, &color);
meta_color_spec_render (op->data.tint.color_spec,
style_gtk, &color);
cairo_rectangle (cr, rx, ry, rwidth, rheight);
cairo_fill (cr);
}
else
{
GdkPixbuf *pixbuf;
if (op->data.tint.alpha_spec &&
op->data.tint.alpha_spec->n_alphas == 1)
color.alpha = op->data.tint.alpha_spec->alphas[0];
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
gdk_cairo_set_source_rgba (cr, &color);
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
}
cairo_rectangle (cr, rx, ry, rwidth, rheight);
cairo_fill (cr);
}
break;
case META_DRAW_GRADIENT:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
rx = parse_x_position_unchecked (op->data.gradient.x, env);
ry = parse_y_position_unchecked (op->data.gradient.y, env);
rwidth = parse_size_unchecked (op->data.gradient.width, env);
rheight = parse_size_unchecked (op->data.gradient.height, env);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
meta_gradient_spec_render (op->data.gradient.gradient_spec,
op->data.gradient.alpha_spec,
cr, style_gtk,
rx, ry, rwidth, rheight);
}
break;
case META_DRAW_IMAGE:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
if (op->data.image.pixbuf)
{
env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
}
if (op->data.image.pixbuf == NULL)
break;
env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
rx = parse_x_position_unchecked (op->data.image.x, env);
ry = parse_y_position_unchecked (op->data.image.y, env);
rwidth = parse_size_unchecked (op->data.image.width, env);
rheight = parse_size_unchecked (op->data.image.height, env);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (pixbuf)
{
rx = parse_x_position_unchecked (op->data.image.x, env);
ry = parse_y_position_unchecked (op->data.image.y, env);
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
draw_image (cr,
op->data.image.pixbuf,
op->data.image.fill_type,
op->data.image.alpha_spec,
rx, ry, rwidth, rheight);
}
break;
@@ -3916,24 +3514,27 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_ICON:
{
int rx, ry, rwidth, rheight;
GdkPixbuf *pixbuf;
GdkPixbuf *src;
rwidth = parse_size_unchecked (op->data.icon.width, env);
rheight = parse_size_unchecked (op->data.icon.height, env);
pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
rwidth, rheight);
if (info->mini_icon &&
rwidth < gdk_pixbuf_get_width (info->mini_icon) &&
rheight < gdk_pixbuf_get_height (info->mini_icon))
src = info->mini_icon;
else if (info->icon)
src = info->icon;
else
break;
if (pixbuf)
{
rx = parse_x_position_unchecked (op->data.icon.x, env);
ry = parse_y_position_unchecked (op->data.icon.y, env);
rx = parse_x_position_unchecked (op->data.icon.x, env);
ry = parse_y_position_unchecked (op->data.icon.y, env);
gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
cairo_paint (cr);
g_object_unref (G_OBJECT (pixbuf));
}
draw_image (cr, src,
op->data.icon.fill_type,
op->data.icon.alpha_spec,
rx, ry, rwidth, rheight);
}
break;
@@ -4053,7 +3654,6 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
}
cairo_restore (cr);
gtk_style_context_restore (style_gtk);
}
void

View File

@@ -0,0 +1,137 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* 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., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-wayland-buffer.h"
#include <clutter/clutter.h>
#include <cogl/cogl-wayland-server.h>
#include <meta/util.h>
static void
meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
void *data)
{
MetaWaylandBuffer *buffer =
wl_container_of (listener, buffer, destroy_listener);
wl_signal_emit (&buffer->destroy_signal, buffer);
g_slice_free (MetaWaylandBuffer, buffer);
}
void
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
{
buffer->ref_count++;
}
void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_clear_pointer (&buffer->texture, cogl_object_unref);
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
}
MetaWaylandBuffer *
meta_wayland_buffer_from_resource (struct wl_resource *resource)
{
MetaWaylandBuffer *buffer;
struct wl_listener *listener;
listener =
wl_resource_get_destroy_listener (resource,
meta_wayland_buffer_destroy_handler);
if (listener)
{
buffer = wl_container_of (listener, buffer, destroy_listener);
}
else
{
buffer = g_slice_new0 (MetaWaylandBuffer);
buffer->resource = resource;
wl_signal_init (&buffer->destroy_signal);
buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler;
wl_resource_add_destroy_listener (resource, &buffer->destroy_listener);
}
return buffer;
}
CoglTexture *
meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglError *catch_error = NULL;
CoglTexture *texture;
if (buffer->texture)
goto out;
texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
buffer->resource,
&catch_error));
if (!texture)
{
cogl_error_free (catch_error);
meta_fatal ("Could not import pending buffer, ignoring commit\n");
}
buffer->texture = texture;
out:
return buffer->texture;
}
void
meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
cairo_region_t *region)
{
struct wl_shm_buffer *shm_buffer;
shm_buffer = wl_shm_buffer_get (buffer->resource);
if (shm_buffer)
{
int i, n_rectangles;
n_rectangles = cairo_region_num_rectangles (region);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
cogl_wayland_texture_set_region_from_shm_buffer (buffer->texture,
rect.x, rect.y, rect.width, rect.height,
shm_buffer,
rect.x, rect.y, 0, NULL);
}
}
}

View File

@@ -0,0 +1,51 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* 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., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_WAYLAND_BUFFER_H
#define META_WAYLAND_BUFFER_H
#include <cogl/cogl.h>
#include <cairo.h>
#include <wayland-server.h>
#include "meta-wayland-types.h"
struct _MetaWaylandBuffer
{
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
CoglTexture *texture;
uint32_t ref_count;
};
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
CoglTexture * meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
cairo_region_t *region);
#endif /* META_WAYLAND_BUFFER_H */

View File

@@ -34,6 +34,7 @@
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "meta-dnd-actor-private.h"
typedef struct
{
@@ -46,6 +47,7 @@ struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
gboolean has_target;
};
static void
@@ -67,7 +69,10 @@ data_offer_accept (struct wl_client *client,
* this be a wl_data_device request? */
if (offer->source)
wl_data_source_send_target (offer->source->resource, mime_type);
{
wl_data_source_send_target (offer->source->resource, mime_type);
offer->source->has_target = mime_type != NULL;
}
}
static void
@@ -162,7 +167,7 @@ static struct wl_data_source_interface data_source_interface = {
data_source_destroy
};
typedef struct {
struct _MetaWaylandDragGrab {
MetaWaylandPointerGrab generic;
MetaWaylandSeat *seat;
@@ -177,7 +182,14 @@ typedef struct {
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
} MetaWaylandDragGrab;
ClutterActor *feedback_actor;
MetaWaylandSurface *drag_origin;
struct wl_listener drag_origin_listener;
int drag_start_x, drag_start_y;
};
static void
destroy_drag_focus (struct wl_listener *listener, void *data)
@@ -257,11 +269,21 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
clutter_event_get_time (event),
sx, sy);
}
if (drag_grab->drag_surface)
meta_feedback_actor_update (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
event);
}
static void
data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
{
if (drag_grab->drag_origin)
{
drag_grab->drag_origin = NULL;
wl_list_remove (&drag_grab->drag_origin_listener.link);
}
if (drag_grab->drag_surface)
{
drag_grab->drag_surface = NULL;
@@ -269,7 +291,18 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
}
if (drag_grab->drag_data_source)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
{
drag_grab->drag_data_source->has_target = FALSE;
wl_list_remove (&drag_grab->drag_data_source_listener.link);
}
if (drag_grab->feedback_actor)
{
clutter_actor_remove_all_children (drag_grab->feedback_actor);
clutter_actor_destroy (drag_grab->feedback_actor);
}
drag_grab->seat->data_device.current_grab = NULL;
drag_grab_focus (&drag_grab->generic, NULL);
@@ -285,10 +318,23 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
MetaWaylandSeat *seat = drag_grab->seat;
ClutterEventType event_type = clutter_event_type (event);
if (drag_grab->drag_focus_data_device &&
drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
{
gboolean success = FALSE;
if (drag_grab->drag_focus_data_device &&
drag_grab->drag_data_source->has_target)
{
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
success = TRUE;
}
/* Finish drag and let actor self-destruct */
meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor),
success);
drag_grab->feedback_actor = NULL;
}
if (seat->pointer.button_count == 0 &&
event_type == CLUTTER_BUTTON_RELEASE)
@@ -301,6 +347,16 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
drag_grab_button,
};
static void
destroy_data_device_origin (struct wl_listener *listener, void *data)
{
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_origin_listener);
drag_grab->drag_origin = NULL;
data_device_end_drag_grab (drag_grab);
}
static void
destroy_data_device_source (struct wl_listener *listener, void *data)
{
@@ -318,6 +374,9 @@ destroy_data_device_icon (struct wl_listener *listener, void *data)
wl_container_of (listener, drag_grab, drag_data_source_listener);
drag_grab->drag_surface = NULL;
if (drag_grab->feedback_actor)
clutter_actor_remove_all_children (drag_grab->feedback_actor);
}
static void
@@ -329,20 +388,29 @@ data_device_start_drag (struct wl_client *client,
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandSurface *surface = NULL;
MetaWaylandDragGrab *drag_grab;
ClutterPoint pos;
if ((seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource)))
if (origin_resource)
surface = wl_resource_get_user_data (origin_resource);
if (!surface)
return;
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != surface)
return;
/* FIXME: Check that the data source type array isn't empty. */
if (seat->pointer.grab != &seat->pointer.default_grab)
if (data_device->current_grab ||
seat->pointer.grab != &seat->pointer.default_grab)
return;
drag_grab = g_slice_new0 (MetaWaylandDragGrab);
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
drag_grab->generic.interface = &drag_grab_interface;
drag_grab->generic.pointer = &seat->pointer;
@@ -350,6 +418,17 @@ data_device_start_drag (struct wl_client *client,
drag_grab->drag_client = client;
drag_grab->seat = seat;
drag_grab->drag_origin = surface;
drag_grab->drag_origin_listener.notify = destroy_data_device_origin;
wl_resource_add_destroy_listener (origin_resource,
&drag_grab->drag_origin_listener);
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
pos.x, pos.y, &pos.x, &pos.y);
drag_grab->drag_start_x = pos.x;
drag_grab->drag_start_y = pos.y;
if (source_resource)
{
drag_grab->drag_data_source = wl_resource_get_user_data (source_resource);
@@ -364,6 +443,19 @@ data_device_start_drag (struct wl_client *client,
drag_grab->drag_icon_listener.notify = destroy_data_device_icon;
wl_resource_add_destroy_listener (icon_resource,
&drag_grab->drag_icon_listener);
drag_grab->feedback_actor = meta_dnd_actor_new (CLUTTER_ACTOR (drag_grab->drag_origin->surface_actor),
drag_grab->drag_start_x,
drag_grab->drag_start_y);
meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
-drag_grab->drag_surface->offset_x,
-drag_grab->drag_surface->offset_y);
clutter_actor_add_child (drag_grab->feedback_actor,
CLUTTER_ACTOR (drag_grab->drag_surface->surface_actor));
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
meta_feedback_actor_set_position (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
pos.x, pos.y);
}
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
@@ -551,3 +643,29 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
wl_data_device_send_selection (data_device_resource, offer);
}
}
gboolean
meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface)
{
return data_device->current_grab &&
data_device->current_grab->drag_surface == surface;
}
void
meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device)
{
MetaWaylandDragGrab *drag_grab;
if (!data_device->current_grab)
return;
drag_grab = data_device->current_grab;
if (!drag_grab->feedback_actor || !drag_grab->drag_surface)
return;
meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
-drag_grab->drag_surface->offset_x,
-drag_grab->drag_surface->offset_y);
}

View File

@@ -27,12 +27,15 @@
#include "meta-wayland-types.h"
typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
struct _MetaWaylandDataDevice
{
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
MetaWaylandDragGrab *current_grab;
};
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@@ -41,4 +44,8 @@ void meta_wayland_data_device_init (MetaWaylandDataDevice *data_device);
void meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device);
gboolean meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface);
void meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_H */

View File

@@ -383,8 +383,6 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy;
wl_array_init (&keyboard->pressed_keys);
keyboard->xkb_info.keymap_fd = -1;
keyboard->settings = g_settings_new ("org.gnome.settings-daemon.peripherals.keyboard");
@@ -417,47 +415,12 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
/* XXX: What about keyboard->resource_list? */
wl_array_release (&keyboard->pressed_keys);
g_object_unref (keyboard->settings);
keyboard->display = NULL;
}
static void
update_pressed_keys (struct wl_array *keys,
uint32_t evdev_code,
gboolean is_press)
{
uint32_t *end = (void *) ((char *) keys->data + keys->size);
uint32_t *k;
if (is_press)
{
/* Make sure we don't already have this key. */
for (k = keys->data; k < end; k++)
if (*k == evdev_code)
return;
/* Otherwise add the key to the list of pressed keys */
k = wl_array_add (keys, sizeof (*k));
*k = evdev_code;
}
else
{
/* Remove the key from the array */
for (k = keys->data; k < end; k++)
if (*k == evdev_code)
{
*k = *(end - 1);
keys->size -= sizeof (*k);
return;
}
g_warning ("unexpected key release event for key 0x%x", evdev_code);
}
}
static guint
evdev_code (const ClutterKeyEvent *event)
{
@@ -471,18 +434,10 @@ meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event)
{
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
struct xkb_state *state = keyboard->xkb_info.state;
enum xkb_state_component changed_state;
update_pressed_keys (&keyboard->pressed_keys, evdev_code (event), is_press);
changed_state = xkb_state_update_key (state,
event->hardware_keycode,
is_press ? XKB_KEY_DOWN : XKB_KEY_UP);
if (changed_state == 0)
return;
notify_modifiers (keyboard);
keyboard->mods_changed = xkb_state_update_key (keyboard->xkb_info.state,
event->hardware_keycode,
is_press ? XKB_KEY_DOWN : XKB_KEY_UP);
}
gboolean
@@ -508,6 +463,12 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
else
meta_verbose ("No wayland surface is focused, continuing normal operation\n");
if (keyboard->mods_changed != 0)
{
notify_modifiers (keyboard);
keyboard->mods_changed = 0;
}
return handled;
}
@@ -538,8 +499,27 @@ static void
broadcast_focus (MetaWaylandKeyboard *keyboard,
struct wl_resource *resource)
{
struct wl_array fake_keys;
struct xkb_state *state = keyboard->xkb_info.state;
/* We never want to send pressed keys to wayland clients on
* enter. The protocol says that we should send them, presumably so
* that clients can trigger their own key repeat routine in case
* they are given focus and a key is physically pressed.
*
* Unfortunately this causes some clients, in particular Xwayland,
* to register key events that they really shouldn't handle,
* e.g. on an Alt+Tab keybinding, where Alt is released before Tab,
* clients would see Tab being pressed on enter followed by a key
* release event for Tab, meaning that Tab would be processed by
* the client when it really shouldn't.
*
* Since the use case for the pressed keys array on enter seems weak
* to us, we'll just fake that there are no pressed keys instead
* which should be spec compliant even if it might not be true.
*/
wl_array_init (&fake_keys);
wl_keyboard_send_modifiers (resource, keyboard->focus_serial,
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
@@ -547,7 +527,7 @@ broadcast_focus (MetaWaylandKeyboard *keyboard,
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
wl_keyboard_send_enter (resource, keyboard->focus_serial,
keyboard->focus_surface->resource,
&keyboard->pressed_keys);
&fake_keys);
}
void

View File

@@ -69,9 +69,8 @@ struct _MetaWaylandKeyboard
struct wl_listener focus_surface_listener;
uint32_t focus_serial;
struct wl_array pressed_keys;
MetaWaylandXkbInfo xkb_info;
enum xkb_state_component mods_changed;
GSettings *settings;
};

View File

@@ -75,6 +75,14 @@ compute_scale (MetaOutput *output)
output->crtc->rect.width >= SMALLEST_4K_WIDTH)
goto out;
/* Somebody encoded the aspect ratio (16/9 or 16/10)
* instead of the physical size */
if ((output->width_mm == 160 && output->height_mm == 90) ||
(output->width_mm == 160 && output->height_mm == 100) ||
(output->width_mm == 16 && output->height_mm == 9) ||
(output->width_mm == 16 && output->height_mm == 10))
goto out;
if (output->width_mm > 0 && output->height_mm > 0)
{
double dpi_x, dpi_y;

View File

@@ -48,6 +48,7 @@
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "meta-wayland-buffer.h"
#include "meta-cursor.h"
#include "meta-cursor-tracker-private.h"
#include "meta-surface-actor-wayland.h"
@@ -272,11 +273,8 @@ sync_focus_surface (MetaWaylandPointer *pointer)
g_assert_not_reached ();
}
if (focus_surface != pointer->focus_surface)
{
const MetaWaylandPointerGrabInterface *interface = pointer->grab->interface;
interface->focus (pointer->grab, focus_surface);
}
const MetaWaylandPointerGrabInterface *interface = pointer->grab->interface;
interface->focus (pointer->grab, focus_surface);
}
static void
@@ -308,9 +306,6 @@ repick_for_event (MetaWaylandPointer *pointer,
else
pointer->current = NULL;
if (pointer->cursor_tracker && pointer->current == NULL)
meta_cursor_tracker_unset_window_cursor (pointer->cursor_tracker);
sync_focus_surface (pointer);
}
@@ -523,10 +518,11 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
clutter_input_device_get_coords (pointer->device, NULL, &pos);
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
pos.x, pos.y);
if (pointer->focus_surface->window)
meta_window_handle_enter (pointer->focus_surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
pos.x, pos.y);
move_resources_for_client (&pointer->focus_resource_list,
&pointer->resource_list,
@@ -545,6 +541,8 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
}
}
}
meta_wayland_pointer_update_cursor_surface (pointer);
}
void
@@ -569,6 +567,8 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
pointer->grab = &pointer->default_grab;
interface = pointer->grab->interface;
interface->focus (pointer->grab, pointer->current);
meta_wayland_pointer_update_cursor_surface (pointer);
}
typedef struct {
@@ -718,10 +718,10 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
popup->grab = grab;
popup->surface = surface;
popup->surface_destroy_listener.notify = on_popup_surface_destroy;
if (surface->xdg_popup.resource)
wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener);
else if (surface->wl_shell_surface.resource)
wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener);
if (surface->xdg_popup)
wl_resource_add_destroy_listener (surface->xdg_popup, &popup->surface_destroy_listener);
else if (surface->wl_shell_surface)
wl_resource_add_destroy_listener (surface->wl_shell_surface, &popup->surface_destroy_listener);
wl_list_insert (&grab->all_popups, &popup->link);
return TRUE;
@@ -753,25 +753,32 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
{
MetaCursorReference *cursor;
if (pointer->cursor_tracker == NULL)
return;
if (pointer->cursor_surface && pointer->cursor_surface->buffer)
if (pointer->current)
{
struct wl_resource *buffer = pointer->cursor_surface->buffer->resource;
cursor = meta_cursor_reference_from_buffer (buffer,
pointer->hotspot_x,
pointer->hotspot_y);
MetaCursorReference *cursor;
if (pointer->cursor_surface && pointer->cursor_surface->buffer)
{
struct wl_resource *buffer = pointer->cursor_surface->buffer->resource;
cursor = meta_cursor_reference_from_buffer (buffer,
pointer->hotspot_x,
pointer->hotspot_y);
}
else
cursor = NULL;
meta_cursor_tracker_set_window_cursor (pointer->cursor_tracker, cursor);
if (cursor)
meta_cursor_reference_unref (cursor);
}
else
cursor = NULL;
meta_cursor_tracker_set_window_cursor (pointer->cursor_tracker, cursor);
if (cursor)
meta_cursor_reference_unref (cursor);
{
meta_cursor_tracker_unset_window_cursor (pointer->cursor_tracker);
}
}
static void

View File

@@ -24,7 +24,6 @@
#include <clutter/clutter.h>
#include <glib.h>
#include <cairo.h>
#include "window-private.h"
#include <meta/meta-cursor-tracker.h>
@@ -34,19 +33,6 @@
#include "meta-wayland-surface.h"
#include "meta-wayland-seat.h"
typedef struct
{
struct wl_resource *resource;
cairo_region_t *region;
} MetaWaylandRegion;
typedef struct
{
GSource source;
GPollFD pfd;
struct wl_display *display;
} WaylandEventSource;
typedef struct
{
struct wl_list link;
@@ -71,7 +57,6 @@ struct _MetaWaylandCompositor
{
struct wl_display *wayland_display;
const char *display_name;
ClutterActor *stage;
GHashTable *outputs;
struct wl_list frame_callbacks;
@@ -80,8 +65,4 @@ struct _MetaWaylandCompositor
MetaWaylandSeat *seat;
};
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
#endif /* META_WAYLAND_PRIVATE_H */

View File

@@ -0,0 +1,105 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* 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., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-wayland-region.h"
struct _MetaWaylandRegion
{
struct wl_resource *resource;
cairo_region_t *region;
};
static void
wl_region_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
wl_region_add (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_union_rectangle (region->region, &rectangle);
}
static void
wl_region_subtract (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_subtract_rectangle (region->region, &rectangle);
}
static const struct wl_region_interface meta_wayland_wl_region_interface = {
wl_region_destroy,
wl_region_add,
wl_region_subtract
};
static void
wl_region_destructor (struct wl_resource *resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_region_destroy (region->region);
g_slice_free (MetaWaylandRegion, region);
}
MetaWaylandRegion *
meta_wayland_region_create (MetaWaylandCompositor *compositor,
struct wl_client *client,
struct wl_resource *compositor_resource,
guint32 id)
{
MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion);
region->resource = wl_resource_create (client, &wl_region_interface, wl_resource_get_version (compositor_resource), id);
wl_resource_set_implementation (region->resource, &meta_wayland_wl_region_interface, region, wl_region_destructor);
region->region = cairo_region_create ();
return region;
}
cairo_region_t *
meta_wayland_region_peek_cairo_region (MetaWaylandRegion *region)
{
return region->region;
}

View File

@@ -0,0 +1,40 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Endless Mobile
*
* 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., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_WAYLAND_REGION_H
#define META_WAYLAND_REGION_H
#include <glib.h>
#include <cairo.h>
#include <wayland-server.h>
#include "meta-wayland-types.h"
MetaWaylandRegion * meta_wayland_region_create (MetaWaylandCompositor *compositor,
struct wl_client *client,
struct wl_resource *compositor_resource,
guint32 id);
cairo_region_t * meta_wayland_region_peek_cairo_region (MetaWaylandRegion *region);
#endif /* META_WAYLAND_REGION_H */

View File

@@ -20,29 +20,24 @@
* 02111-1307, USA.
*/
#include <config.h>
#include "config.h"
#include "meta-wayland-surface.h"
#include <clutter/clutter.h>
#include <clutter/wayland/clutter-wayland-compositor.h>
#include <clutter/wayland/clutter-wayland-surface.h>
#include <cogl/cogl-wayland-server.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayland-server.h>
#include "gtk-shell-server-protocol.h"
#include "xdg-shell-server-protocol.h"
#include "scaler-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-xwayland-private.h"
#include "meta-wayland-buffer.h"
#include "meta-wayland-region.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-keyboard.h"
#include "meta-wayland-pointer.h"
@@ -52,9 +47,6 @@
#include "display-private.h"
#include "window-private.h"
#include "window-wayland.h"
#include <meta/types.h>
#include <meta/main.h>
#include "frame.h"
#include "meta-surface-actor.h"
#include "meta-surface-actor-wayland.h"
@@ -106,67 +98,38 @@ static void
surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *region)
{
int i, n_rectangles;
cairo_rectangle_int_t buffer_rect;
int scale = surface->scale;
CoglTexture *texture;
struct wl_shm_buffer *shm_buffer;
int i, n_rectangles;
/* Damage without a buffer makes no sense so ignore that, otherwise we would crash */
if (!surface->buffer)
return;
texture = surface->buffer->texture;
buffer_rect.x = 0;
buffer_rect.y = 0;
buffer_rect.width = cogl_texture_get_width (surface->buffer->texture);
buffer_rect.height = cogl_texture_get_height (surface->buffer->texture);
/* The region will get destroyed after this call anyway so we can
just modify it here to avoid a copy */
* just modify it here to avoid a copy. */
cairo_region_intersect_rectangle (region, &buffer_rect);
/* First update the buffer. */
meta_wayland_buffer_process_damage (surface->buffer, region);
/* Now damage the actor. */
/* XXX: Should this be a signal / callback on MetaWaylandBuffer instead? */
n_rectangles = cairo_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (surface->buffer->resource);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
if (shm_buffer)
cogl_wayland_texture_set_region_from_shm_buffer (texture, rect.x, rect.y, rect.width, rect.height, shm_buffer, rect.x, rect.y, 0, NULL);
meta_surface_actor_process_damage (surface->surface_actor,
rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);
}
}
static void
ensure_buffer_texture (MetaWaylandBuffer *buffer)
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglError *catch_error = NULL;
CoglTexture *texture;
if (buffer->texture)
return;
texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
buffer->resource,
&catch_error));
if (!texture)
{
cogl_error_free (catch_error);
meta_warning ("Could not import pending buffer, ignoring commit\n");
return;
}
buffer->texture = texture;
}
static void
cursor_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
@@ -175,6 +138,13 @@ cursor_surface_commit (MetaWaylandSurface *surface,
meta_wayland_seat_update_cursor_surface (surface->compositor->seat);
}
static void
dnd_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
meta_wayland_data_device_update_dnd_surface (&surface->compositor->seat->data_device);
}
static void
calculate_surface_window_geometry (MetaWaylandSurface *surface,
MetaRectangle *total_geometry,
@@ -296,6 +266,7 @@ pending_state_init (MetaWaylandPendingState *state)
wl_list_init (&state->frame_callback_list);
state->has_new_geometry = FALSE;
state->viewport.changed = FALSE;
}
static void
@@ -418,8 +389,8 @@ commit_pending_state (MetaWaylandSurface *surface,
if (pending->buffer)
{
ensure_buffer_texture (pending->buffer);
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), pending->buffer->texture);
CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), texture);
}
}
@@ -429,6 +400,9 @@ commit_pending_state (MetaWaylandSurface *surface,
if (!cairo_region_is_empty (pending->damage))
surface_process_damage (surface, pending->damage);
surface->offset_x += pending->dx;
surface->offset_y += pending->dy;
if (pending->opaque_region)
{
pending->opaque_region = scale_region (pending->opaque_region, surface->scale);
@@ -436,19 +410,11 @@ commit_pending_state (MetaWaylandSurface *surface,
}
if (pending->input_region)
{
pending->input_region = scale_region (pending->input_region, surface->scale);
pending->input_region = scale_region (pending->input_region,
meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor)));
meta_surface_actor_set_input_region (surface->surface_actor, pending->input_region);
}
if (surface == compositor->seat->pointer.cursor_surface)
cursor_surface_commit (surface, pending);
else if (surface->window)
toplevel_surface_commit (surface, pending);
else if (surface->subsurface.resource)
subsurface_surface_commit (surface, pending);
g_list_foreach (surface->subsurfaces, parent_surface_committed, NULL);
/* scale surface texture */
meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
@@ -456,6 +422,23 @@ commit_pending_state (MetaWaylandSurface *surface,
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
wl_list_init (&pending->frame_callback_list);
if (pending->viewport.changed)
meta_surface_actor_set_viewport (surface->surface_actor,
&pending->viewport.src_rect,
pending->viewport.dest_width,
pending->viewport.dest_height);
if (surface == compositor->seat->pointer.cursor_surface)
cursor_surface_commit (surface, pending);
else if (meta_wayland_data_device_is_dnd_surface (&compositor->seat->data_device, surface))
dnd_surface_commit (surface, pending);
else if (surface->window)
toplevel_surface_commit (surface, pending);
else if (surface->wl_subsurface)
subsurface_surface_commit (surface, pending);
g_list_foreach (surface->subsurfaces, parent_surface_committed, NULL);
pending_state_reset (pending);
}
@@ -566,7 +549,8 @@ wl_surface_set_opaque_region (struct wl_client *client,
if (region_resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
surface->pending.opaque_region = cairo_region_copy (region->region);
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
surface->pending.opaque_region = cairo_region_copy (cr_region);
}
}
@@ -585,7 +569,8 @@ wl_surface_set_input_region (struct wl_client *client,
if (region_resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
surface->pending.input_region = cairo_region_copy (region->region);
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
surface->pending.input_region = cairo_region_copy (cr_region);
}
}
@@ -642,7 +627,7 @@ surface_should_be_reactive (MetaWaylandSurface *surface)
return TRUE;
/* If we're a subsurface, we should be reactive */
if (surface->subsurface.resource)
if (surface->wl_subsurface)
return TRUE;
return FALSE;
@@ -722,33 +707,6 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
return surface;
}
static void
destroy_surface_extension (MetaWaylandSurfaceExtension *extension)
{
extension->resource = NULL;
}
static gboolean
create_surface_extension (MetaWaylandSurfaceExtension *extension,
const struct wl_interface *interface,
const void *implementation,
wl_resource_destroy_func_t destructor,
MetaWaylandSurface *surface,
struct wl_resource *master_resource,
guint32 id)
{
struct wl_client *client;
if (extension->resource != NULL)
return FALSE;
client = wl_resource_get_client (surface->resource);
extension->resource = wl_resource_create (client, interface, wl_resource_get_version (master_resource), id);
wl_resource_set_implementation (extension->resource, implementation, surface, destructor);
return TRUE;
}
static void
xdg_shell_use_unstable_version (struct wl_client *client,
struct wl_resource *resource,
@@ -775,7 +733,7 @@ xdg_surface_destructor (struct wl_resource *resource)
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
destroy_window (surface);
destroy_surface_extension (&surface->xdg_surface);
surface->xdg_surface = NULL;
}
static void
@@ -1013,11 +971,7 @@ xdg_shell_get_xdg_surface (struct wl_client *client,
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWindow *window;
if (!create_surface_extension (&surface->xdg_surface,
&xdg_surface_interface,
&meta_wayland_xdg_surface_interface,
xdg_surface_destructor,
surface, resource, id))
if (surface->xdg_surface != NULL)
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1025,6 +979,9 @@ xdg_shell_get_xdg_surface (struct wl_client *client,
return;
}
surface->xdg_surface = wl_resource_create (client, &xdg_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->xdg_surface, &meta_wayland_xdg_surface_interface, surface, xdg_surface_destructor);
surface->xdg_shell_resource = resource;
window = meta_window_wayland_new (meta_get_display (), surface);
@@ -1037,7 +994,7 @@ xdg_popup_destructor (struct wl_resource *resource)
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
destroy_window (surface);
destroy_surface_extension (&surface->xdg_popup);
surface->xdg_popup = NULL;
}
static void
@@ -1067,15 +1024,12 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWindow *window;
MetaDisplay *display = meta_get_display ();
if (parent_surf == NULL || parent_surf->window == NULL)
return;
if (!create_surface_extension (&surface->xdg_popup,
&xdg_popup_interface,
&meta_wayland_xdg_popup_interface,
xdg_popup_destructor,
surface, resource, id))
if (surface->xdg_popup != NULL)
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1083,9 +1037,12 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
return;
}
surface->xdg_popup = wl_resource_create (client, &xdg_popup_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->xdg_popup, &meta_wayland_xdg_popup_interface, surface, xdg_popup_destructor);
surface->xdg_shell_resource = resource;
window = meta_window_wayland_new (meta_get_display (), surface);
window = meta_window_wayland_new (display, surface);
meta_window_move_frame (window, FALSE,
parent_surf->window->rect.x + x,
parent_surf->window->rect.y + y);
@@ -1096,6 +1053,7 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
meta_wayland_surface_set_window (surface, window);
meta_window_focus (window, meta_display_get_current_time (display));
meta_wayland_pointer_start_popup_grab (&seat->pointer, surface);
}
@@ -1129,7 +1087,7 @@ wl_shell_surface_destructor (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
destroy_surface_extension (&surface->wl_shell_surface);
surface->wl_shell_surface = NULL;
}
static void
@@ -1337,11 +1295,7 @@ wl_shell_get_shell_surface (struct wl_client *client,
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWindow *window;
if (!create_surface_extension (&surface->wl_shell_surface,
&wl_shell_surface_interface,
&meta_wayland_wl_shell_surface_interface,
wl_shell_surface_destructor,
surface, resource, id))
if (surface->wl_shell_surface != NULL)
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1349,6 +1303,9 @@ wl_shell_get_shell_surface (struct wl_client *client,
return;
}
surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor);
window = meta_window_wayland_new (meta_get_display (), surface);
meta_wayland_surface_set_window (surface, window);
}
@@ -1374,7 +1331,7 @@ gtk_surface_destructor (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
destroy_surface_extension (&surface->gtk_surface);
surface->gtk_surface = NULL;
}
static void
@@ -1417,17 +1374,16 @@ get_gtk_surface (struct wl_client *client,
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
if (!create_surface_extension (&surface->gtk_surface,
&gtk_surface_interface,
&meta_wayland_gtk_surface_interface,
gtk_surface_destructor,
surface, resource, id))
if (surface->gtk_surface != NULL)
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"gtk_shell::get_gtk_surface already requested");
return;
}
surface->gtk_surface = wl_resource_create (client, &gtk_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->gtk_surface, &meta_wayland_gtk_surface_interface, surface, gtk_surface_destructor);
}
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = {
@@ -1441,12 +1397,15 @@ bind_gtk_shell (struct wl_client *client,
guint32 id)
{
struct wl_resource *resource;
uint32_t capabilities = 0;
resource = wl_resource_create (client, &gtk_shell_interface, version, id);
wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL);
/* FIXME: ask the plugin */
gtk_shell_send_capabilities (resource, GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU);
if (!meta_prefs_get_show_fallback_app_menu ())
capabilities = GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU;
gtk_shell_send_capabilities (resource, capabilities);
}
static void
@@ -1525,7 +1484,7 @@ wl_subsurface_destructor (struct wl_resource *resource)
}
pending_state_destroy (&surface->sub.pending);
destroy_surface_extension (&surface->subsurface);
surface->wl_subsurface = NULL;
}
static void
@@ -1651,7 +1610,7 @@ wl_subsurface_set_desync (struct wl_client *client,
surface->sub.synchronous = FALSE;
}
static const struct wl_subsurface_interface meta_wayland_subsurface_interface = {
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
wl_subsurface_destroy,
wl_subsurface_set_position,
wl_subsurface_place_above,
@@ -1689,11 +1648,7 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
if (!create_surface_extension (&surface->subsurface,
&wl_subsurface_interface,
&meta_wayland_subsurface_interface,
wl_subsurface_destructor,
surface, resource, id))
if (surface->wl_subsurface != NULL)
{
wl_resource_post_error (surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1701,6 +1656,9 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
return;
}
surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, wl_subsurface_destructor);
pending_state_init (&surface->sub.pending);
surface->sub.synchronous = TRUE;
surface->sub.parent = parent;
@@ -1731,6 +1689,136 @@ bind_subcompositor (struct wl_client *client,
wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface, data, NULL);
}
static void
destroy_wl_viewport (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->has_viewport = FALSE;
surface->pending.viewport.changed = TRUE;
}
static void
wl_viewport_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
viewport_set_src (struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.viewport.src_rect.x = wl_fixed_to_int (src_x);
surface->pending.viewport.src_rect.y = wl_fixed_to_int (src_y);
surface->pending.viewport.src_rect.width = wl_fixed_to_int (src_width);
surface->pending.viewport.src_rect.height = wl_fixed_to_int (src_height);
surface->pending.viewport.changed = TRUE;
}
static void
viewport_set_dest (struct wl_resource *resource,
int dst_width,
int dst_height)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.viewport.dest_width = dst_width;
surface->pending.viewport.dest_height = dst_height;
surface->pending.viewport.changed = TRUE;
}
static void
wl_viewport_set (struct wl_client *client,
struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height,
int dst_width,
int dst_height)
{
viewport_set_src (resource, src_x, src_y, src_width, src_height);
viewport_set_dest (resource, dst_width, dst_height);
}
static void
wl_viewport_set_source (struct wl_client *client,
struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height)
{
viewport_set_src (resource, src_x, src_y, src_width, src_height);
}
static void
wl_viewport_set_destination (struct wl_client *client,
struct wl_resource *resource,
int dst_width,
int dst_height)
{
viewport_set_dest (resource, dst_width, dst_height);
}
static const struct wl_viewport_interface meta_wayland_viewport_interface = {
wl_viewport_destroy,
wl_viewport_set,
wl_viewport_set_source,
wl_viewport_set_destination,
};
static void
wl_scaler_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
wl_scaler_get_viewport (struct wl_client *client,
struct wl_resource *master_resource,
uint32_t viewport_id,
struct wl_resource *surface_resource)
{
struct wl_resource *resource;
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
if (surface->has_viewport)
{
wl_resource_post_error (master_resource,
WL_SCALER_ERROR_VIEWPORT_EXISTS,
"viewport already exists on surface");
return;
}
resource = wl_resource_create (client, &wl_viewport_interface, wl_resource_get_version (master_resource), viewport_id);
wl_resource_set_implementation (resource, &meta_wayland_viewport_interface, surface, destroy_wl_viewport);
surface->has_viewport = TRUE;
}
static const struct wl_scaler_interface meta_wayland_scaler_interface = {
wl_scaler_destroy,
wl_scaler_get_viewport,
};
static void
bind_scaler (struct wl_client *client,
void *data,
guint32 version,
guint32 id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &wl_scaler_interface, version, id);
wl_resource_set_implementation (resource, &meta_wayland_scaler_interface, data, NULL);
}
void
meta_wayland_shell_init (MetaWaylandCompositor *compositor)
{
@@ -1757,6 +1845,12 @@ meta_wayland_shell_init (MetaWaylandCompositor *compositor)
META_WL_SUBCOMPOSITOR_VERSION,
compositor, bind_subcompositor) == NULL)
g_error ("Failed to register a global wl-subcompositor object");
if (wl_global_create (compositor->wayland_display,
&wl_scaler_interface,
META_WL_SCALER_VERSION,
compositor, bind_scaler) == NULL)
g_error ("Failed to register a global wl-subcompositor object");
}
static void
@@ -1792,9 +1886,9 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int new_height,
MetaWaylandSerial *sent_serial)
{
if (surface->xdg_surface.resource)
if (surface->xdg_surface)
{
struct wl_client *client = wl_resource_get_client (surface->xdg_surface.resource);
struct wl_client *client = wl_resource_get_client (surface->xdg_surface);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
struct wl_array states;
@@ -1808,7 +1902,7 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
new_width /= surface->scale;
new_height /= surface->scale;
xdg_surface_send_configure (surface->xdg_surface.resource, new_width, new_height, &states, serial);
xdg_surface_send_configure (surface->xdg_surface, new_width, new_height, &states, serial);
wl_array_release (&states);
@@ -1818,13 +1912,13 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
sent_serial->value = serial;
}
}
else if (surface->xdg_popup.resource)
else if (surface->xdg_popup)
{
/* This can happen if the popup window loses or receives focus.
* Just ignore it. */
}
else if (surface->wl_shell_surface.resource)
wl_shell_surface_send_configure (surface->wl_shell_surface.resource,
else if (surface->wl_shell_surface)
wl_shell_surface_send_configure (surface->wl_shell_surface,
0, new_width, new_height);
else
g_assert_not_reached ();
@@ -1836,15 +1930,15 @@ meta_wayland_surface_ping (MetaWaylandSurface *surface,
{
if (surface->xdg_shell_resource)
xdg_shell_send_ping (surface->xdg_shell_resource, serial);
else if (surface->wl_shell_surface.resource)
wl_shell_surface_send_ping (surface->wl_shell_surface.resource, serial);
else if (surface->wl_shell_surface)
wl_shell_surface_send_ping (surface->wl_shell_surface, serial);
}
void
meta_wayland_surface_delete (MetaWaylandSurface *surface)
{
if (surface->xdg_surface.resource)
xdg_surface_send_close (surface->xdg_surface.resource);
if (surface->xdg_surface)
xdg_surface_send_close (surface->xdg_surface);
}
void
@@ -1854,8 +1948,8 @@ meta_wayland_surface_popup_done (MetaWaylandSurface *surface)
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
if (surface->xdg_popup.resource)
xdg_popup_send_popup_done (surface->xdg_popup.resource, serial);
else if (surface->wl_shell_surface.resource)
wl_shell_surface_send_popup_done (surface->wl_shell_surface.resource);
if (surface->xdg_popup)
xdg_popup_send_popup_done (surface->xdg_popup, serial);
else if (surface->wl_shell_surface)
wl_shell_surface_send_popup_done (surface->wl_shell_surface);
}

View File

@@ -36,16 +36,6 @@ struct _MetaWaylandSerial {
uint32_t value;
};
struct _MetaWaylandBuffer
{
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
CoglTexture *texture;
uint32_t ref_count;
};
typedef struct
{
/* wl_surface.attach */
@@ -68,32 +58,44 @@ typedef struct
MetaRectangle new_geometry;
gboolean has_new_geometry;
} MetaWaylandPendingState;
typedef struct
{
struct wl_resource *resource;
} MetaWaylandSurfaceExtension;
struct {
gboolean changed;
cairo_rectangle_int_t src_rect;
int32_t dest_width, dest_height;
} viewport;
} MetaWaylandPendingState;
struct _MetaWaylandSurface
{
/* Generic stuff */
struct wl_resource *resource;
MetaWaylandCompositor *compositor;
MetaSurfaceActor *surface_actor;
MetaWindow *window;
struct wl_resource *xdg_shell_resource;
MetaWaylandSurfaceExtension xdg_surface;
MetaWaylandSurfaceExtension xdg_popup;
MetaWaylandSurfaceExtension wl_shell_surface;
MetaWaylandSurfaceExtension gtk_surface;
MetaWaylandSurfaceExtension subsurface;
int scale;
MetaWaylandBuffer *buffer;
struct wl_listener buffer_destroy_listener;
int scale;
int32_t offset_x, offset_y;
GList *subsurfaces;
gboolean has_viewport;
/* All the pending state that wl_surface.commit will apply. */
MetaWaylandPendingState pending;
/* Extension resources. */
struct wl_resource *xdg_surface;
struct wl_resource *xdg_popup;
struct wl_resource *wl_shell_surface;
struct wl_resource *gtk_surface;
struct wl_resource *wl_subsurface;
/* xdg_surface stuff */
struct wl_resource *xdg_shell_resource;
MetaWaylandSerial acked_configure_serial;
gboolean has_set_geometry;
/* wl_subsurface stuff. */
struct {
MetaWaylandSurface *parent;
struct wl_listener parent_destroy_listener;
@@ -114,13 +116,6 @@ struct _MetaWaylandSurface
gboolean pending_pos;
GSList *pending_placement_ops;
} sub;
gboolean has_set_geometry;
/* All the pending state that wl_surface.commit will apply. */
MetaWaylandPendingState pending;
MetaWaylandSerial acked_configure_serial;
};
void meta_wayland_shell_init (MetaWaylandCompositor *compositor);

View File

@@ -32,7 +32,7 @@ typedef struct _MetaWaylandDataSource MetaWaylandDataSource;
typedef struct _MetaWaylandDataDevice MetaWaylandDataDevice;
typedef struct _MetaWaylandBuffer MetaWaylandBuffer;
typedef struct _MetaWaylandBufferReference MetaWaylandBufferReference;
typedef struct _MetaWaylandRegion MetaWaylandRegion;
typedef struct _MetaWaylandSurface MetaWaylandSurface;

View File

@@ -44,5 +44,6 @@
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 1
#define META_WL_SUBCOMPOSITOR_VERSION 1
#define META_WL_SCALER_VERSION 2
#endif

View File

@@ -19,40 +19,26 @@
* 02111-1307, USA.
*/
#include <config.h>
#include "config.h"
#include "meta-wayland.h"
#include <clutter/clutter.h>
#include <clutter/wayland/clutter-wayland-compositor.h>
#include <clutter/wayland/clutter-wayland-surface.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayland-server.h>
#include <meta/meta-backend.h>
#include "meta-wayland-private.h"
#include "meta-xwayland-private.h"
#include "meta-window-actor-private.h"
#include "meta-wayland-region.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-keyboard.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-outputs.h"
#include "meta-wayland-data-device.h"
#include "meta-cursor-tracker-private.h"
#include "display-private.h"
#include "window-private.h"
#include <meta/types.h>
#include <meta/main.h>
#include "frame.h"
static MetaWaylandCompositor _meta_wayland_compositor;
@@ -70,6 +56,13 @@ get_time (void)
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
typedef struct
{
GSource source;
GPollFD pfd;
struct wl_display *display;
} WaylandEventSource;
static gboolean
wayland_event_source_prepare (GSource *base, int *timeout)
{
@@ -126,61 +119,6 @@ wayland_event_source_new (struct wl_display *display)
return &source->source;
}
static void
meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
void *data)
{
MetaWaylandBuffer *buffer =
wl_container_of (listener, buffer, destroy_listener);
wl_signal_emit (&buffer->destroy_signal, buffer);
g_slice_free (MetaWaylandBuffer, buffer);
}
void
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
{
buffer->ref_count++;
}
void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_clear_pointer (&buffer->texture, cogl_object_unref);
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
}
MetaWaylandBuffer *
meta_wayland_buffer_from_resource (struct wl_resource *resource)
{
MetaWaylandBuffer *buffer;
struct wl_listener *listener;
listener =
wl_resource_get_destroy_listener (resource,
meta_wayland_buffer_destroy_handler);
if (listener)
{
buffer = wl_container_of (listener, buffer, destroy_listener);
}
else
{
buffer = g_slice_new0 (MetaWaylandBuffer);
buffer->resource = resource;
wl_signal_init (&buffer->destroy_signal);
buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler;
wl_resource_add_destroy_listener (resource, &buffer->destroy_listener);
}
return buffer;
}
void
meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window)
@@ -202,91 +140,23 @@ wl_compositor_create_surface (struct wl_client *client,
guint32 id)
{
MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
meta_wayland_surface_create (compositor, client, resource, id);
}
static void
wl_region_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
wl_region_add (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_union_rectangle (region->region, &rectangle);
}
static void
wl_region_subtract (struct wl_client *client,
struct wl_resource *resource,
gint32 x,
gint32 y,
gint32 width,
gint32 height)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_rectangle_int_t rectangle = { x, y, width, height };
cairo_region_subtract_rectangle (region->region, &rectangle);
}
static const struct wl_region_interface meta_wayland_region_interface = {
wl_region_destroy,
wl_region_add,
wl_region_subtract
};
static void
meta_wayland_region_resource_destroy_cb (struct wl_resource *resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
cairo_region_destroy (region->region);
g_slice_free (MetaWaylandRegion, region);
}
static void
wl_compositor_create_region (struct wl_client *client,
struct wl_resource *compositor_resource,
struct wl_resource *resource,
uint32_t id)
{
MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion);
region->resource = wl_resource_create (client, &wl_region_interface, wl_resource_get_version (compositor_resource), id);
wl_resource_set_implementation (region->resource, &meta_wayland_region_interface, region, meta_wayland_region_resource_destroy_cb);
region->region = cairo_region_create ();
MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
meta_wayland_region_create (compositor, client, resource, id);
}
const static struct wl_compositor_interface meta_wayland_compositor_interface = {
const static struct wl_compositor_interface meta_wayland_wl_compositor_interface = {
wl_compositor_create_surface,
wl_compositor_create_region
};
void
meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
{
while (!wl_list_empty (&compositor->frame_callbacks))
{
MetaWaylandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_callback_send_done (callback->resource, get_time ());
wl_resource_destroy (callback->resource);
}
}
static void
compositor_bind (struct wl_client *client,
void *data,
@@ -297,7 +167,7 @@ compositor_bind (struct wl_client *client,
struct wl_resource *resource;
resource = wl_resource_create (client, &wl_compositor_interface, version, id);
wl_resource_set_implementation (resource, &meta_wayland_compositor_interface, compositor, NULL);
wl_resource_set_implementation (resource, &meta_wayland_wl_compositor_interface, compositor, NULL);
}
/**
@@ -316,6 +186,19 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
meta_wayland_seat_update (compositor->seat, event);
}
void
meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
{
while (!wl_list_empty (&compositor->frame_callbacks))
{
MetaWaylandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_callback_send_done (callback->resource, get_time ());
wl_resource_destroy (callback->resource);
}
}
/**
* meta_wayland_compositor_handle_event:
* @compositor: the #MetaWaylandCompositor instance
@@ -385,7 +268,6 @@ meta_wayland_pre_clutter_init (void)
meta_wayland_compositor_init (compositor);
/* Set up our logging. */
wl_log_set_handler_server (meta_wayland_log_func);
compositor->wayland_display = wl_display_create ();
@@ -401,12 +283,6 @@ meta_wayland_init (void)
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
GSource *wayland_event_source;
if (!wl_global_create (compositor->wayland_display,
&wl_compositor_interface,
META_WL_COMPOSITOR_VERSION,
compositor, compositor_bind))
g_error ("Failed to register the global wl_compositor");
wayland_event_source = wayland_event_source_new (compositor->wayland_display);
/* XXX: Here we are setting the wayland event source to have a
@@ -414,13 +290,16 @@ meta_wayland_init (void)
* much more likely to get confused being told about surface changes
* relating to X clients when we don't know what's happened to them
* according to the X protocol.
*
* At some point we could perhaps try and get the X protocol proxied
* over the wayland protocol so that we don't have to worry about
* synchronizing the two command streams. */
*/
g_source_set_priority (wayland_event_source, GDK_PRIORITY_EVENTS + 1);
g_source_attach (wayland_event_source, NULL);
if (!wl_global_create (compositor->wayland_display,
&wl_compositor_interface,
META_WL_COMPOSITOR_VERSION,
compositor, compositor_bind))
g_error ("Failed to register the global wl_compositor");
wl_display_init_shm (compositor->wayland_display);
meta_wayland_outputs_init (compositor);
@@ -428,21 +307,10 @@ meta_wayland_init (void)
meta_wayland_shell_init (compositor);
meta_wayland_seat_init (compositor);
/* FIXME: find the first free name instead */
compositor->display_name = wl_display_add_socket_auto (compositor->wayland_display);
if (compositor->display_name == NULL)
g_error ("Failed to create socket");
/* XXX: It's important that we only try and start xwayland after we
* have initialized EGL because EGL implements the "wl_drm"
* interface which xwayland requires to determine what drm device
* name it should use.
*
* By waiting until we've shown the stage above we ensure that the
* underlying GL resources for the surface have also been allocated
* and so EGL must be initialized by this point.
*/
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
g_error ("Failed to start X Wayland");

View File

@@ -23,6 +23,8 @@
#ifndef META_WAYLAND_H
#define META_WAYLAND_H
#include <clutter/clutter.h>
#include <meta/types.h>
#include "meta-wayland-types.h"
void meta_wayland_pre_clutter_init (void);

View File

@@ -0,0 +1,210 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="scaler">
<copyright>
Copyright © 2013-2014 Collabora, Ltd.
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="wl_scaler" version="2">
<description summary="surface cropping and scaling">
The global interface exposing surface cropping and scaling
capabilities is used to instantiate an interface extension for a
wl_surface object. This extended interface will then allow
cropping and scaling the surface contents, effectively
disconnecting the direct relationship between the buffer and the
surface size.
</description>
<request name="destroy" type="destructor">
<description summary="unbind from the cropping and scaling interface">
Informs the server that the client will not be using this
protocol object anymore. This does not affect any other objects,
wl_viewport objects included.
</description>
</request>
<enum name="error">
<entry name="viewport_exists" value="0"
summary="the surface already has a viewport object associated"/>
</enum>
<request name="get_viewport">
<description summary="extend surface interface for crop and scale">
Instantiate an interface extension for the given wl_surface to
crop and scale its content. If the given wl_surface already has
a wl_viewport object associated, the viewport_exists
protocol error is raised.
</description>
<arg name="id" type="new_id" interface="wl_viewport"
summary="the new viewport interface id"/>
<arg name="surface" type="object" interface="wl_surface"
summary="the surface"/>
</request>
</interface>
<interface name="wl_viewport" version="2">
<description summary="crop and scale interface to a wl_surface">
An additional interface to a wl_surface object, which allows the
client to specify the cropping and scaling of the surface
contents.
This interface allows to define the source rectangle (src_x,
src_y, src_width, src_height) from where to take the wl_buffer
contents, and scale that to destination size (dst_width,
dst_height). This state is double-buffered, and is applied on the
next wl_surface.commit.
The two parts of crop and scale state are independent: the source
rectangle, and the destination size. Initially both are unset, that
is, no scaling is applied. The whole of the current wl_buffer is
used as the source, and the surface size is as defined in
wl_surface.attach.
If the destination size is set, it causes the surface size to become
dst_width, dst_height. The source (rectangle) is scaled to exactly
this size. This overrides whatever the attached wl_buffer size is,
unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
has no content and therefore no size. Otherwise, the size is always
at least 1x1 in surface coordinates.
If the source rectangle is set, it defines what area of the
wl_buffer is taken as the source. If the source rectangle is set and
the destination size is not set, the surface size becomes the source
rectangle size rounded up to the nearest integer. If the source size
is already exactly integers, this results in cropping without scaling.
The coordinate transformations from buffer pixel coordinates up to
the surface-local coordinates happen in the following order:
1. buffer_transform (wl_surface.set_buffer_transform)
2. buffer_scale (wl_surface.set_buffer_scale)
3. crop and scale (wl_viewport.set*)
This means, that the source rectangle coordinates of crop and scale
are given in the coordinates after the buffer transform and scale,
i.e. in the coordinates that would be the surface-local coordinates
if the crop and scale was not applied.
If the source rectangle is partially or completely outside of the
wl_buffer, then the surface contents are undefined (not void), and
the surface size is still dst_width, dst_height.
The x, y arguments of wl_surface.attach are applied as normal to
the surface. They indicate how many pixels to remove from the
surface size from the left and the top. In other words, they are
still in the surface-local coordinate system, just like dst_width
and dst_height are.
If the wl_surface associated with the wl_viewport is destroyed,
the wl_viewport object becomes inert.
If the wl_viewport object is destroyed, the crop and scale
state is removed from the wl_surface. The change will be applied
on the next wl_surface.commit.
</description>
<request name="destroy" type="destructor">
<description summary="remove scaling and cropping from the surface">
The associated wl_surface's crop and scale state is removed.
The change is applied on the next wl_surface.commit.
</description>
</request>
<enum name="error">
<entry name="bad_value" value="0"
summary="negative or zero values in width or height"/>
</enum>
<request name="set">
<description summary="set the crop and scale state">
Set both source rectangle and destination size of the associated
wl_surface. See wl_viewport for the description, and relation to
the wl_buffer size.
The bad_value protocol error is raised if src_width or
src_height is negative, or if dst_width or dst_height is not
positive.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
Arguments dst_x and dst_y do not exist here, use the x and y
arguments to wl_surface.attach. The x, y, dst_width, and dst_height
define the surface-local coordinate system irrespective of the
attached wl_buffer size.
</description>
<arg name="src_x" type="fixed" summary="source rectangle x"/>
<arg name="src_y" type="fixed" summary="source rectangle y"/>
<arg name="src_width" type="fixed" summary="source rectangle width"/>
<arg name="src_height" type="fixed" summary="source rectangle height"/>
<arg name="dst_width" type="int" summary="surface width"/>
<arg name="dst_height" type="int" summary="surface height"/>
</request>
<request name="set_source" since="2">
<description summary="set the source rectangle for cropping">
Set the source rectangle of the associated wl_surface. See
wl_viewport for the description, and relation to the wl_buffer
size.
If width is -1.0 and height is -1.0, the destination size is unset
instead. Any other pair of values for width and height that
contains zero or negative values raises the bad_value protocol
error.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
</description>
<arg name="x" type="fixed" summary="source rectangle x"/>
<arg name="y" type="fixed" summary="source rectangle y"/>
<arg name="width" type="fixed" summary="source rectangle width"/>
<arg name="height" type="fixed" summary="source rectangle height"/>
</request>
<request name="set_destination" since="2">
<description summary="set the surface size for scaling">
Set the destination size of the associated wl_surface. See
wl_viewport for the description, and relation to the wl_buffer
size.
If width is -1 and height is -1, the destination size is unset
instead. Any other pair of values for width and height that
contains zero or negative values raises the bad_value protocol
error.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
Arguments x and y do not exist here, use the x and y arguments to
wl_surface.attach. The x, y, width, and height define the
surface-local coordinate system irrespective of the attached
wl_buffer size.
</description>
<arg name="width" type="int" summary="surface width"/>
<arg name="height" type="int" summary="surface height"/>
</request>
</interface>
</protocol>

View File

@@ -509,8 +509,6 @@ meta_window_x11_manage (MetaWindow *window)
meta_icon_cache_init (&priv->icon_cache);
meta_display_register_x_window (display, &window->xwindow, window);
meta_window_x11_update_shape_region (window);
meta_window_x11_update_input_region (window);
/* assign the window to its group, or create a new group if needed */
window->group = NULL;
@@ -568,6 +566,9 @@ meta_window_x11_manage (MetaWindow *window)
meta_window_client_rect_to_frame_rect (window, &rect, &rect);
meta_window_move_resize_internal (window, flags, gravity, rect);
}
meta_window_x11_update_shape_region (window);
meta_window_x11_update_input_region (window);
}
static void