Compare commits

...

59 Commits

Author SHA1 Message Date
Jasper St. Pierre
c9e225822c xdg-shell: Update for new state change mechanism
We're still not properly going through the request system. This
will require a dense investigation of the code, but it will happen
soon...
2014-02-18 18:57:12 -05:00
Jasper St. Pierre
1689de7015 xdg-shell: Update to latest renames for focused_set / focused_unset 2014-02-18 18:57:12 -05:00
Jasper St. Pierre
47f4c9db7b wayland-surface: Correct xdg_popup placement
Now that we call set_custom_frame_extents, the frame rect corresponds
to the "visible window geometry" used for constrainment, while the
x/y fields in get_xdg_popup instead are relative to the surface.
2014-02-18 18:55:54 -05:00
Jasper St. Pierre
4c621cc30f pointer/keyboard: Make sure to clean up the destroy listeners when releasing 2014-02-18 18:39:19 -05:00
Jasper St. Pierre
756a412436 pointer: Make nested grabs work
Something noticed on code inspection. If we have a popup grab,
it will always return FALSE. The code here clearly meant to continue
if we had an existing popup grab from an existing client.
2014-02-18 18:06:55 -05:00
Jasper St. Pierre
be16c2fe71 pointer: Reindent 2014-02-18 18:06:17 -05:00
Jasper St. Pierre
a364c2a96b pointer/keyboard: Make sure not to get stale on client resources as well
Both the pointer/keyboard resource and surface resource can be destroyed
at any point in the destruction process, so we need to have destroy
listeners on both. To make the code easier to follow, rename ->focus
to ->focus_surface at the same time, and rearrange the code so that
the two of them are always grouped together.
2014-02-18 18:03:31 -05:00
Jasper St. Pierre
414259a7f8 wayland: Fix cast warning
It's sometimes hard to see around all the deprecation warnings. Sorry
about that...
2014-02-18 17:26:03 -05:00
Jasper St. Pierre
283a81eac0 wayland: Explicitly destroy the surface actor
This shouldn't change anything right now, but it's better to be
careful than anything else. This is where the actor should be
destroyed.
2014-02-18 17:07:36 -05:00
Jasper St. Pierre
2a145262c7 wayland: Rework how surface destruction works
To prevent the MetaSurfaceActor from being destroyed, we normally
unparent it before we unmanage the window. However, this doesn't
work for XWayland windows, which we unmanage when we get UnmapNotify
or DestroyNotify, not when we get the wl_surface_destroy.

To solve this, add an early hook in meta_window_unmanage that
unparents the surface actor if we have one. At the same time, clean
up the destruction code to remove old comments and assumptions about
how wl_shell behaves.
2014-02-18 17:01:33 -05:00
Jasper St. Pierre
57728b4322 Kill HAVE_WAYLAND 2014-02-17 21:50:32 -05:00
Jasper St. Pierre
ef24fb6296 wayland: Don't use WESTON_LAUNCHER_SOCK
We can simply check the windowing backend.
2014-02-17 21:50:32 -05:00
Jasper St. Pierre
86f057a712 monitor: Add a Wayland backend
We shouldn't crash when trying to run nested under Wayland. Just
use the dummy backend for now until we are able to run with a
system compositor.
2014-02-17 21:50:32 -05:00
Jasper St. Pierre
dcd628d289 wayland: Kill meta_wayland_compositor_is_native
It's unused. Squash the remaining functionality, setting the DRM FD,
into the main path.
2014-02-17 21:15:31 -05:00
Jasper St. Pierre
6038877c4c cursor-tracker: Kill off the last user of is_native 2014-02-17 21:11:57 -05:00
Jasper St. Pierre
4e6321c239 monitor: Kill off another use of is_native 2014-02-17 20:51:35 -05:00
Jasper St. Pierre
304a525744 wayland: Remove is_native from seat
We can easily do this with a Clutter backend check instead...
2014-02-17 20:49:04 -05:00
Jasper St. Pierre
f26de405dd main: Remove clutter / cogl option groups
Neither of these groups are too useful, and all the switches useful
for debugging can also be controlled by envvars.
2014-02-17 20:41:36 -05:00
Jasper St. Pierre
ed18580118 default: Improve the destroy effect as well 2014-02-17 19:27:33 -05:00
Jasper St. Pierre
b65649186d pointer/keyboard: Put the destroy listener on the right resource
We care about when the surface is destroyed, not when the wl_pointer
slash wl_keyboard resource is destroyed.
2014-02-17 19:22:30 -05:00
Jasper St. Pierre
515dc08a97 pointer/keyboard: Do a series of renames to our listener as well 2014-02-17 19:22:30 -05:00
Jasper St. Pierre
2e7a56a28f wayland: Rename resource_destroy_cb to wl_surface_destructor
So it doesn't seem like a wl_listener callback.
2014-02-17 19:22:30 -05:00
Jasper St. Pierre
c485637a61 default: Don't use anchor points
It doesn't work now that we set the pivot point. This breaks the
maximize effect, but it fixes the destroy effect. The maximize effect
looks bad anyway, so it's not too important to me.
2014-02-17 17:57:45 -05:00
Jasper St. Pierre
f9f2a82e18 xwayland: Don't -retro
This means we see black instead of checkerboard for now when resizing,
but that's better.
2014-02-17 17:57:40 -05:00
Jasper St. Pierre
2f4563132a default: Use a consistent rand() for monitor backgrounds
g_random_int() is seeded with /dev/urandom, so it's not consistent.
2014-02-17 14:02:13 -05:00
Jasper St. Pierre
e3a0f2c546 default: Don't wait to show the stage
We can show it immediately now...
2014-02-17 13:57:35 -05:00
Jasper St. Pierre
d39baeb8ad wayland-surface: Destroy the right thing
data is the wl_client, which we don't want to destroy. Destroy
our XdgShell pointer instead.
2014-02-17 12:53:56 -05:00
Jasper St. Pierre
f27f6aab78 Update to new xdg-shell pinging standards 2014-02-16 10:21:22 -05:00
Jasper St. Pierre
a66060e21a Revert "Move window pings to MetaWindow"
This was a bad idea, as ping/pong has moved to a client-specific
request/event pair, rather than a surface-specific one. Revert
the changes we made here and correct the code to make up for it.

This reverts commit aa3643cdde.
2014-02-16 10:21:22 -05:00
Jasper St. Pierre
11aa3c030b wayland-surface: Don't require we manually bump the version for xdg-shell
It's in the protocol as an enum.
2014-02-16 10:21:22 -05:00
Jasper St. Pierre
bd1bec5617 wayland-surface: Prefix xdg-shell methods with "xdg_shell_" 2014-02-16 10:21:22 -05:00
Adel Gadllah
d9659d4b36 wayland-surface: Don't crash when someone tries to run a native app using old gtk
This ends up calling set_dbus_properties with a NULL
window, instead of segfaulting the compositor return so that the broken
app dies instead.

https://bugzilla.gnome.org/show_bug.cgi?id=724472
2014-02-16 16:19:23 +01:00
Ryan Lortie
d043d9943b idle-monitor: avoid XSyncBadAlarm X error
If we fail to find the IDLETIME counter, then the alarm variable will be
uninitialised.  Most code paths are careful to check this before
submitting XSync calls, but there is one check missing.

https://bugzilla.gnome.org/show_bug.cgi?id=724364
2014-02-15 13:14:01 +01:00
Jasper St. Pierre
a0ef7c7142 Move position-changed / size-changed signals to the MetaWindow
They fit more appropriately over here...

https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-14 23:44:39 -05:00
Jasper St. Pierre
4efe4483fb compositor: Delay meta_compositor_add_window until the first show
In order for the compositor to properly determine whether a client
is an X11 client or not, we need to wait until XWayland calls
set_window_id to mark the surface as an XWayland client. To prevent
the compositor from getting tripped up over this, make sure that
the window has been fully initialized by the time we call
meta_compositor_add_window.

https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-14 23:44:38 -05:00
Jasper St. Pierre
aec3edb1cc Always map the client and frame windows
Traditionally, WMs unmap windows when minimizing them, and map them
when restoring them or wanting to show them for other reasons, like
upon creation.

However, as metacity morphed into mutter, we optionally chose to keep
windows mapped for the lifetime of the window under the user option
"live-window-previews", which makes the code keep windows mapped so it
can show window preview for minimized windows in other places, like
Alt-Tab and Expose.

I removed this preference two years ago mechanically, by removing all
the if statements, but never went through and cleaned up the code so
that windows are simply mapped for the lifetime of the window -- the
"architecture" of the old code that maps and unmaps on show/hide was
still there.

Remove this now.

The one case we still need to be careful of is shaded windows, in which
we do still unmap the client window. In the future, we might want to
show previews of shaded windows in the overview and Alt-Tab. In that
we'd also keep shaded windows mapped, and could remove all unmap logic,
but we'd need a more complex method of showing the shaded titlebar, such
as using a different actor.

At the same time, simplify the compositor interface by removing
meta_compositor_window_[un]mapped API, and instead adding/removing the
window on-demand.

https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-14 23:19:41 -05:00
Giovanni Campagna
0c5a6ad775 window: don't set _NET_WM_FULLSCREEN_MONITORS to bogus values
Prior to the DisplayConfig merge, we would set _NET_WM_FULLSCREEN_MONITORS
to (unsigned)-1 when unset. After that, we would have invalid
reads inside meta_screen_monitor_index_to_xinerama_index() (called
with -1).
The way I read the specification, the proper way to indicate
that the window is back to fullscreen on all monitors is to
remove the property, so do that.

Also, add an assertion that meta_screne_monitor_index_to_xinerama_index()
is doing the right thing.

https://bugzilla.gnome.org/show_bug.cgi?id=724258
2014-02-13 13:16:51 +01:00
Giovanni Campagna
2be5401b1e window: fix invalid read in computing the input shape
If we are reported only one rectangle in the input shape, we should
not try to read more.

https://bugzilla.gnome.org/show_bug.cgi?id=724257
2014-02-13 13:13:35 +01:00
Jasper St. Pierre
f16e9b2ee7 wayland-surface: Make set_margin double-buffered as well 2014-02-10 14:16:06 -05:00
Jasper St. Pierre
06380938d4 wayland-surface: Make set_fullscreen / set_maximized and friends double-buffered 2014-02-09 18:23:39 -05:00
Ryan Lortie
87b20d7f2a autogen.sh: use #!/bin/sh instead of #!/bin/bash
We don't have any bashisms in this file, so we may as well use sh.

https://bugzilla.gnome.org/show_bug.cgi?id=722530
2014-02-09 11:54:51 -05:00
Jasper St. Pierre
593db0baee default: Make the map animation more friendly 2014-02-09 11:53:15 -05:00
Jasper St. Pierre
6b66553493 display: Remove unused variable 2014-02-09 11:53:15 -05:00
Adel Gadllah
ddaae9c923 Fix build
I broke it while cherry picking the last commit.
2014-02-09 16:39:04 +01:00
Adel Gadllah
0c7a7d7527 Disable clutter's high dpi scaling
mutter needs some work to work with high dpi scaling so disable
the scaling until that is fixed.

https://bugzilla.gnome.org/show_bug.cgi?id=723931
2014-02-09 16:25:37 +01:00
Jasper St. Pierre
6561b53346 display: Clean up screen management code 2014-02-07 19:52:34 -05:00
Jasper St. Pierre
def5e86673 wayland: Add support for the set_margin request 2014-02-07 19:28:36 -05:00
Jasper St. Pierre
0c213c8fee wayland: Add support for the delete event 2014-02-07 19:28:36 -05:00
Jasper St. Pierre
912a0abd26 wayland: Remove edges
This is an upstream change to xdg-shell.
2014-02-07 19:28:36 -05:00
Jasper St. Pierre
d694260ad2 xwayland: Fix xwayland
Don't give us a freed pointer here.
2014-02-07 19:28:05 -05:00
Jasper St. Pierre
8566566451 xwayland: Split out the XWayland stuff into its own private struct 2014-02-07 16:21:27 -05:00
Jasper St. Pierre
0ce64e46e8 build: Don't build client-protocols for things
We don't use these.
2014-02-07 16:21:27 -05:00
Rico Tzschichholz
a8336669a3 shaped-texture: Fix unused variable warning
(cherry picked from commit 101a13c86d)
2014-02-05 22:51:46 +01:00
Jasper St. Pierre
f6db756326 shaped-texture: Move unobscured_region processing here
We want to remove a bunch of auxilliary duties from the MetaWindowActor
and MetaSurfaceActor, including some details of how culling is done.
Move the unobscured region culling code to the MetaShapedTexture, which
helps the actor become "more independent".

https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-05 14:42:38 -05:00
Jasper St. Pierre
27ab516f41 cullable: Reset the culling state instead of skipping the traversal
When we traversed down to reset the culling state, previously we
would just skip any actors that wanted culling. In order to properly
reset the unobscured_region before painting, we need to traverse down
to these places as well. Do this by calling cull_out with NULL regions
for both arguments, and adapt existing cull_out implementations to
match.

https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-05 14:24:08 -05:00
Jasper St. Pierre
9542b464bf window-actor: Clean up whitespace 2014-02-05 14:14:41 -05:00
Jasper St. Pierre
1ebaaa1950 shaped-texture: Clean up code flow a bit
This is easier for me to read.
2014-02-05 14:10:50 -05:00
Jasper St. Pierre
71efbf0330 shaped-texture: Constify clip
This matches upstream
2014-02-05 14:10:49 -05:00
Jasper St. Pierre
a6539463be shaped-texture: Remove get_clip
It seems that this code is trying to transform from "surface coordinates"
(the size of texture that's being displayed) to "actor coordinates"
(the actor's allocation), but I can't find any place where the two are
different. As such, let's just go back to using "surface coordinates"
everywhere and see what breaks.
2014-02-05 14:05:18 -05:00
48 changed files with 1354 additions and 1436 deletions

3
.gitignore vendored
View File

@@ -79,13 +79,10 @@ src/meta-dbus-xrandr.[ch]
src/meta-dbus-idle-monitor.[ch]
src/mutter-plugins.pc
src/wayland/gtk-shell-protocol.c
src/wayland/gtk-shell-client-protocol.h
src/wayland/gtk-shell-server-protocol.h
src/wayland/xdg-shell-protocol.c
src/wayland/xdg-shell-client-protocol.h
src/wayland/xdg-shell-server-protocol.h
src/wayland/xserver-protocol.c
src/wayland/xserver-client-protocol.h
src/wayland/xserver-server-protocol.h
doc/reference/*.args
doc/reference/*.bak

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`

View File

@@ -212,9 +212,6 @@ fi
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
# We always build with wayland enabled
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))

View File

@@ -96,8 +96,6 @@ meta_compositor_hide_window
meta_compositor_switch_workspace
meta_compositor_maximize_window
meta_compositor_unmaximize_window
meta_compositor_window_mapped
meta_compositor_window_unmapped
meta_compositor_sync_window_geometry
meta_compositor_set_updates_frozen
meta_compositor_queue_frame_drawn

View File

@@ -43,7 +43,7 @@
Use this enum to check the protocol version, and it will be updated
automatically.
</description>
<entry name="current" value="1" summary="Always the latest version"/>
<entry name="current" value="2" summary="Always the latest version"/>
</enum>
@@ -84,6 +84,28 @@
<arg name="y" type="int"/>
<arg name="flags" type="uint"/>
</request>
<event name="ping">
<description summary="check if the client is alive">
The ping event asks the client if it's still alive. Pass the
serial specified in the event back to the compositor by sending
a "pong" request back with the specified serial.
Compositors can use this to determine if the client is still
alive. It's unspecified what will happen if the client doesn't
respond to the ping request, or in what timeframe. Clients should
try to respond in a reasonable amount of time.
</description>
<arg name="serial" type="uint" summary="pass this to the callback"/>
</event>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
</interface>
<interface name="xdg_surface" version="1">
@@ -124,6 +146,32 @@
<arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
</request>
<request name="set_margin">
<description summary="set the visible frame boundaries">
This tells the compositor what the visible size of the window
should be, so it can use it to determine what borders to use for
constrainment and alignment.
CSD often has invisible areas for decoration purposes, like drop
shadows. These "shadow" drawings need to be subtracted out of the
normal boundaries of the window when computing where to place
windows (e.g. to set this window so it's centered on top of another,
or to put it to the left or right of the screen.)
This value should change as little as possible at runtime, to
prevent flicker.
This value is also ignored when the window is maximized or
fullscreen, and assumed to be 0.
If never called, this value is assumed to be 0.
</description>
<arg name="left_margin" type="int"/>
<arg name="right_margin" type="int"/>
<arg name="top_margin" type="int"/>
<arg name="bottom_margin" type="int"/>
</request>
<request name="set_title">
<description summary="set surface title">
Set a short title for the surface.
@@ -150,22 +198,6 @@
<arg name="app_id" type="string"/>
</request>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
<event name="ping">
<description summary="ping client">
Ping a client to check if it is receiving events and sending
requests. A client is expected to reply with a pong request.
</description>
<arg name="serial" type="uint"/>
</event>
<request name="move">
<description summary="start an interactive move">
Start a pointer-driven move of the surface.
@@ -217,12 +249,6 @@
ignore it if it doesn't resize, pick a smaller size (to
satisfy aspect ratio or resize in steps of NxM pixels).
The edges parameter provides a hint about how the surface
was resized. The client may use this information to decide
how to adjust its content to the new size (e.g. a scrolling
area might adjust its content position to leave the viewable
content unmoved). Valid edge values are from resize_edge enum.
The client is free to dismiss all but the last configure
event it received.
@@ -230,7 +256,6 @@
in surface local coordinates.
</description>
<arg name="edges" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</event>
@@ -250,128 +275,122 @@
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<event name="request_set_fullscreen">
<description summary="server requests that the client set fullscreen">
Event sent from the compositor to the client requesting that the client
goes to a fullscreen state. It's the client job to call set_fullscreen
and really trigger the fullscreen state.
<enum name="state_type">
<description summary="types of state on the surface">
The different state values used on the surface. This is designed for
state values like maximized, fullscreen. It is paired with the
request_change_state event to ensure that both the client and the
compositor setting the state can be synchronized.
States set in this way are double-buffered. They will get applied on
the next commit.
Desktop environments may extend this enum by taking up a range of
values and documenting the range they chose in this description.
They are not required to document the values for the range that they
chose. Ideally, any good extensions from a desktop environment should
make its way into standardization into this enum.
The current reserved ranges are:
0x0000 - 0x0FFF: xdg-shell core values, documented below.
0x1000 - 0x1FFF: GNOME
</description>
</event>
<entry name="maximized" value="1" summary="the surface is maximized">
A non-zero value indicates the surface is maximized. Otherwise,
the surface is unmaximized.
</entry>
<entry name="fullscreen" value="2" summary="the surface is fullscreen">
A non-zero value indicates the surface is fullscreen. Otherwise,
the surface is not fullscreen.
</entry>
</enum>
<event name="request_unset_fullscreen">
<description summary="server requests that the client unset fullscreen">
Event sent from the compositor to the client requesting that the client
leaves the fullscreen state. It's the client job to call
unset_fullscreen and really leave the fullscreen state.
</description>
</event>
<request name="set_fullscreen">
<description summary="set the surface state as fullscreen">
Set the surface as fullscreen.
After this request, the compositor should send a configure event
informing the output size.
This request informs the compositor that the next attached buffer
committed will be in a fullscreen state. The buffer size should be the
same size as the size informed in the configure event, if the client
doesn't want to leave any empty area.
In other words: the next attached buffer after set_maximized is the new
maximized buffer. And the surface will be positioned at the maximized
position on commit.
A simple way to synchronize and wait for the correct configure event is
to use a wl_display.sync request right after the set_fullscreen
request. When the sync callback returns, the last configure event
received just before it will be the correct one, and should contain the
right size for the surface to maximize.
Setting one state won't unset another state. Use
xdg_surface.unset_fullscreen for unsetting it.
<request name="request_change_state">
<description summary="client requests to change a surface's state">
This asks the compositor to change the state. If the compositor wants
to change the state, it will send a change_state event with the same
state_type, value, and serial, and the event flow continues as if it
it was initiated by the compositor.
If the compositor does not want to change the state, it will send a
change_state to the client with the old value of the state.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="an event serial">
This serial is so the client can know which change_state event corresponds
to which request_change_state request it sent out.
</arg>
</request>
<request name="unset_fullscreen">
<description summary="unset the surface state as fullscreen">
Unset the surface fullscreen state.
Same negotiation as set_fullscreen must be used.
<event name="change_state">
<description summary="compositor wants to change a surface's state">
This event tells the client to change a surface's state. The client
should respond with an ack_change_state request to the compositor to
guarantee that the compositor knows that the client has seen it.
</description>
</request>
<event name="request_set_maximized">
<description summary="server requests that the client set maximized">
Event sent from the compositor to the client requesting that the client
goes to a maximized state. It's the client job to call set_maximized
and really trigger the maximized state.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/>
</event>
<event name="request_unset_maximized">
<description summary="server requests that the client unset maximized">
Event sent from the compositor to the client requesting that the client
leaves the maximized state. It's the client job to call unset_maximized
and really leave the maximized state.
</description>
</event>
<request name="set_maximized">
<description summary="set the surface state as maximized">
Set the surface as maximized.
After this request, the compositor will send a configure event
informing the output size minus panel and other MW decorations.
This request informs the compositor that the next attached buffer
committed will be in a maximized state. The buffer size should be the
same size as the size informed in the configure event, if the client
doesn't want to leave any empty area.
In other words: the next attached buffer after set_maximized is the new
maximized buffer. And the surface will be positioned at the maximized
position on commit.
A simple way to synchronize and wait for the correct configure event is
to use a wl_display.sync request right after the set_maximized request.
When the sync callback returns, the last configure event received just
before it will be the correct one, and should contain the right size
for the surface to maximize.
Setting one state won't unset another state. Use
xdg_surface.unset_maximized for unsetting it.
</description>
</request>
<request name="unset_maximized">
<description summary="unset the surface state as maximized">
Unset the surface maximized state.
Same negotiation as set_maximized must be used.
<request name="ack_change_state">
<description summary="ack a change_state event">
When a change_state event is received, a client should then ack it
using the ack_change_state request to ensure that the compositor
knows the client has seen the event.
By this point, the state is confirmed, and the next attach should
contain the buffer drawn for the new state value.
The values here need to be the same as the values in the cooresponding
change_state event.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="a serial to pass to change_state"/>
</request>
<request name="set_minimized">
<description summary="set the surface state as minimized">
Set the surface minimized state.
Setting one state won't unset another state.
<description summary="minimize the surface">
Minimize the surface.
</description>
</request>
<event name="focused_set">
<description summary="surface was focused">
The focused_set event is sent when this surface has been
activated. Window decorations should be updated accordingly.
<event name="activated">
<description summary="surface was activated">
The activated_set event is sent when this surface has been
activated, which means that the surface has user attention.
Window decorations should be updated accordingly. You should
not use this event for anything but the style of decorations
you display, use wl_keyboard.enter and wl_keyboard.leave for
determining keyboard focus.
</description>
</event>
<event name="focused_unset">
<description summary="surface was unfocused">
The focused_unset event is sent when this surface has been
deactivated, because another surface has been activated. Window
decorations should be updated accordingly.
<event name="deactivated">
<description summary="surface was deactivated">
The deactivate event is sent when this surface has been
deactivated, which means that the surface lost user attention.
Window decorations should be updated accordingly. You should
not use this event for anything but the style of decorations
you display, use wl_keyboard.enter and wl_keyboard.leave for
determining keyboard focus.
</description>
</event>
<event name="delete">
<description summary="surface wants to be closed">
The delete event is sent by the compositor when the user
wants the surface to be closed. This should be equivalent to
the user clicking the close button in client-side decorations,
if your application has any...
This is only a request that the user intends to close your
window. The client may choose to ignore this request, or show
a dialog to ask the user to save their data...
</description>
</event>
</interface>
@@ -409,22 +428,6 @@
</description>
</request>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
<event name="ping">
<description summary="ping client">
Ping a client to check if it is receiving events and sending
requests. A client is expected to reply with a pong request.
</description>
<arg name="serial" type="uint"/>
</event>
<event name="popup_done">
<description summary="popup interaction is done">
The popup_done event is sent out when a popup grab is broken,

View File

@@ -42,13 +42,10 @@ mutter_built_sources = \
mutter-enum-types.c \
wayland/gtk-shell-protocol.c \
wayland/gtk-shell-server-protocol.h \
wayland/gtk-shell-client-protocol.h \
wayland/xdg-shell-protocol.c \
wayland/xdg-shell-server-protocol.h \
wayland/xdg-shell-client-protocol.h \
wayland/xserver-protocol.c \
wayland/xserver-server-protocol.h \
wayland/xserver-client-protocol.h
wayland/xserver-server-protocol.h
libmutter_wayland_la_SOURCES = \
core/async-getprop.c \
@@ -191,12 +188,7 @@ libmutter_wayland_la_SOURCES = \
ui/theme.c \
meta/theme.h \
ui/theme-private.h \
ui/ui.c
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
libmutter_wayland_la_SOURCES += \
ui/ui.c \
wayland/meta-wayland.c \
wayland/meta-wayland-private.h \
wayland/meta-xwayland-private.h \
@@ -218,6 +210,9 @@ libmutter_wayland_la_SOURCES += \
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
libmutter_wayland_la_LDFLAGS = -no-undefined
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
@@ -420,6 +415,3 @@ wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
wayland/%-client-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@

View File

@@ -42,15 +42,6 @@
* the call, so it may be necessary to readjust the display based on the
* old_rect to start the animation.
*
* meta_compositor_window_mapped() and meta_compositor_window_unmapped() are
* notifications when the toplevel window (frame or client window) is mapped or
* unmapped. That is, when the result of meta_window_toplevel_is_mapped()
* changes. The main use of this is to drop resources when a window is unmapped.
* A window will always be mapped before meta_compositor_show_window()
* is called and will not be unmapped until after meta_compositor_hide_window()
* is called. If the live_hidden_windows preference is set, windows will never
* be unmapped.
*
* # Containers #
*
* There's two containers in the stage that are used to place window actors, here
@@ -149,19 +140,6 @@ meta_compositor_destroy (MetaCompositor *compositor)
clutter_threads_remove_repaint_func (compositor->repaint_func_id);
}
static void
add_win (MetaWindow *window)
{
MetaScreen *screen = meta_window_get_screen (window);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
g_return_if_fail (info != NULL);
meta_window_actor_new (window);
sync_actor_stacking (info);
}
static void
process_damage (MetaCompositor *compositor,
XDamageNotifyEvent *event,
@@ -844,13 +822,20 @@ meta_compositor_add_window (MetaCompositor *compositor,
{
MetaScreen *screen = meta_window_get_screen (window);
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
g_return_if_fail (info != NULL);
/* Window was already added previously, probably coming
* back from hiding */
if (window->compositor_private != NULL)
return;
DEBUG_TRACE ("meta_compositor_add_window\n");
meta_error_trap_push (display);
add_win (window);
meta_window_actor_new (window);
meta_error_trap_pop (display);
sync_actor_stacking (info);
}
void
@@ -1369,30 +1354,6 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
sync_actor_stacking (info);
}
void
meta_compositor_window_mapped (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_window_mapped\n");
if (!window_actor)
return;
meta_window_actor_mapped (window_actor);
}
void
meta_compositor_window_unmapped (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_window_unmapped\n");
if (!window_actor)
return;
meta_window_actor_unmapped (window_actor);
}
void
meta_compositor_sync_window_geometry (MetaCompositor *compositor,
MetaWindow *window,

View File

@@ -70,10 +70,16 @@ meta_cullable_cull_out_children (MetaCullable *cullable,
while (clutter_actor_iter_prev (&iter, &child))
{
float x, y;
gboolean needs_culling;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
if (!META_IS_CULLABLE (child))
continue;
needs_culling = (unobscured_region != NULL && clip_region != NULL);
if (needs_culling && !CLUTTER_ACTOR_IS_VISIBLE (child))
needs_culling = FALSE;
/* If an actor has effects applied, then that can change the area
* it paints and the opacity, so we no longer can figure out what
* portion of the actor is obscured and what portion of the screen
@@ -90,25 +96,29 @@ meta_cullable_cull_out_children (MetaCullable *cullable,
* as well for the same reason, but omitted for simplicity in the
* hopes that no-one will do that.
*/
if (clutter_actor_has_effects (child))
continue;
if (needs_culling && clutter_actor_has_effects (child))
needs_culling = FALSE;
if (!META_IS_CULLABLE (child))
continue;
if (needs_culling && !meta_actor_is_untransformed (child, NULL, NULL))
needs_culling = FALSE;
if (!meta_actor_is_untransformed (child, NULL, NULL))
continue;
if (needs_culling)
{
clutter_actor_get_position (child, &x, &y);
clutter_actor_get_position (child, &x, &y);
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (unobscured_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (unobscured_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region);
meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region);
cairo_region_translate (unobscured_region, x, y);
cairo_region_translate (clip_region, x, y);
cairo_region_translate (unobscured_region, x, y);
cairo_region_translate (clip_region, x, y);
}
else
{
meta_cullable_cull_out (META_CULLABLE (child), NULL, NULL);
}
}
}

View File

@@ -32,5 +32,8 @@
ClutterActor *meta_shaped_texture_new (void);
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
gboolean meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *stex,
cairo_rectangle_int_t *unobscured_bounds);
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
#endif

View File

@@ -73,10 +73,15 @@ struct _MetaShapedTexturePrivate
CoglTexture *texture;
CoglTexture *mask_texture;
cairo_region_t *clip_region;
cairo_region_t *input_shape_region;
/* The region containing only fully opaque pixels */
cairo_region_t *opaque_region;
/* MetaCullable regions, see that documentation for more details */
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
guint tex_width, tex_height;
guint create_mipmaps : 1;
@@ -113,6 +118,21 @@ meta_shaped_texture_init (MetaShapedTexture *self)
priv->create_mipmaps = TRUE;
}
static void
set_unobscured_region (MetaShapedTexture *self,
cairo_region_t *unobscured_region)
{
MetaShapedTexturePrivate *priv = self->priv;
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 };
priv->unobscured_region = cairo_region_copy (unobscured_region);
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
}
}
static void
set_clip_region (MetaShapedTexture *self,
cairo_region_t *clip_region)
@@ -138,6 +158,7 @@ meta_shaped_texture_dispose (GObject *object)
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
meta_shaped_texture_set_mask_texture (self, NULL);
set_unobscured_region (self, NULL);
set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
@@ -546,10 +567,37 @@ meta_shaped_texture_get_preferred_height (ClutterActor *self,
}
static gboolean
meta_shaped_texture_get_paint_volume (ClutterActor *self,
meta_shaped_texture_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
return clutter_paint_volume_set_from_allocation (volume, self);
MetaShapedTexture *self = META_SHAPED_TEXTURE (actor);
cairo_rectangle_int_t unobscured_bounds;
if (!clutter_paint_volume_set_from_allocation (volume, actor))
return FALSE;
if (meta_shaped_texture_get_unobscured_bounds (self, &unobscured_bounds))
{
ClutterVertex origin;
cairo_rectangle_int_t bounds;
/* I hate ClutterPaintVolume so much... */
clutter_paint_volume_get_origin (volume, &origin);
bounds.x = origin.x;
bounds.y = origin.y;
bounds.width = clutter_paint_volume_get_width (volume);
bounds.height = clutter_paint_volume_get_height (volume);
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
origin.x = bounds.x;
origin.y = bounds.y;
clutter_paint_volume_set_origin (volume, &origin);
clutter_paint_volume_set_width (volume, bounds.width);
clutter_paint_volume_set_height (volume, bounds.height);
}
return TRUE;
}
void
@@ -594,50 +642,38 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
static gboolean
get_clip (MetaShapedTexture *stex,
int x,
int y,
int width,
int height,
cairo_rectangle_int_t *clip)
static cairo_region_t *
effective_unobscured_region (MetaShapedTexture *self)
{
ClutterActor *self = CLUTTER_ACTOR (stex);
MetaShapedTexturePrivate *priv;
ClutterActorBox allocation;
double scale_x;
double scale_y;
MetaShapedTexturePrivate *priv = self->priv;
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's
* coordinate space so we need to convert from surface coordinates to
* actor coordinates...
*/
return clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)) ? NULL : priv->unobscured_region;
}
/* Calling clutter_actor_get_allocation_box() is enormously expensive
* if the actor has an out-of-date allocation, since it triggers
* a full redraw. clutter_actor_queue_redraw_with_clip() would redraw
* the whole stage anyways in that case, so just go ahead and do
* it here.
*/
if (!clutter_actor_has_allocation (self))
gboolean
meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *self,
cairo_rectangle_int_t *unobscured_bounds)
{
cairo_region_t *unobscured_region = effective_unobscured_region (self);
if (unobscured_region)
{
cairo_region_get_extents (unobscured_region, unobscured_bounds);
return TRUE;
}
else
return FALSE;
}
priv = stex->priv;
gboolean
meta_shaped_texture_is_obscured (MetaShapedTexture *self)
{
cairo_region_t *unobscured_region = effective_unobscured_region (self);
if (priv->tex_width == 0 || priv->tex_height == 0)
if (unobscured_region)
return cairo_region_is_empty (unobscured_region);
else
return FALSE;
clutter_actor_get_allocation_box (self, &allocation);
scale_x = (allocation.x2 - allocation.x1) / priv->tex_width;
scale_y = (allocation.y2 - allocation.y1) / priv->tex_height;
clip->x = x * scale_x;
clip->y = y * scale_y;
clip->width = width * scale_x;
clip->height = height * scale_y;
return TRUE;
}
/**
@@ -647,14 +683,9 @@ get_clip (MetaShapedTexture *stex,
* @y: the y coordinate of the damaged area
* @width: the width of the damaged area
* @height: the height of the damaged area
* @unobscured_region: The unobscured region of the window or %NULL if
* there is no valid one (like when the actor is transformed or
* has a mapped clone)
*
* Repairs the damaged area indicated by @x, @y, @width and @height
* and queues a redraw for the intersection @unobscured_region and
* the damage area. If @unobscured_region is %NULL a redraw will always
* get queued.
* and potentially queues a redraw.
*
* Return value: Whether a redraw have been queued or not
*/
@@ -663,12 +694,11 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region)
int height)
{
MetaShapedTexturePrivate *priv;
cairo_rectangle_int_t clip;
gboolean has_clip;
cairo_region_t *unobscured_region;
const cairo_rectangle_int_t clip = { x, y, width, height };
priv = stex->priv;
@@ -677,8 +707,7 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
has_clip = get_clip (stex, x, y, width, height, &clip);
unobscured_region = effective_unobscured_region (stex);
if (unobscured_region)
{
cairo_region_t *intersection;
@@ -687,8 +716,7 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
return FALSE;
intersection = cairo_region_copy (unobscured_region);
if (has_clip)
cairo_region_intersect_rectangle (intersection, &clip);
cairo_region_intersect_rectangle (intersection, &clip);
if (!cairo_region_is_empty (intersection))
{
@@ -696,21 +724,17 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
cairo_region_get_extents (intersection, &damage_rect);
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
cairo_region_destroy (intersection);
return TRUE;
}
cairo_region_destroy (intersection);
return FALSE;
}
if (has_clip)
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
else
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
return TRUE;
{
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
return TRUE;
}
}
/**
@@ -911,14 +935,17 @@ meta_shaped_texture_cull_out (MetaCullable *cullable,
MetaShapedTexture *self = META_SHAPED_TEXTURE (cullable);
MetaShapedTexturePrivate *priv = self->priv;
set_unobscured_region (self, unobscured_region);
set_clip_region (self, clip_region);
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self)) == 0xff)
{
if (priv->opaque_region)
{
cairo_region_subtract (unobscured_region, priv->opaque_region);
cairo_region_subtract (clip_region, priv->opaque_region);
if (unobscured_region)
cairo_region_subtract (unobscured_region, priv->opaque_region);
if (clip_region)
cairo_region_subtract (clip_region, priv->opaque_region);
}
}
}

View File

@@ -31,6 +31,14 @@ static void cullable_iface_init (MetaCullableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
gboolean
meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
cairo_rectangle_int_t *unobscured_bounds)
{
MetaSurfaceActorPrivate *priv = self->priv;
return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds);
}
static void
meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
{
@@ -109,18 +117,13 @@ update_area (MetaSurfaceActor *self,
}
gboolean
meta_surface_actor_damage_all (MetaSurfaceActor *self,
cairo_region_t *unobscured_region)
meta_surface_actor_damage_all (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
CoglTexture *texture = meta_shaped_texture_get_texture (priv->texture);
update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture));
return meta_shaped_texture_update_area (priv->texture,
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture),
unobscured_region);
return meta_shaped_texture_update_area (priv->texture, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture));
}
gboolean
@@ -128,15 +131,19 @@ meta_surface_actor_damage_area (MetaSurfaceActor *self,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region)
int height)
{
MetaSurfaceActorPrivate *priv = self->priv;
update_area (self, x, y, width, height);
return meta_shaped_texture_update_area (priv->texture,
x, y, width, height,
unobscured_region);
return meta_shaped_texture_update_area (priv->texture, x, y, width, height);
}
gboolean
meta_surface_actor_is_obscured (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
return meta_shaped_texture_is_obscured (priv->texture);
}
void

View File

@@ -43,15 +43,16 @@ cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self,
MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self);
gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self,
cairo_region_t *unobscured_region);
gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self);
gboolean meta_surface_actor_damage_area (MetaSurfaceActor *self,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region);
int height);
gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self);
gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
cairo_rectangle_int_t *unobscured_bounds);
void meta_surface_actor_set_texture (MetaSurfaceActor *self,
CoglTexture *texture);

View File

@@ -59,9 +59,6 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
gboolean no_delay_frame);
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region);
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);

View File

@@ -37,15 +37,6 @@
#include "monitor-private.h"
#include "meta-cullable.h"
enum {
POSITION_CHANGED,
SIZE_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = {0};
struct _MetaWindowActorPrivate
{
MetaWindow *window;
@@ -72,9 +63,6 @@ struct _MetaWindowActorPrivate
/* The region we should clip to when painting the shadow */
cairo_region_t *shadow_clip;
/* The region that is visible, used to optimize out redraws */
cairo_region_t *unobscured_region;
guint send_frame_messages_timer;
gint64 frame_drawn_time;
@@ -106,7 +94,6 @@ struct _MetaWindowActorPrivate
Damage damage; /* Not used in wayland compositor mode */
guint visible : 1;
guint mapped : 1;
guint argb32 : 1;
guint disposed : 1;
guint redecorating : 1;
@@ -249,19 +236,6 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
g_object_class_install_property (object_class,
PROP_SHADOW_CLASS,
pspec);
signals[POSITION_CHANGED] =
g_signal_new ("position-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[SIZE_CHANGED] =
g_signal_new ("size-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
@@ -331,8 +305,6 @@ surface_allocation_changed_notify (ClutterActor *actor,
{
meta_window_actor_sync_actor_geometry (self, FALSE);
meta_window_actor_update_shape (self);
g_signal_emit (self, signals[SIZE_CHANGED], 0);
}
static gboolean
@@ -425,7 +397,6 @@ meta_window_actor_dispose (GObject *object)
priv->send_frame_messages_timer = 0;
}
g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
@@ -696,7 +667,7 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
{
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
MetaWindowActorPrivate *priv = self->priv;
cairo_rectangle_int_t bounds;
cairo_rectangle_int_t unobscured_bounds, bounds;
gboolean appears_focused = meta_window_appears_focused (priv->window);
ClutterVertex origin;
@@ -721,12 +692,8 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
}
if (priv->unobscured_region && !clutter_actor_has_mapped_clones (actor))
{
cairo_rectangle_int_t unobscured_bounds;
cairo_region_get_extents (priv->unobscured_region, &unobscured_bounds);
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
}
if (meta_surface_actor_get_unobscured_bounds (priv->surface, &unobscured_bounds))
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
origin.x = bounds.x;
origin.y = bounds.y;
@@ -925,21 +892,15 @@ static void
meta_window_actor_damage_all (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *unobscured_region;
gboolean redraw_queued;
if (!priv->needs_damage_all)
return;
if (!priv->mapped || priv->needs_pixmap)
if (priv->needs_pixmap)
return;
unobscured_region =
clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
? NULL : priv->unobscured_region;
redraw_queued = meta_surface_actor_damage_all (priv->surface, unobscured_region);
redraw_queued = meta_surface_actor_damage_all (priv->surface);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
priv->needs_damage_all = FALSE;
}
@@ -997,17 +958,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
if (!priv->repaint_scheduled)
{
gboolean is_obscured = FALSE;
/* Find out whether the window is completly obscured */
if (priv->unobscured_region)
{
cairo_region_t *unobscured_window_region;
unobscured_window_region = cairo_region_copy (priv->shape_region);
cairo_region_intersect (unobscured_window_region, priv->unobscured_region);
is_obscured = cairo_region_is_empty (unobscured_window_region);
cairo_region_destroy (unobscured_window_region);
}
gboolean is_obscured = meta_surface_actor_is_obscured (priv->surface);
/* A frame was marked by the client without actually doing any
* damage or any unobscured, or while we had the window frozen
@@ -1021,7 +972,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
{
queue_send_frame_messages_timeout (self);
}
else if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
else
{
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip);
@@ -1053,9 +1004,6 @@ meta_window_actor_queue_create_x11_pixmap (MetaWindowActor *self)
priv->needs_pixmap = TRUE;
if (!priv->mapped)
return;
if (is_frozen (self))
return;
@@ -1153,9 +1101,6 @@ meta_window_actor_after_effects (MetaWindowActor *self)
if (!meta_is_wayland_compositor ())
{
if (!meta_window_is_mapped (priv->window))
meta_window_actor_detach_x11_pixmap (self);
if (priv->needs_pixmap)
clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface));
}
@@ -1421,8 +1366,6 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
window_rect.x, window_rect.y);
clutter_actor_set_size (CLUTTER_ACTOR (self),
window_rect.width, window_rect.height);
g_signal_emit (self, signals[POSITION_CHANGED], 0);
}
void
@@ -1582,15 +1525,13 @@ meta_window_actor_new (MetaWindow *window)
NULL);
priv = self->priv;
priv->mapped = meta_window_toplevel_is_mapped (priv->window);
if (!meta_is_wayland_compositor ())
{
priv->last_width = -1;
priv->last_height = -1;
if (priv->mapped)
meta_window_actor_queue_create_x11_pixmap (self);
meta_window_actor_queue_create_x11_pixmap (self);
meta_window_actor_set_updates_frozen (self,
meta_window_updates_are_frozen (priv->window));
@@ -1626,38 +1567,6 @@ meta_window_actor_new (MetaWindow *window)
return self;
}
void
meta_window_actor_mapped (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
g_return_if_fail (!priv->mapped);
priv->mapped = TRUE;
if (!meta_is_wayland_compositor ())
meta_window_actor_queue_create_x11_pixmap (self);
}
void
meta_window_actor_unmapped (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
g_return_if_fail (priv->mapped);
priv->mapped = FALSE;
if (meta_window_actor_effect_in_progress (self))
return;
if (!meta_is_wayland_compositor ())
{
meta_window_actor_detach_x11_pixmap (self);
priv->needs_pixmap = FALSE;
}
}
#if 0
/* Print out a region; useful for debugging */
static void
@@ -1699,30 +1608,6 @@ see_region (cairo_region_t *region,
}
#endif
/**
* meta_window_actor_set_unobscured_region:
* @self: a #MetaWindowActor
* @unobscured_region: the region of the screen that isn't completely
* obscured.
*
* Provides a hint as to what areas of the window need to queue
* redraws when damaged. Regions not in @unobscured_region are completely obscured.
*/
void
meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->unobscured_region)
cairo_region_destroy (priv->unobscured_region);
if (unobscured_region)
priv->unobscured_region = cairo_region_copy (unobscured_region);
else
priv->unobscured_region = NULL;
}
/**
* meta_window_actor_set_clip_region_beneath:
* @self: a #MetaWindowActor
@@ -1745,13 +1630,19 @@ meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
{
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
priv->shadow_clip = cairo_region_copy (beneath_region);
if (clip_shadow_under_window (self))
if (beneath_region)
{
cairo_region_t *frame_bounds = meta_window_get_frame_bounds (priv->window);
cairo_region_subtract (priv->shadow_clip, frame_bounds);
priv->shadow_clip = cairo_region_copy (beneath_region);
if (clip_shadow_under_window (self))
{
cairo_region_t *frame_bounds = meta_window_get_frame_bounds (priv->window);
cairo_region_subtract (priv->shadow_clip, frame_bounds);
}
}
else
priv->shadow_clip = NULL;
}
}
@@ -1767,7 +1658,6 @@ meta_window_actor_cull_out (MetaCullable *cullable,
if (priv->unredirected)
return;
meta_window_actor_set_unobscured_region (self, unobscured_region);
meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
meta_window_actor_set_clip_region_beneath (self, clip_region);
}
@@ -1806,9 +1696,6 @@ check_needs_x11_pixmap (MetaWindowActor *self)
if (!priv->needs_pixmap)
return;
if (!priv->mapped)
return;
if (xwindow == meta_screen_get_xroot (screen) ||
xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)))
return;
@@ -1853,17 +1740,6 @@ check_needs_x11_pixmap (MetaWindowActor *self)
g_warning ("NOTE: Not using GLX TFP!\n");
meta_surface_actor_set_texture (META_SURFACE_ACTOR (priv->surface), texture);
/* ::size-changed is supposed to refer to meta_window_get_frame_rect().
* Emitting it here works pretty much OK because a new value of the
* *input* rect (which is the outer rect with the addition of invisible
* borders) forces a new pixmap and we get here. In the rare case where
* a change to the window size was exactly balanced by a change to the
* invisible borders, we would miss emitting the signal. We would also
* emit spurious signals when we get a new pixmap without a new size,
* but that should be mostly harmless.
*/
g_signal_emit (self, signals[SIZE_CHANGED], 0);
}
priv->needs_pixmap = FALSE;
@@ -1882,9 +1758,6 @@ check_needs_shadow (MetaWindowActor *self)
gboolean should_have_shadow;
gboolean appears_focused;
if (!priv->mapped)
return;
/* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap
* and avoids the need to explicitly handle window type changes, which
* we would do if tried to keep track of when we might be adding or removing
@@ -1944,7 +1817,6 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
gboolean redraw_queued;
cairo_region_t *unobscured_region;
priv->received_x11_damage = TRUE;
@@ -1989,21 +1861,15 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
return;
}
if (!priv->mapped || priv->needs_pixmap)
if (priv->needs_pixmap)
return;
unobscured_region =
clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
? NULL : priv->unobscured_region;
redraw_queued = meta_surface_actor_damage_area (priv->surface,
event->area.x,
event->area.y,
event->area.width,
event->area.height,
unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
event->area.height);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
}
void
@@ -2268,9 +2134,6 @@ check_needs_reshape (MetaWindowActor *self)
MetaFrameBorders borders;
cairo_rectangle_int_t client_area;
if (!priv->mapped)
return;
if (!priv->needs_reshape)
return;

View File

@@ -115,8 +115,6 @@ meta_window_group_paint (ClutterActor *actor)
{
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
ClutterActorIter iter;
ClutterActor *child;
cairo_rectangle_int_t visible_rect, clip_rect;
int paint_x_offset, paint_y_offset;
int paint_x_origin, paint_y_origin;
@@ -125,18 +123,6 @@ meta_window_group_paint (ClutterActor *actor)
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
ClutterActor *stage = clutter_actor_get_stage (actor);
/* Start off by treating all windows as completely unobscured, so damage anywhere
* in a window queues redraws, but confine it more below. */
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
meta_window_actor_set_unobscured_region (window_actor, NULL);
}
}
/* Normally we expect an actor to be drawn at it's position on the screen.
* However, if we're inside the paint of a ClutterClone, that won't be the
* case and we need to compensate. We look at the position of the window

View File

@@ -32,7 +32,7 @@
#include <gmodule.h>
#include <string.h>
#define DESTROY_TIMEOUT 250
#define DESTROY_TIMEOUT 100
#define MINIMIZE_TIMEOUT 250
#define MAXIMIZE_TIMEOUT 250
#define MAP_TIMEOUT 250
@@ -289,26 +289,13 @@ on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
meta_plugin_switch_workspace_completed (plugin);
}
static gboolean
show_stage (MetaPlugin *plugin)
{
MetaScreen *screen;
ClutterActor *stage;
screen = meta_plugin_get_screen (plugin);
stage = meta_get_stage_for_screen (screen);
clutter_actor_show (stage);
return FALSE;
}
static void
on_monitors_changed (MetaScreen *screen,
MetaPlugin *plugin)
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
int i, n;
GRand *rand = g_rand_new_with_seed (12345);
clutter_actor_destroy_all_children (self->priv->background_group);
@@ -331,14 +318,16 @@ on_monitors_changed (MetaScreen *screen,
reproducible.
*/
clutter_color_init (&color,
g_random_int () % 255,
g_random_int () % 255,
g_random_int () % 255,
g_rand_int_range (rand, 0, 255),
g_rand_int_range (rand, 0, 255),
g_rand_int_range (rand, 0, 255),
255);
clutter_actor_set_background_color (background, &color);
clutter_actor_add_child (self->priv->background_group, background);
}
g_rand_free (rand);
}
static void
@@ -355,10 +344,7 @@ start (MetaPlugin *plugin)
G_CALLBACK (on_monitors_changed), plugin);
on_monitors_changed (screen, plugin);
meta_later_add (META_LATER_BEFORE_REDRAW,
(GSourceFunc) show_stage,
plugin,
NULL);
clutter_actor_show (meta_get_stage_for_screen (screen));
}
static void
@@ -483,8 +469,6 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
/* FIXME - we shouldn't assume the original scale, it should be saved
* at the start of the effect */
clutter_actor_set_scale (data->actor, 1.0, 1.0);
clutter_actor_move_anchor_point_from_gravity (data->actor,
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_minimize_completed (plugin, window_actor);
@@ -521,9 +505,6 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
apriv->is_minimized = TRUE;
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
MINIMIZE_TIMEOUT,
@@ -562,8 +543,6 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
/* FIXME - don't assume the original scale was 1.0 */
clutter_actor_set_scale (data->actor, 1.0, 1.0);
clutter_actor_move_anchor_point_from_gravity (data->actor,
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_maximize_completed (plugin, window_actor);
@@ -588,10 +567,8 @@ maximize (MetaPlugin *plugin,
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
gfloat anchor_x = 0;
gfloat anchor_y = 0;
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
type = meta_window_get_window_type (meta_window);
@@ -615,13 +592,6 @@ maximize (MetaPlugin *plugin,
scale_x = (gdouble)end_width / (gdouble) width;
scale_y = (gdouble)end_height / (gdouble) height;
anchor_x = (gdouble)(x - end_x)*(gdouble)width /
((gdouble)(end_width - width));
anchor_y = (gdouble)(y - end_y)*(gdouble)height /
((gdouble)(end_height - height));
clutter_actor_move_anchor_point (actor, anchor_x, anchor_y);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
MAXIMIZE_TIMEOUT,
@@ -676,9 +646,6 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
apriv->tml_map = NULL;
clutter_actor_move_anchor_point_from_gravity (data->actor,
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_map_completed (plugin, window_actor);
@@ -704,15 +671,15 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
clutter_actor_set_scale (actor, 0.0, 0.0);
clutter_actor_set_pivot_point (actor, 0.5, 0.5);
clutter_actor_set_opacity (actor, 0);
clutter_actor_set_scale (actor, 0.5, 0.5);
clutter_actor_show (actor);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
CLUTTER_EASE_OUT_QUAD,
MAP_TIMEOUT,
"opacity", 255,
"scale-x", 1.0,
"scale-y", 1.0,
NULL);
@@ -764,14 +731,12 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
CLUTTER_EASE_OUT_QUAD,
DESTROY_TIMEOUT,
"scale-x", 0.0,
"scale-y", 1.0,
"opacity", 0,
"scale-x", 0.8,
"scale-y", 0.8,
NULL);
apriv->tml_destroy = clutter_animation_get_timeline (animation);
data->plugin = plugin;

View File

@@ -37,6 +37,8 @@
#include <stdlib.h>
#include <stdio.h>
#include "meta-wayland-surface.h"
static void meta_window_present_delete_dialog (MetaWindow *window,
guint32 timestamp);
@@ -130,35 +132,42 @@ void
meta_window_check_alive (MetaWindow *window,
guint32 timestamp)
{
meta_window_ping (window,
timestamp,
delete_ping_reply_func,
delete_ping_timeout_func,
NULL);
meta_display_ping_window (window,
timestamp,
delete_ping_reply_func,
delete_ping_timeout_func,
NULL);
}
void
meta_window_delete (MetaWindow *window,
guint32 timestamp)
{
meta_error_trap_push (window->display);
if (window->delete_window)
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with delete_window request\n",
window->desc);
meta_window_send_icccm_message (window,
window->display->atom_WM_DELETE_WINDOW,
timestamp);
meta_error_trap_push (window->display);
if (window->delete_window)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with delete_window request\n",
window->desc);
meta_window_send_icccm_message (window,
window->display->atom_WM_DELETE_WINDOW,
timestamp);
}
else
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with explicit kill\n",
window->desc);
XKillClient (window->display->xdisplay, window->xwindow);
}
meta_error_trap_pop (window->display);
}
else
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Deleting %s with explicit kill\n",
window->desc);
XKillClient (window->display->xdisplay, window->xwindow);
meta_wayland_surface_delete (window->surface);
}
meta_error_trap_pop (window->display);
meta_window_check_alive (window, timestamp);

View File

@@ -55,6 +55,10 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef void (* MetaWindowPingFunc) (MetaWindow *window,
guint32 timestamp,
gpointer user_data);
typedef enum {
META_LIST_DEFAULT = 0, /* normal windows */
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
@@ -183,7 +187,7 @@ struct _MetaDisplay
guint32 window_sequence_counter;
/* Pings which we're waiting for a reply from */
GHashTable *pending_pings;
GSList *pending_pings;
/* Pending focus change */
guint focus_timeout_id;
@@ -449,6 +453,14 @@ void meta_display_retheme_all (void);
void meta_display_set_cursor_theme (const char *theme,
int size);
void meta_display_ping_window (MetaWindow *window,
guint32 timestamp,
MetaWindowPingFunc ping_reply_func,
MetaWindowPingFunc ping_timeout_func,
void *user_data);
void meta_display_pong_for_serial (MetaDisplay *display,
guint32 serial);
int meta_resize_gravity_from_grab_op (MetaGrabOp op);
gboolean meta_grab_op_is_moving (MetaGrabOp op);

View File

@@ -82,6 +82,40 @@
g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK || \
g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP)
/*
* SECTION:pings
*
* Sometimes we want to see whether a window is responding,
* so we send it a "ping" message and see whether it sends us back a "pong"
* message within a reasonable time. Here we have a system which lets us
* nominate one function to be called if we get the pong in time and another
* function if we don't. The system is rather more complicated than it needs
* to be, since we only ever use it to destroy windows which are asked to
* close themselves and don't do so within a reasonable amount of time, and
* therefore we always use the same callbacks. It's possible that we might
* use it for other things in future, or on the other hand we might decide
* that we're never going to do so and simplify it a bit.
*/
/**
* MetaPingData:
*
* Describes a ping on a window. When we send a ping to a window, we build
* one of these structs, and it eventually gets passed to the timeout function
* or to the function which handles the response from the window. If the window
* does or doesn't respond to the ping, we use this information to deal with
* these facts; we have a handler function for each.
*/
typedef struct
{
MetaWindow *window;
guint32 timestamp;
MetaWindowPingFunc ping_reply_func;
MetaWindowPingFunc ping_timeout_func;
void *user_data;
guint ping_timeout_id;
} MetaPingData;
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
/* Signals */
@@ -283,6 +317,62 @@ meta_display_class_init (MetaDisplayClass *klass)
G_PARAM_READABLE));
}
/**
* ping_data_free:
*
* Destructor for #MetaPingData structs. Will destroy the
* event source for the struct as well.
*/
static void
ping_data_free (MetaPingData *ping_data)
{
/* Remove the timeout */
if (ping_data->ping_timeout_id != 0)
g_source_remove (ping_data->ping_timeout_id);
g_free (ping_data);
}
/**
* remove_pending_pings_for_window:
* @display: The display the window appears on
* @xwindow: The X ID of the window whose pings we should remove
*
* Frees every pending ping structure for the given X window on the
* given display. This means that we also destroy the timeouts.
*/
static void
remove_pending_pings_for_window (MetaDisplay *display, Window xwindow)
{
GSList *tmp;
GSList *dead;
/* could obviously be more efficient, don't care */
/* build list to be removed */
dead = NULL;
for (tmp = display->pending_pings; tmp; tmp = tmp->next)
{
MetaPingData *ping_data = tmp->data;
if (ping_data->window->xwindow == xwindow)
dead = g_slist_prepend (dead, ping_data);
}
/* remove what we found */
for (tmp = dead; tmp; tmp = tmp->next)
{
MetaPingData *ping_data = tmp->data;
display->pending_pings = g_slist_remove (display->pending_pings, ping_data);
ping_data_free (ping_data);
}
g_slist_free (dead);
}
#ifdef HAVE_STARTUP_NOTIFICATION
static void
sn_error_trap_push (SnDisplay *sn_display,
@@ -388,7 +478,6 @@ meta_display_open (void)
Display *xdisplay;
GSList *screens;
MetaScreen *screen;
GSList *tmp;
int i;
guint32 timestamp;
@@ -434,6 +523,7 @@ meta_display_open (void)
the_display->server_grab_count = 0;
the_display->display_opening = TRUE;
the_display->pending_pings = NULL;
the_display->autoraise_timeout_id = 0;
the_display->autoraise_window = NULL;
the_display->focus_window = NULL;
@@ -505,7 +595,6 @@ meta_display_open (void)
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
meta_unsigned_long_equal);
the_display->pending_pings = g_hash_table_new (g_int_hash, g_int_equal);
the_display->wayland_windows = g_hash_table_new (NULL, NULL);
i = 0;
@@ -808,12 +897,7 @@ meta_display_open (void)
screen = meta_screen_new (the_display, i, timestamp);
if (screen)
screens = g_slist_prepend (screens, screen);
the_display->screens = screens;
if (screens == NULL)
if (!screen)
{
/* This would typically happen because all the screens already
* have window managers.
@@ -822,24 +906,19 @@ meta_display_open (void)
return FALSE;
}
screens = g_slist_prepend (screens, screen);
the_display->screens = screens;
enable_compositor (the_display);
/* Now manage all existing windows */
tmp = the_display->screens;
while (tmp != NULL)
{
MetaScreen *screen = tmp->data;
meta_screen_create_guard_window (screen);
meta_screen_create_guard_window (screen);
/* We know that if mutter is running as a Wayland compositor,
* we start out with no windows.
*/
if (!meta_is_wayland_compositor ())
meta_screen_manage_all_windows (screen);
tmp = tmp->next;
}
/* We know that if mutter is running as a Wayland compositor,
* we start out with no windows.
*/
if (!meta_is_wayland_compositor ())
meta_screen_manage_all_windows (screen);
{
Window focus;
@@ -1976,18 +2055,16 @@ meta_display_handle_event (MetaDisplay *display,
{
MetaWindow *window;
gboolean bypass_clutter = FALSE, bypass_wayland = FALSE;
MetaWaylandCompositor *compositor = NULL;
/* XXX -- we need to fill this in properly at some point... */
gboolean frame_was_receiver = FALSE;
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *compositor = NULL;
if (meta_is_wayland_compositor ())
{
compositor = meta_wayland_compositor_get_default ();
meta_wayland_compositor_update (compositor, event);
}
#endif /* HAVE_WAYLAND */
window = get_window_for_event (display, event);
@@ -2235,13 +2312,11 @@ meta_display_handle_event (MetaDisplay *display,
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
bypass_wayland = TRUE;
#ifdef HAVE_WAYLAND
if (compositor && !bypass_wayland)
{
if (meta_wayland_compositor_handle_event (compositor, event))
bypass_clutter = TRUE;
}
#endif /* HAVE_WAYLAND */
return bypass_clutter;
}
@@ -2774,7 +2849,7 @@ handle_other_xevent (MetaDisplay *display,
if (display->grab_op != META_GRAB_OP_NONE &&
display->grab_window == window &&
((window->frame == NULL) || !window->frame->mapped))
window->frame == NULL)
meta_display_end_grab_op (display, timestamp);
if (!frame_was_receiver)
@@ -3067,12 +3142,8 @@ handle_other_xevent (MetaDisplay *display,
if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING)
{
guint32 timestamp = event->xclient.data.l[1];
window = g_hash_table_lookup (display->pending_pings, &timestamp);
if (window)
meta_window_pong (window, timestamp);
else
meta_verbose ("Received invalid _NET_WM_PING for unknown timestamp %d\n", timestamp);
meta_display_pong_for_serial (display, timestamp);
/* We don't want ping reply events going into
* the GTK+ event loop because gtk+ will treat
@@ -3981,6 +4052,9 @@ meta_display_unregister_x_window (MetaDisplay *display,
g_return_if_fail (g_hash_table_lookup (display->xids, &xwindow) != NULL);
g_hash_table_remove (display->xids, &xwindow);
/* Remove any pending pings */
remove_pending_pings_for_window (display, xwindow);
}
void
@@ -4829,6 +4903,115 @@ meta_set_syncing (gboolean setting)
}
}
/*
* How long, in milliseconds, we should wait after pinging a window
* before deciding it's not going to get back to us.
*/
#define PING_TIMEOUT_DELAY 5000
/**
* meta_display_ping_timeout:
* @data: All the information about this ping. It is a #MetaPingData
* cast to a #gpointer in order to be passable to a timeout function.
* This function will also free this parameter.
*
* Does whatever it is we decided to do when a window didn't respond
* to a ping. We also remove the ping from the display's list of
* pending pings. This function is called by the event loop when the timeout
* times out which we created at the start of the ping.
*
* Returns: Always returns %FALSE, because this function is called as a
* timeout and we don't want to run the timer again.
*/
static gboolean
meta_display_ping_timeout (gpointer data)
{
MetaPingData *ping_data = data;
MetaDisplay *display = ping_data->window->display;
ping_data->ping_timeout_id = 0;
meta_topic (META_DEBUG_PING,
"Ping %u on window %s timed out\n",
ping_data->timestamp, ping_data->window->desc);
(* ping_data->ping_timeout_func) (ping_data->window, ping_data->timestamp, ping_data->user_data);
display->pending_pings = g_slist_remove (display->pending_pings, ping_data);
ping_data_free (ping_data);
return FALSE;
}
/**
* meta_display_ping_window:
* @display: The #MetaDisplay that the window is on
* @window: The #MetaWindow to send the ping to
* @timestamp: The timestamp of the ping. Used for uniqueness.
* Cannot be CurrentTime; use a real timestamp!
* @ping_reply_func: The callback to call if we get a response.
* @ping_timeout_func: The callback to call if we don't get a response.
* @user_data: Arbitrary data that will be passed to the callback
* function. (In practice it's often a pointer to
* the window.)
*
* Sends a ping request to a window. The window must respond to
* the request within a certain amount of time. If it does, we
* will call one callback; if the time passes and we haven't had
* a response, we call a different callback. The window must have
* the hint showing that it can respond to a ping; if it doesn't,
* we call the "got a response" callback immediately and return.
* This function returns straight away after setting things up;
* the callbacks will be called from the event loop.
*/
void
meta_display_ping_window (MetaWindow *window,
guint32 timestamp,
MetaWindowPingFunc ping_reply_func,
MetaWindowPingFunc ping_timeout_func,
gpointer user_data)
{
MetaDisplay *display = window->display;
MetaPingData *ping_data;
if (timestamp == CurrentTime)
{
meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n");
return;
}
if (!window->net_wm_ping)
{
if (ping_reply_func)
(* ping_reply_func) (window, timestamp, user_data);
return;
}
ping_data = g_new (MetaPingData, 1);
ping_data->window = window;
ping_data->timestamp = timestamp;
ping_data->ping_reply_func = ping_reply_func;
ping_data->ping_timeout_func = ping_timeout_func;
ping_data->user_data = user_data;
ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY,
meta_display_ping_timeout,
ping_data);
display->pending_pings = g_slist_prepend (display->pending_pings, ping_data);
meta_topic (META_DEBUG_PING,
"Sending ping with timestamp %u to window %s\n",
timestamp, window->desc);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_window_send_icccm_message (window,
display->atom__NET_WM_PING,
timestamp);
else
meta_wayland_surface_ping (window->surface, timestamp);
}
static void
process_request_frame_extents (MetaDisplay *display,
XEvent *event)
@@ -4889,6 +5072,56 @@ process_request_frame_extents (MetaDisplay *display,
meta_XFree (hints);
}
/**
* meta_display_pong_for_serial:
* @display: the display we got the pong from
* @serial: the serial in the pong repsonse
*
* Process the pong (the response message) from the ping we sent
* to the window. This involves removing the timeout, calling the
* reply handler function, and freeing memory.
*/
void
meta_display_pong_for_serial (MetaDisplay *display,
guint32 serial)
{
GSList *tmp;
meta_topic (META_DEBUG_PING, "Received a pong with serial %u\n", serial);
for (tmp = display->pending_pings; tmp; tmp = tmp->next)
{
MetaPingData *ping_data = tmp->data;
if (serial == ping_data->timestamp)
{
meta_topic (META_DEBUG_PING,
"Matching ping found for pong %u\n",
ping_data->timestamp);
/* Remove the ping data from the list */
display->pending_pings = g_slist_remove (display->pending_pings,
ping_data);
/* Remove the timeout */
if (ping_data->ping_timeout_id != 0)
{
g_source_remove (ping_data->ping_timeout_id);
ping_data->ping_timeout_id = 0;
}
/* Call callback */
(* ping_data->ping_reply_func) (ping_data->window,
ping_data->timestamp,
ping_data->user_data);
ping_data_free (ping_data);
break;
}
}
}
MetaGroup*
get_focussed_group (MetaDisplay *display)
{

View File

@@ -62,7 +62,6 @@ meta_window_ensure_frame (MetaWindow *window)
frame->right_width = 0;
frame->current_cursor = 0;
frame->mapped = FALSE;
frame->is_flashing = FALSE;
frame->borders_cached = FALSE;
@@ -157,6 +156,8 @@ meta_window_ensure_frame (MetaWindow *window)
/* Move keybindings to frame instead of window */
meta_window_grab_keys (window);
meta_ui_map_frame (frame->window->screen->ui, frame->xwindow);
}
void

View File

@@ -47,7 +47,6 @@ struct _MetaFrame
int right_width;
int bottom_height;
guint mapped : 1;
guint need_reapply_frame_shape : 1;
guint is_flashing : 1; /* used by the visual bell flash */
guint borders_cached : 1;

View File

@@ -41,6 +41,7 @@
#include "screen-private.h"
#include <meta/prefs.h>
#include "util-private.h"
#include "meta-wayland-private.h"
#include <X11/keysym.h>
#include <string.h>
@@ -51,10 +52,6 @@
#include <X11/XKBlib.h>
#endif
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings"
@@ -4079,7 +4076,6 @@ handle_set_spew_mark (MetaDisplay *display,
meta_verbose ("-- MARK MARK MARK MARK --\n");
}
#ifdef HAVE_WAYLAND
static void
handle_switch_vt (MetaDisplay *display,
MetaScreen *screen,
@@ -4098,7 +4094,6 @@ handle_switch_vt (MetaDisplay *display,
g_error_free (error);
}
}
#endif
/**
* meta_keybindings_set_custom_handler:
@@ -4403,7 +4398,6 @@ init_builtin_key_bindings (MetaDisplay *display)
META_KEYBINDING_ACTION_SET_SPEW_MARK,
handle_set_spew_mark, 0);
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
add_builtin_keybinding (display,
@@ -4455,7 +4449,6 @@ init_builtin_key_bindings (MetaDisplay *display)
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 7);
}
#endif
#undef REVERSES_AND_REVERSED

View File

@@ -254,19 +254,8 @@ meta_get_option_context (void)
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
/* We must set the windowing backend here, because Clutter creates the backend
object when the first call is made.
We consider running from mutter-launch equivalent to running from bare metal.
*/
if (getenv ("WESTON_LAUNCHER_SOCK"))
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
ctx = g_option_context_new (NULL);
g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE);
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
g_option_context_add_group (ctx, cogl_get_option_group ());
return ctx;
}
@@ -389,7 +378,8 @@ meta_init (void)
{
struct sigaction act;
sigset_t empty_mask;
ClutterSettings *clutter_settings;
sigemptyset (&empty_mask);
act.sa_handler = SIG_IGN;
act.sa_mask = empty_mask;
@@ -410,6 +400,10 @@ meta_init (void)
if (g_getenv ("MUTTER_DEBUG"))
meta_set_debugging (TRUE);
/* We consider running from mutter-launch equivalent to running from bare metal. */
if (getenv ("WESTON_LAUNCHER_SOCK"))
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
meta_set_is_wayland_compositor (opt_wayland);
if (g_get_home_dir ())
@@ -441,7 +435,7 @@ meta_init (void)
meta_fatal ("Can't specify both SM save file and SM client id\n");
meta_main_loop = g_main_loop_new (NULL, FALSE);
meta_ui_init ();
/* If we are running with wayland then we don't wait until we have
@@ -455,6 +449,13 @@ meta_init (void)
*/
meta_clutter_init ();
}
/*
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
* for now.
*/
clutter_settings = clutter_settings_get_default ();
g_object_set (clutter_settings, "window-scaling-factor", 1, NULL);
}
/**

View File

@@ -570,12 +570,14 @@ make_wayland_cursor_tracker (MetaScreen *screen)
compositor = meta_wayland_compositor_get_default ();
compositor->seat->cursor_tracker = self;
if (meta_wayland_compositor_is_native (compositor))
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
self->gbm = gbm_create_device (self->drm_fd);
}
#endif
monitors = meta_monitor_manager_get ();
g_signal_connect_object (monitors, "monitors-changed",
@@ -613,11 +615,9 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen)
if (screen->cursor_tracker)
return screen->cursor_tracker;
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
self = make_wayland_cursor_tracker (screen);
else
#endif
self = make_x11_cursor_tracker (screen);
screen->cursor_tracker = self;

View File

@@ -535,7 +535,7 @@ make_watch (MetaIdleMonitor *monitor,
watch->timeout_source = source;
}
}
else
else if (monitor->user_active_alarm != None)
{
if (timeout_msec != 0)
{

View File

@@ -42,9 +42,7 @@
#include <meta/screen.h>
#include "stack-tracker.h"
#include "ui.h"
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
#endif
#include "meta-xrandr-shared.h"
#include "meta-dbus-xrandr.h"
@@ -54,19 +52,6 @@ typedef struct _MetaMonitorManager MetaMonitorManager;
typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass;
typedef struct _MetaMonitorConfig MetaMonitorConfig;
#ifndef HAVE_WAYLAND
enum wl_output_transform {
WL_OUTPUT_TRANSFORM_NORMAL,
WL_OUTPUT_TRANSFORM_90,
WL_OUTPUT_TRANSFORM_180,
WL_OUTPUT_TRANSFORM_270,
WL_OUTPUT_TRANSFORM_FLIPPED,
WL_OUTPUT_TRANSFORM_FLIPPED_90,
WL_OUTPUT_TRANSFORM_FLIPPED_180,
WL_OUTPUT_TRANSFORM_FLIPPED_270
};
#endif
typedef struct _MetaOutput MetaOutput;
typedef struct _MetaCRTC MetaCRTC;
typedef struct _MetaMonitorMode MetaMonitorMode;

View File

@@ -356,19 +356,35 @@ make_logical_config (MetaMonitorManager *manager)
static GType
get_default_backend (void)
{
if (meta_is_wayland_compositor ())
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
return META_TYPE_MONITOR_MANAGER_KMS;
#endif
#if defined(CLUTTER_WINDOWING_X11)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
{
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
if (meta_wayland_compositor_is_native (compositor))
return META_TYPE_MONITOR_MANAGER_KMS;
else
/* If we're a Wayland compositor using the X11 backend,
* we're a nested configuration, so return the dummy
* monitor setup. */
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER;
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
#endif
#if defined(CLUTTER_WINDOWING_WAYLAND)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND))
{
/* Use the dummy implementation on Wayland for now.
* In the future, we should support wl_fullscreen_output
* which will have CRTC management in the protocol. */
return META_TYPE_MONITOR_MANAGER;
}
#endif
g_assert_not_reached ();
}
static MetaMonitorManager *

View File

@@ -389,6 +389,8 @@ int
meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
int index)
{
g_return_val_if_fail (index >= 0 && index < screen->n_monitor_infos, -1);
meta_screen_ensure_xinerama_indices (screen);
return screen->monitor_infos[index].xinerama_index;

View File

@@ -79,9 +79,7 @@ struct _MetaWindow
const MetaMonitorInfo *monitor;
MetaWorkspace *workspace;
MetaWindowClientType client_type;
#ifdef HAVE_WAYLAND
MetaWaylandSurface *surface;
#endif
Window xwindow;
/* may be NULL! not all windows get decorated */
MetaFrame *frame;
@@ -467,8 +465,6 @@ struct _MetaWindow
/* Bypass compositor hints */
guint bypass_compositor;
GSList *pending_pings;
};
struct _MetaWindowClass
@@ -733,6 +729,9 @@ void meta_window_set_transient_for (MetaWindow *window,
void meta_window_set_opacity (MetaWindow *window,
guint opacity);
void meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents);
void meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,
@@ -741,17 +740,6 @@ void meta_window_handle_enter (MetaWindow *window,
void meta_window_set_surface_mapped (MetaWindow *window,
gboolean surface_mapped);
typedef void (* MetaWindowPingFunc) (MetaWindow *window,
guint32 timestamp,
gpointer user_data);
void meta_window_ping (MetaWindow *window,
guint32 timestamp,
MetaWindowPingFunc ping_reply_func,
MetaWindowPingFunc ping_timeout_func,
void *user_data);
void meta_window_pong (MetaWindow *window,
guint32 timestamp);
Window meta_window_get_toplevel_xwindow (MetaWindow *window);
void meta_window_activate_full (MetaWindow *window,

View File

@@ -303,22 +303,18 @@ reload_gtk_frame_extents (MetaWindow *window,
}
else
{
GtkBorder *extents = &window->custom_frame_extents;
window->has_custom_frame_extents = TRUE;
extents->left = (int)value->v.cardinal_list.cardinals[0];
extents->right = (int)value->v.cardinal_list.cardinals[1];
extents->top = (int)value->v.cardinal_list.cardinals[2];
extents->bottom = (int)value->v.cardinal_list.cardinals[3];
GtkBorder extents;
extents.left = (int)value->v.cardinal_list.cardinals[0];
extents.right = (int)value->v.cardinal_list.cardinals[1];
extents.top = (int)value->v.cardinal_list.cardinals[2];
extents.bottom = (int)value->v.cardinal_list.cardinals[3];
meta_window_set_custom_frame_extents (window, &extents);
}
}
else
{
window->has_custom_frame_extents = FALSE;
meta_window_set_custom_frame_extents (window, NULL);
}
if (!initial)
meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
}
static void

View File

@@ -127,23 +127,35 @@ meta_window_x11_set_net_wm_state (MetaWindow *window)
if (window->fullscreen)
{
data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[0]);
data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[1]);
data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[2]);
data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[3]);
if (window->fullscreen_monitors[0] >= 0)
{
data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[0]);
data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[1]);
data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[2]);
data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen,
window->fullscreen_monitors[3]);
meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
meta_error_trap_push (window->display);
XChangeProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_FULLSCREEN_MONITORS,
XA_CARDINAL, 32, PropModeReplace,
(guchar*) data, 4);
meta_error_trap_pop (window->display);
meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
meta_error_trap_push (window->display);
XChangeProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_FULLSCREEN_MONITORS,
XA_CARDINAL, 32, PropModeReplace,
(guchar*) data, 4);
meta_error_trap_pop (window->display);
}
else
{
meta_verbose ("Clearing _NET_WM_FULLSCREEN_MONITORS\n");
meta_error_trap_push (window->display);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_FULLSCREEN_MONITORS);
meta_error_trap_pop (window->display);
}
}
}
@@ -377,9 +389,9 @@ meta_window_x11_update_input_region (MetaWindow *window)
if (n_rects > 1 ||
(n_rects == 1 &&
(rects[0].x != x_bounding ||
rects[1].y != y_bounding ||
rects[2].width != w_bounding ||
rects[3].height != h_bounding)))
rects[0].y != y_bounding ||
rects[0].width != w_bounding ||
rects[0].height != h_bounding)))
region = region_create_from_x_rectangles (rects, n_rects);
XFree (rects);

View File

@@ -69,26 +69,6 @@
static int destroying_windows_disallowed = 0;
/**
* MetaPingData:
*
* Describes a ping on a window. When we send a ping to a window, we build
* one of these structs, and it eventually gets passed to the timeout function
* or to the function which handles the response from the window. If the window
* does or doesn't respond to the ping, we use this information to deal with
* these facts; we have a handler function for each.
*/
typedef struct
{
MetaWindow *window;
guint32 timestamp;
MetaWindowPingFunc ping_reply_func;
MetaWindowPingFunc ping_timeout_func;
void *user_data;
guint ping_timeout_id;
} MetaPingData;
static void ping_data_free (MetaPingData *ping_data);
static void update_sm_hints (MetaWindow *window);
static void update_net_frame_extents (MetaWindow *window);
@@ -202,6 +182,8 @@ enum
FOCUS,
RAISED,
UNMANAGED,
SIZE_CHANGED,
POSITION_CHANGED,
LAST_SIGNAL
};
@@ -609,6 +591,40 @@ meta_window_class_init (MetaWindowClass *klass)
G_STRUCT_OFFSET (MetaWindowClass, unmanaged),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* MetaWindow::position-changed:
* @window: a #MetaWindow
*
* This is emitted when the position of a window might
* have changed. Specifically, this is emitted when the
* position of the toplevel window has changed, or when
* the position of the client window has changed.
*/
window_signals[POSITION_CHANGED] =
g_signal_new ("position-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* MetaWindow::size-changed:
* @window: a #MetaWindow
*
* This is emitted when the position of a window might
* have changed. Specifically, this is emitted when the
* size of the toplevel window has changed, or when the
* size of the client window has changed.
*/
window_signals[SIZE_CHANGED] =
g_signal_new ("size-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
@@ -688,6 +704,35 @@ meta_window_should_attach_to_parent (MetaWindow *window)
}
}
static gboolean
client_window_should_be_mapped (MetaWindow *window)
{
return !window->shaded;
}
static void
sync_client_window_mapped (MetaWindow *window)
{
gboolean should_be_mapped = client_window_should_be_mapped (window);
if (window->mapped == should_be_mapped)
return;
window->mapped = should_be_mapped;
meta_error_trap_push (window->display);
if (should_be_mapped)
{
XMapWindow (window->display->xdisplay, window->xwindow);
}
else
{
XUnmapWindow (window->display->xdisplay, window->xwindow);
window->unmaps_pending ++;
}
meta_error_trap_pop (window->display);
}
MetaWindow *
_meta_window_shared_new (MetaDisplay *display,
MetaScreen *screen,
@@ -1175,9 +1220,6 @@ _meta_window_shared_new (MetaDisplay *display,
set_net_wm_state (window);
}
if (screen->display->compositor)
meta_compositor_add_window (screen->display->compositor, window);
/* Sync stack changes */
meta_stack_thaw (window->screen->stack);
@@ -1191,6 +1233,8 @@ _meta_window_shared_new (MetaDisplay *display,
/* disable show desktop mode unless we're a desktop component */
maybe_leave_show_desktop_mode (window);
sync_client_window_mapped (window);
meta_window_queue (window, META_QUEUE_CALC_SHOWING);
/* See bug 303284; a transient of the given window can already exist, in which
* case we think it should probably be shown.
@@ -1454,6 +1498,9 @@ meta_window_unmanage (MetaWindow *window,
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
if (window->surface)
meta_wayland_surface_window_unmanaged (window->surface);
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
MetaStackWindow stack_window;
@@ -1719,8 +1766,6 @@ meta_window_unmanage (MetaWindow *window,
else
meta_display_unregister_wayland_window (window->display, window);
g_slist_free_full (window->pending_pings, (GDestroyNotify) ping_data_free);
meta_prefs_remove_listener (prefs_changed_callback, window);
meta_screen_queue_check_fullscreen (window->screen);
@@ -1932,6 +1977,8 @@ implement_showing (MetaWindow *window,
meta_verbose ("Implement showing = %d for window %s\n",
showing, window->desc);
sync_client_window_mapped (window);
if (!showing)
{
/* When we manage a new window, we normally delay placing it
@@ -2520,94 +2567,6 @@ window_would_be_covered (const MetaWindow *newbie)
return FALSE; /* none found */
}
static gboolean
map_frame (MetaWindow *window)
{
if (window->frame && !window->frame->mapped)
{
meta_topic (META_DEBUG_WINDOW_STATE,
"Frame actually needs map\n");
window->frame->mapped = TRUE;
meta_ui_map_frame (window->screen->ui, window->frame->xwindow);
return TRUE;
}
else
return FALSE;
}
static gboolean
map_client_window (MetaWindow *window)
{
if (!window->mapped)
{
meta_topic (META_DEBUG_WINDOW_STATE,
"%s actually needs map\n", window->desc);
window->mapped = TRUE;
meta_error_trap_push (window->display);
XMapWindow (window->display->xdisplay, window->xwindow);
meta_error_trap_pop (window->display);
return TRUE;
}
else
return FALSE;
}
static gboolean
unmap_client_window (MetaWindow *window,
const char *reason)
{
if (window->mapped)
{
meta_topic (META_DEBUG_WINDOW_STATE,
"%s actually needs unmap%s\n",
window->desc, reason);
meta_topic (META_DEBUG_WINDOW_STATE,
"Incrementing unmaps_pending on %s%s\n",
window->desc, reason);
window->mapped = FALSE;
window->unmaps_pending += 1;
meta_error_trap_push (window->display);
XUnmapWindow (window->display->xdisplay, window->xwindow);
meta_error_trap_pop (window->display);
return TRUE;
}
else
return FALSE;
}
/**
* meta_window_is_mapped:
* @window: a #MetaWindow
*
* Determines whether the X window for the MetaWindow is mapped.
*/
gboolean
meta_window_is_mapped (MetaWindow *window)
{
return window->mapped;
}
/**
* meta_window_toplevel_is_mapped:
* @window: a #MetaWindow
*
* Determines whether the toplevel X window for the MetaWindow is
* mapped. (The frame window is mapped even without the client window
* when a window is shaded.)
*
* Return Value: %TRUE if the toplevel is mapped.
*/
gboolean
meta_window_toplevel_is_mapped (MetaWindow *window)
{
/* The frame is mapped but not the client window when the window
* is shaded.
*/
return window->mapped || (window->frame && window->frame->mapped);
}
static void
meta_window_force_placement (MetaWindow *window)
{
@@ -2646,16 +2605,12 @@ meta_window_show (MetaWindow *window)
gboolean place_on_top_on_map;
gboolean needs_stacking_adjustment;
MetaWindow *focus_window;
gboolean toplevel_was_mapped;
gboolean toplevel_now_mapped;
gboolean notify_demands_attention = FALSE;
meta_topic (META_DEBUG_WINDOW_STATE,
"Showing window %s, shaded: %d iconic: %d placed: %d\n",
window->desc, window->shaded, window->iconic, window->placed);
toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
focus_window = window->display->focus_window; /* May be NULL! */
did_show = FALSE;
window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
@@ -2782,46 +2737,18 @@ meta_window_show (MetaWindow *window)
}
}
/* Shaded means the frame is mapped but the window is not */
if (map_frame (window))
did_show = TRUE;
if (window->shaded)
if (window->hidden)
{
unmap_client_window (window, " (shading)");
if (!window->iconic)
{
window->iconic = TRUE;
set_wm_state (window);
}
}
else
{
if (map_client_window (window))
did_show = TRUE;
if (window->hidden)
{
meta_stack_freeze (window->screen->stack);
window->hidden = FALSE;
meta_stack_thaw (window->screen->stack);
did_show = TRUE;
}
if (window->iconic)
{
window->iconic = FALSE;
set_wm_state (window);
}
meta_stack_freeze (window->screen->stack);
window->hidden = FALSE;
meta_stack_thaw (window->screen->stack);
did_show = TRUE;
}
toplevel_now_mapped = meta_window_toplevel_is_mapped (window);
if (toplevel_now_mapped != toplevel_was_mapped)
if (window->iconic)
{
if (window->display->compositor)
meta_compositor_window_mapped (window->display->compositor, window);
window->iconic = FALSE;
set_wm_state (window);
}
if (!window->visible_to_compositor)
@@ -2844,8 +2771,8 @@ meta_window_show (MetaWindow *window)
break;
}
meta_compositor_show_window (window->display->compositor,
window, effect);
meta_compositor_add_window (window->display->compositor, window);
meta_compositor_show_window (window->display->compositor, window, effect);
}
}
@@ -2913,14 +2840,10 @@ static void
meta_window_hide (MetaWindow *window)
{
gboolean did_hide;
gboolean toplevel_was_mapped;
gboolean toplevel_now_mapped;
meta_topic (META_DEBUG_WINDOW_STATE,
"Hiding window %s\n", window->desc);
toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
if (window->visible_to_compositor)
{
window->visible_to_compositor = FALSE;
@@ -2941,19 +2864,12 @@ meta_window_hide (MetaWindow *window)
break;
}
meta_compositor_hide_window (window->display->compositor,
window, effect);
meta_compositor_hide_window (window->display->compositor, window, effect);
}
}
did_hide = FALSE;
/* If this is the first time that we've calculating the showing
* state of the window, the frame and client window might not
* yet be mapped, so we need to map them now */
map_frame (window);
map_client_window (window);
if (!window->hidden)
{
meta_stack_freeze (window->screen->stack);
@@ -2969,19 +2885,6 @@ meta_window_hide (MetaWindow *window)
set_wm_state (window);
}
toplevel_now_mapped = meta_window_toplevel_is_mapped (window);
if (toplevel_now_mapped != toplevel_was_mapped)
{
if (window->display->compositor)
{
/* As above, we may be *mapping* live hidden windows */
if (toplevel_now_mapped)
meta_compositor_window_mapped (window->display->compositor, window);
else
meta_compositor_window_unmapped (window->display->compositor, window);
}
}
set_net_wm_state (window);
if (did_hide && window->struts)
@@ -3213,6 +3116,9 @@ meta_window_maximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (window->surface && window->maximized_horizontally && window->maximized_vertically)
meta_wayland_surface_send_maximized (window->surface);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically");
@@ -3698,10 +3604,13 @@ meta_window_unmaximize_internal (MetaWindow *window,
set_net_wm_state (window);
}
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically");
g_object_thaw_notify (G_OBJECT (window));
if (window->surface && !window->maximized_horizontally && !window->maximized_vertically)
meta_wayland_surface_send_unmaximized (window->surface);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically");
g_object_thaw_notify (G_OBJECT (window));
}
void
@@ -3804,6 +3713,9 @@ meta_window_make_fullscreen_internal (MetaWindow *window)
/* For the auto-minimize feature, if we fail to get focus */
meta_screen_queue_check_fullscreen (window->screen);
if (window->surface)
meta_wayland_surface_send_fullscreened (window->surface);
g_object_notify (G_OBJECT (window), "fullscreen");
}
}
@@ -3860,6 +3772,9 @@ meta_window_unmake_fullscreen (MetaWindow *window)
meta_window_update_layer (window);
if (window->surface)
meta_wayland_surface_send_unfullscreened (window->surface);
g_object_notify (G_OBJECT (window), "fullscreen");
}
}
@@ -4741,9 +4656,7 @@ meta_window_move_resize_internal (MetaWindow *window,
need_resize_client = TRUE;
meta_wayland_surface_configure_notify (window->surface,
new_rect.width,
new_rect.height,
(dx != 0 ? WL_SHELL_SURFACE_RESIZE_LEFT : 0) |
(dy != 0 ? WL_SHELL_SURFACE_RESIZE_TOP : 0));
new_rect.height);
}
else
{
@@ -5070,6 +4983,12 @@ meta_window_move_resize_internal (MetaWindow *window,
else if (is_user_action)
save_user_window_placement (window);
if (need_move_client || need_move_frame)
g_signal_emit (window, window_signals[POSITION_CHANGED], 0);
if (need_resize_client || need_resize_frame)
g_signal_emit (window, window_signals[SIZE_CHANGED], 0);
if (need_move_frame || need_resize_frame ||
need_move_client || need_resize_client ||
did_placement || is_wayland_resize)
@@ -6815,7 +6734,7 @@ redraw_icon (MetaWindow *window)
/* We could probably be smart and just redraw the icon here,
* instead of the whole frame.
*/
if (window->frame && (window->mapped || window->frame->mapped))
if (window->frame)
meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
}
@@ -10687,200 +10606,25 @@ meta_window_set_surface_mapped (MetaWindow *window,
meta_window_queue (window, META_QUEUE_CALC_SHOWING);
}
/*
* SECTION:pings
*
* Sometimes we want to see whether a window is responding,
* so we send it a "ping" message and see whether it sends us back a "pong"
* message within a reasonable time. Here we have a system which lets us
* nominate one function to be called if we get the pong in time and another
* function if we don't. The system is rather more complicated than it needs
* to be, since we only ever use it to destroy windows which are asked to
* close themselves and don't do so within a reasonable amount of time, and
* therefore we always use the same callbacks. It's possible that we might
* use it for other things in future, or on the other hand we might decide
* that we're never going to do so and simplify it a bit.
*/
/**
* ping_data_free:
*
* Destructor for #MetaPingData structs. Will destroy the
* event source for the struct as well.
*/
static void
ping_data_free (MetaPingData *ping_data)
{
MetaWindow *window = ping_data->window;
MetaDisplay *display = window->display;
/* Remove the timeout */
if (ping_data->ping_timeout_id != 0)
g_source_remove (ping_data->ping_timeout_id);
g_hash_table_remove (display->pending_pings, &ping_data->timestamp);
g_free (ping_data);
}
/**
* meta_window_pong:
* @window: the window we got the pong on
* @timestamp: the timestamp that the client sent back
*
* Process the pong (the response message) from the ping we sent
* to the window. This involves removing the timeout, calling the
* reply handler function, and freeing memory.
*/
void
meta_window_pong (MetaWindow *window,
guint32 timestamp)
{
GSList *tmp;
meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n",
timestamp);
for (tmp = window->pending_pings; tmp; tmp = tmp->next)
{
MetaPingData *ping_data = tmp->data;
if (timestamp == ping_data->timestamp)
{
meta_topic (META_DEBUG_PING,
"Matching ping found for pong %u\n",
ping_data->timestamp);
/* Remove the ping data from the list */
window->pending_pings = g_slist_remove (window->pending_pings, ping_data);
/* Remove the timeout */
if (ping_data->ping_timeout_id != 0)
{
g_source_remove (ping_data->ping_timeout_id);
ping_data->ping_timeout_id = 0;
}
/* Call callback */
(* ping_data->ping_reply_func) (window,
ping_data->timestamp,
ping_data->user_data);
ping_data_free (ping_data);
break;
}
}
}
/*
* How long, in milliseconds, we should wait after pinging a window
* before deciding it's not going to get back to us.
*/
#define PING_TIMEOUT_DELAY 5000
/**
* ping_timeout:
* @data: All the information about this ping. It is a #MetaPingData
* cast to a #gpointer in order to be passable to a timeout function.
* This function will also free this parameter.
*
* Does whatever it is we decided to do when a window didn't respond
* to a ping. We also remove the ping from the display's list of
* pending pings. This function is called by the event loop when the timeout
* times out which we created at the start of the ping.
*
* Returns: Always returns %FALSE, because this function is called as a
* timeout and we don't want to run the timer again.
*/
static gboolean
ping_timeout (gpointer data)
{
MetaPingData *ping_data;
ping_data = data;
ping_data->ping_timeout_id = 0;
meta_topic (META_DEBUG_PING,
"Ping %u on window %s timed out\n",
ping_data->timestamp, ping_data->window->desc);
(* ping_data->ping_timeout_func) (ping_data->window, ping_data->timestamp, ping_data->user_data);
ping_data_free (ping_data);
return FALSE;
}
/**
* meta_window_ping:
* @window: The #MetaWindow to send the ping to
* @timestamp: The timestamp of the ping. Used for uniqueness.
* Cannot be CurrentTime; use a real timestamp!
* @ping_reply_func: The callback to call if we get a response.
* @ping_timeout_func: The callback to call if we don't get a response.
* @user_data: Arbitrary data that will be passed to the callback
* function. (In practice it's often a pointer to
* the window.)
*
* Sends a ping request to a window. The window must respond to
* the request within a certain amount of time. If it does, we
* will call one callback; if the time passes and we haven't had
* a response, we call a different callback. The window must have
* the hint showing that it can respond to a ping; if it doesn't,
* we call the "got a response" callback immediately and return.
* This function returns straight away after setting things up;
* the callbacks will be called from the event loop.
*/
void
meta_window_ping (MetaWindow *window,
guint32 timestamp,
MetaWindowPingFunc ping_reply_func,
MetaWindowPingFunc ping_timeout_func,
gpointer user_data)
{
MetaPingData *ping_data;
MetaDisplay *display = window->display;
if (timestamp == CurrentTime)
{
meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n");
return;
}
if (!window->net_wm_ping)
{
if (ping_reply_func)
(* ping_reply_func) (window, timestamp, user_data);
return;
}
ping_data = g_new (MetaPingData, 1);
ping_data->window = window;
ping_data->timestamp = timestamp;
ping_data->ping_reply_func = ping_reply_func;
ping_data->ping_timeout_func = ping_timeout_func;
ping_data->user_data = user_data;
ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY, ping_timeout, ping_data);
window->pending_pings = g_slist_prepend (window->pending_pings, ping_data);
g_hash_table_insert (display->pending_pings, &ping_data->timestamp, window);
meta_topic (META_DEBUG_PING,
"Sending ping with timestamp %u to window %s\n",
timestamp, window->desc);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_window_send_icccm_message (window, display->atom__NET_WM_PING, timestamp);
else
meta_wayland_surface_ping (window->surface, timestamp);
}
Window
meta_window_get_toplevel_xwindow (MetaWindow *window)
{
return window->frame ? window->frame->xwindow : window->xwindow;
}
void
meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents)
{
if (extents)
{
window->has_custom_frame_extents = TRUE;
window->custom_frame_extents = *extents;
}
else
{
window->has_custom_frame_extents = FALSE;
}
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
}

View File

@@ -75,11 +75,10 @@ gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor,
MetaScreen *screen,
MetaKeyBinding *binding);
void meta_compositor_add_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_remove_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_add_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_remove_window (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_show_window (MetaCompositor *compositor,
MetaWindow *window,
MetaCompEffect effect);
@@ -101,10 +100,6 @@ void meta_compositor_unmaximize_window (MetaCompositor *compositor,
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_compositor_window_mapped (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_unmapped (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
MetaWindow *window,
gboolean did_placement);

View File

@@ -69,8 +69,7 @@ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region);
int height);
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);

View File

@@ -189,8 +189,6 @@ gboolean meta_window_requested_bypass_compositor (MetaWindow *window);
gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window);
gint *meta_window_get_all_monitors (MetaWindow *window, gsize *length);
gboolean meta_window_is_mapped (MetaWindow *window);
gboolean meta_window_toplevel_is_mapped (MetaWindow *window);
gboolean meta_window_get_icon_geometry (MetaWindow *window,
MetaRectangle *rect);
void meta_window_set_icon_geometry (MetaWindow *window,

View File

@@ -115,7 +115,7 @@ inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard,
struct wl_resource *keyboard_resource;
compositor = meta_wayland_compositor_get_default ();
xclient = compositor->xwayland_client;
xclient = compositor->xwayland_manager.client;
wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
{
@@ -201,13 +201,17 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
strcpy (xkb_info->keymap_area, keymap_str);
free (keymap_str);
if (keyboard->is_evdev)
#if defined(CLUTTER_WINDOWING_EGL)
/* XXX -- the evdev backend can be used regardless of the
* windowing backend. To do this properly we need a Clutter
* API to check the input backend. */
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
ClutterDeviceManager *manager;
manager = clutter_device_manager_get_default ();
clutter_evdev_set_keyboard_map (manager, xkb_info->keymap);
}
#endif
inform_clients_of_new_keymap (keyboard, flags);
@@ -222,13 +226,27 @@ err_keymap_str:
}
static void
lose_keyboard_focus (struct wl_listener *listener, void *data)
release_focus (MetaWaylandKeyboard *keyboard)
{
MetaWaylandKeyboard *keyboard =
wl_container_of (listener, keyboard, focus_listener);
wl_list_remove (&keyboard->focus_surface_listener.link);
wl_list_remove (&keyboard->focus_resource_listener.link);
keyboard->focus_resource = NULL;
keyboard->focus = NULL;
keyboard->focus_surface = NULL;
}
static void
keyboard_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_surface_listener);
release_focus (keyboard);
}
static void
keyboard_handle_focus_resource_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_resource_listener);
release_focus (keyboard);
}
static gboolean
@@ -284,10 +302,9 @@ default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
wl_keyboard_send_modifiers (resource, serial, mods_depressed,
mods_latched, mods_locked, group);
if (pointer && pointer->focus && pointer->focus != keyboard->focus)
if (pointer && pointer->focus_surface && pointer->focus_surface != keyboard->focus_surface)
{
pr = find_resource_for_surface (&keyboard->resource_list,
pointer->focus);
pr = find_resource_for_surface (&keyboard->resource_list, pointer->focus_surface);
if (pr)
{
wl_keyboard_send_modifiers (pr, serial,
@@ -332,15 +349,17 @@ static MetaWaylandKeyboardGrabInterface modal_grab = {
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display,
gboolean is_evdev)
struct wl_display *display)
{
memset (keyboard, 0, sizeof *keyboard);
keyboard->xkb_info.keymap_fd = -1;
wl_list_init (&keyboard->resource_list);
wl_array_init (&keyboard->keys);
keyboard->focus_listener.notify = lose_keyboard_focus;
keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy;
keyboard->focus_resource_listener.notify = keyboard_handle_focus_resource_destroy;
keyboard->default_grab.interface = &default_keyboard_grab_interface;
keyboard->default_grab.keyboard = keyboard;
keyboard->grab = &keyboard->default_grab;
@@ -348,7 +367,6 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->display = display;
keyboard->xkb_context = xkb_context_new (0 /* flags */);
keyboard->is_evdev = is_evdev;
/* Compute a default until gnome-settings-daemon starts and sets
the appropriate values
@@ -512,19 +530,27 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
struct wl_resource *resource;
uint32_t serial;
if (keyboard->focus == surface && keyboard->focus_resource != NULL)
if (keyboard->focus_surface == surface && keyboard->focus_resource != NULL)
return;
resource = keyboard->focus_resource;
if (keyboard->focus_resource && keyboard->focus->resource)
if (resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
wl_list_remove (&keyboard->focus_listener.link);
if (keyboard->focus_surface->resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
wl_keyboard_send_leave (resource, serial, keyboard->focus_surface->resource);
meta_wayland_surface_focused_unset (keyboard->focus);
meta_wayland_surface_deactivated (keyboard->focus_surface);
}
wl_list_remove (&keyboard->focus_resource_listener.link);
wl_list_remove (&keyboard->focus_surface_listener.link);
keyboard->focus_resource = NULL;
keyboard->focus_surface = NULL;
}
resource = find_resource_for_surface (&keyboard->resource_list, surface);
@@ -557,14 +583,17 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
wl_keyboard_send_enter (resource, serial, surface->resource,
&keyboard->keys);
}
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
meta_wayland_surface_activated (surface);
keyboard->focus_resource = resource;
keyboard->focus_surface = surface;
wl_resource_add_destroy_listener (keyboard->focus_resource, &keyboard->focus_resource_listener);
wl_resource_add_destroy_listener (keyboard->focus_surface->resource, &keyboard->focus_surface_listener);
keyboard->focus_serial = serial;
meta_wayland_surface_focused_set (surface);
}
keyboard->focus_resource = resource;
keyboard->focus = surface;
}
void
@@ -590,8 +619,6 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
xkb_context_unref (keyboard->xkb_context);
/* XXX: What about keyboard->resource_list? */
if (keyboard->focus_resource)
wl_list_remove (&keyboard->focus_listener.link);
wl_array_release (&keyboard->keys);
}
@@ -610,7 +637,7 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
if (keyboard->grab != &keyboard->default_grab)
return FALSE;
if (keyboard->focus)
if (keyboard->focus_surface)
{
/* Fake key release events for the focused app */
serial = wl_display_next_serial (keyboard->display);
@@ -652,7 +679,7 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
meta_wayland_keyboard_end_grab (keyboard);
g_slice_free (MetaWaylandKeyboardGrab, grab);
if (keyboard->focus)
if (keyboard->focus_surface)
{
/* Fake key press events for the focused app */
serial = wl_display_next_serial (keyboard->display);

View File

@@ -92,9 +92,11 @@ typedef struct
struct _MetaWaylandKeyboard
{
struct wl_list resource_list;
MetaWaylandSurface *focus;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
struct wl_listener focus_resource_listener;
uint32_t focus_serial;
MetaWaylandKeyboardGrab *grab;
@@ -110,7 +112,6 @@ struct _MetaWaylandKeyboard
struct wl_display *display;
struct xkb_context *xkb_context;
gboolean is_evdev;
MetaWaylandXkbInfo xkb_info;
MetaWaylandKeyboardGrab input_method_grab;
@@ -119,8 +120,7 @@ struct _MetaWaylandKeyboard
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display,
gboolean is_evdev);
struct wl_display *display);
typedef enum {
META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1,

View File

@@ -64,13 +64,27 @@ meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
}
static void
lose_pointer_focus (struct wl_listener *listener, void *data)
release_focus (MetaWaylandPointer *pointer)
{
MetaWaylandPointer *pointer =
wl_container_of (listener, pointer, focus_listener);
wl_list_remove (&pointer->focus_surface_listener.link);
wl_list_remove (&pointer->focus_resource_listener.link);
pointer->focus_resource = NULL;
pointer->focus = NULL;
pointer->focus_surface = NULL;
}
static void
pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener);
release_focus (pointer);
}
static void
pointer_handle_focus_resource_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_resource_listener);
release_focus (pointer);
}
static void
@@ -98,7 +112,7 @@ default_grab_motion (MetaWaylandPointerGrab *grab,
wl_fixed_t sx, sy;
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
grab->pointer->focus,
grab->pointer->focus_surface,
&sx, &sy);
wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy);
}
@@ -258,8 +272,7 @@ pointer_constrain_callback (ClutterInputDevice *device,
}
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
gboolean is_native)
meta_wayland_pointer_init (MetaWaylandPointer *pointer)
{
ClutterDeviceManager *manager;
ClutterInputDevice *device;
@@ -267,7 +280,10 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
memset (pointer, 0, sizeof *pointer);
wl_list_init (&pointer->resource_list);
pointer->focus_listener.notify = lose_pointer_focus;
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
pointer->focus_resource_listener.notify = pointer_handle_focus_resource_destroy;
pointer->default_grab.interface = &default_pointer_grab_interface;
pointer->default_grab.pointer = pointer;
pointer->grab = &pointer->default_grab;
@@ -275,9 +291,16 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
manager = clutter_device_manager_get_default ();
device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
if (is_native)
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
pointer, NULL);
#if defined(CLUTTER_WINDOWING_EGL)
/* XXX -- the evdev backend can be used regardless of the
* windowing backend. To do this properly we need a Clutter
* API to check the input backend. */
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
pointer, NULL);
}
#endif
clutter_input_device_get_coords (device, NULL, &current);
pointer->x = wl_fixed_from_double (current.x);
@@ -287,12 +310,7 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
{
/* XXX: What about pointer->resource_list? */
if (pointer->focus_resource)
wl_list_remove (&pointer->focus_listener.link);
pointer->focus = NULL;
pointer->focus_resource = NULL;
release_focus (pointer);
}
static struct wl_resource *
@@ -318,21 +336,25 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
struct wl_resource *resource, *kr;
uint32_t serial;
if (pointer->focus == surface && pointer->focus_resource != NULL)
if (pointer->focus_surface == surface && pointer->focus_resource != NULL)
return;
resource = pointer->focus_resource;
if (resource)
{
if (pointer->focus->resource)
if (pointer->focus_surface->resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
wl_pointer_send_leave (resource, serial, pointer->focus->resource);
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
}
wl_list_remove (&pointer->focus_listener.link);
wl_list_remove (&pointer->focus_surface_listener.link);
wl_list_remove (&pointer->focus_resource_listener.link);
pointer->focus_surface = NULL;
pointer->focus_resource = NULL;
}
resource = find_resource_for_surface (&pointer->resource_list, surface);
@@ -365,12 +387,15 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
wl_fixed_to_int (pointer->x),
wl_fixed_to_int (pointer->y));
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
pointer->focus_resource = resource;
pointer->focus_surface = surface;
wl_resource_add_destroy_listener (pointer->focus_resource, &pointer->focus_resource_listener);
wl_resource_add_destroy_listener (pointer->focus_surface->resource, &pointer->focus_surface_listener);
pointer->focus_serial = serial;
}
pointer->focus_resource = resource;
pointer->focus = surface;
}
void
@@ -567,15 +592,13 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
if (pointer->grab != &pointer->default_grab)
{
if (pointer->grab->interface == &popup_grab_interface)
{
grab = (MetaWaylandPopupGrab*)pointer->grab;
if (pointer->grab->interface != &popup_grab_interface)
return FALSE;
if (wl_resource_get_client (surface->resource) != grab->grab_client)
return FALSE;
}
grab = (MetaWaylandPopupGrab*)pointer->grab;
return FALSE;
if (wl_resource_get_client (surface->resource) != grab->grab_client)
return FALSE;
}
if (pointer->grab == &pointer->default_grab)

View File

@@ -46,9 +46,11 @@ struct _MetaWaylandPointerGrab
struct _MetaWaylandPointer
{
struct wl_list resource_list;
MetaWaylandSurface *focus;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
struct wl_listener focus_resource_listener;
guint32 focus_serial;
guint32 click_serial;
@@ -67,8 +69,7 @@ struct _MetaWaylandPointer
};
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
gboolean is_native);
meta_wayland_pointer_init (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer);

View File

@@ -59,28 +59,34 @@ typedef struct
struct wl_resource *resource;
} MetaWaylandFrameCallback;
typedef struct
{
int display_index;
char *lockfile;
int abstract_fd;
int unix_fd;
pid_t pid;
struct wl_client *client;
struct wl_resource *xserver_resource;
char *display_name;
GMainLoop *init_loop;
} MetaXWaylandManager;
struct _MetaWaylandCompositor
{
struct wl_display *wayland_display;
char *display_name;
struct wl_event_loop *wayland_loop;
GMainLoop *init_loop;
ClutterActor *stage;
GHashTable *outputs;
GSource *wayland_event_source;
GList *surfaces;
struct wl_list frame_callbacks;
int xwayland_display_index;
char *xwayland_lockfile;
int xwayland_abstract_fd;
int xwayland_unix_fd;
pid_t xwayland_pid;
struct wl_client *xwayland_client;
struct wl_resource *xserver_resource;
MetaXWaylandManager xwayland_manager;
MetaLauncher *launcher;
gboolean native;
MetaWaylandSeat *seat;
};
@@ -99,8 +105,6 @@ void meta_wayland_compositor_set_input_focus (MetaWaylandComp
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
gboolean meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor);
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);

View File

@@ -95,9 +95,9 @@ pointer_set_cursor (struct wl_client *client,
surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
if (seat->pointer.focus == NULL)
if (seat->pointer.focus_surface == NULL)
return;
if (wl_resource_get_client (seat->pointer.focus->resource) != client)
if (wl_resource_get_client (seat->pointer.focus_surface->resource) != client)
return;
if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2)
return;
@@ -125,9 +125,9 @@ seat_get_pointer (struct wl_client *client,
wl_resource_set_implementation (cr, &pointer_interface, seat, unbind_resource);
wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr));
if (seat->pointer.focus &&
wl_resource_get_client (seat->pointer.focus->resource) == client)
meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus);
if (seat->pointer.focus_surface &&
wl_resource_get_client (seat->pointer.focus_surface->resource) == client)
meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus_surface);
}
static void
@@ -148,10 +148,10 @@ seat_get_keyboard (struct wl_client *client,
seat->keyboard.xkb_info.keymap_fd,
seat->keyboard.xkb_info.keymap_size);
if (seat->keyboard.focus &&
wl_resource_get_client (seat->keyboard.focus->resource) == client)
if (seat->keyboard.focus_surface &&
wl_resource_get_client (seat->keyboard.focus_surface->resource) == client)
{
meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus);
meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus_surface);
meta_wayland_data_device_set_keyboard_focus (seat);
}
}
@@ -204,8 +204,7 @@ pointer_handle_cursor_surface_destroy (struct wl_listener *listener, void *data)
}
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native)
meta_wayland_seat_new (struct wl_display *display)
{
MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
@@ -213,9 +212,8 @@ meta_wayland_seat_new (struct wl_display *display,
wl_list_init (&seat->base_resource_list);
wl_list_init (&seat->data_device_resource_list);
meta_wayland_pointer_init (&seat->pointer, is_native);
meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
meta_wayland_pointer_init (&seat->pointer);
meta_wayland_keyboard_init (&seat->keyboard, display);
seat->display = display;
@@ -431,7 +429,7 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
}
pointer->current = surface;
if (surface != pointer->focus)
if (surface != pointer->focus_surface)
{
const MetaWaylandPointerGrabInterface *interface =
pointer->grab->interface;

View File

@@ -74,8 +74,7 @@ struct _MetaWaylandSeat
};
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native);
meta_wayland_seat_new (struct wl_display *display);
void
meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,

View File

@@ -115,11 +115,7 @@ surface_process_damage (MetaWaylandSurface *surface,
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
meta_surface_actor_damage_area (surface->surface_actor,
rect.x,
rect.y,
rect.width,
rect.height,
NULL);
rect.x, rect.y, rect.width, rect.height);
}
}
@@ -340,6 +336,9 @@ toplevel_surface_commit (MetaWaylandSurface *surface,
meta_window_move_resize_wayland (window, new_width, new_height, pending->dx, pending->dy);
}
}
if (pending->frame_extents_changed)
meta_window_set_custom_frame_extents (surface->window, &pending->frame_extents);
}
static void
@@ -363,6 +362,8 @@ double_buffered_state_init (MetaWaylandDoubleBufferedState *state)
state->buffer_destroy_listener.notify =
surface_handle_pending_buffer_destroy;
wl_list_init (&state->frame_callback_list);
state->frame_extents_changed = FALSE;
}
static void
@@ -554,23 +555,6 @@ const struct wl_surface_interface meta_wayland_surface_interface = {
meta_wayland_surface_set_buffer_scale
};
static void
meta_wayland_surface_free (MetaWaylandSurface *surface)
{
MetaWaylandCompositor *compositor = surface->compositor;
compositor->surfaces = g_list_remove (compositor->surfaces, surface);
surface_set_buffer (surface, NULL);
double_buffered_state_destroy (&surface->pending);
g_object_unref (surface->surface_actor);
if (surface->resource)
wl_resource_set_user_data (surface->resource, NULL);
g_slice_free (MetaWaylandSurface, surface);
meta_wayland_compositor_repick (compositor);
}
static void
unparent_actor (MetaWaylandSurface *surface)
{
@@ -580,46 +564,53 @@ unparent_actor (MetaWaylandSurface *surface)
clutter_actor_remove_child (parent_actor, CLUTTER_ACTOR (surface->surface_actor));
}
void
meta_wayland_surface_window_unmanaged (MetaWaylandSurface *surface)
{
/* The window is being unmanaged. Unparent our surface actor
* before the window actor is destroyed, as we need to hold
* onto it... */
unparent_actor (surface);
surface->window = NULL;
}
static void
destroy_window (MetaWaylandSurface *surface)
{
MetaDisplay *display = meta_get_display ();
guint32 timestamp = meta_display_get_current_time_roundtrip (display);
/* Remove our actor from the parent, so it doesn't get destroyed when
* the MetaWindowActor is destroyed. */
unparent_actor (surface);
g_assert (surface->window != NULL);
meta_window_unmanage (surface->window, timestamp);
surface->window = NULL;
g_assert (surface->window == NULL);
}
static void
meta_wayland_surface_resource_destroy_cb (struct wl_resource *resource)
wl_surface_destructor (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
MetaWaylandCompositor *compositor = surface->compositor;
/* There are four cases here:
- An X11 unmanaged window -> surface is NULL, nothing to do
- An X11 unmanaged window, but we got the wayland event first ->
just clear the resource pointer
- A wayland surface without window (destroyed before set_toplevel) ->
need to free the surface itself
- A wayland window -> need to unmanage
*/
/* At the time when the wl_surface is destroyed, we should
* no longer have a window, unless we're an XWayland window
* in which case we received the wl_surface.destroy before
* the UnmapNotify/DestroyNotify. */
g_assert (surface->window == NULL || surface->window->client_type == META_WINDOW_CLIENT_TYPE_X11);
if (surface)
{
surface->resource = NULL;
compositor->surfaces = g_list_remove (compositor->surfaces, surface);
/* NB: If the surface corresponds to an X window then we will be
* sure to free the MetaWindow according to some X event. */
if (surface->window && surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
destroy_window (surface);
surface_set_buffer (surface, NULL);
double_buffered_state_destroy (&surface->pending);
meta_wayland_surface_free (surface);
}
clutter_actor_destroy (CLUTTER_ACTOR (surface->surface_actor));
g_object_unref (surface->surface_actor);
if (surface->resource)
wl_resource_set_user_data (surface->resource, NULL);
g_slice_free (MetaWaylandSurface, surface);
meta_wayland_compositor_repick (compositor);
}
MetaWaylandSurface *
@@ -633,14 +624,13 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
surface->compositor = compositor;
surface->resource = wl_resource_create (client, &wl_surface_interface, version, id);
wl_resource_set_implementation (surface->resource, &meta_wayland_surface_interface, surface,
meta_wayland_surface_resource_destroy_cb);
wl_resource_set_implementation (surface->resource, &meta_wayland_surface_interface, surface, wl_surface_destructor);
surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy;
surface->surface_actor = g_object_ref_sink (meta_surface_actor_new ());
double_buffered_state_init (&surface->pending);
surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy;
surface->surface_actor = g_object_ref_sink (meta_surface_actor_new ());
return surface;
}
@@ -689,6 +679,25 @@ create_surface_extension (MetaWaylandSurfaceExtension *extension,
return TRUE;
}
static void
xdg_shell_use_unstable_version (struct wl_client *client,
struct wl_resource *resource,
int32_t version)
{
if (version != XDG_SHELL_VERSION_CURRENT)
g_warning ("Bad xdg_shell version: %d", version);
}
static void
xdg_shell_pong (struct wl_client *client,
struct wl_resource *resource,
uint32_t serial)
{
MetaDisplay *display = meta_get_display ();
meta_display_pong_for_serial (display, serial);
}
static void
xdg_surface_destructor (struct wl_resource *resource)
{
@@ -724,6 +733,24 @@ xdg_surface_set_transient_for (struct wl_client *client,
meta_window_set_transient_for (surface->window, transient_for);
}
static void
xdg_surface_set_margin (struct wl_client *client,
struct wl_resource *resource,
int32_t left_margin,
int32_t right_margin,
int32_t top_margin,
int32_t bottom_margin)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
surface->pending.frame_extents_changed = TRUE;
surface->pending.frame_extents.left = left_margin;
surface->pending.frame_extents.right = right_margin;
surface->pending.frame_extents.top = top_margin;
surface->pending.frame_extents.bottom = bottom_margin;
}
static void
xdg_surface_set_title (struct wl_client *client,
struct wl_resource *resource,
@@ -746,17 +773,6 @@ xdg_surface_set_app_id (struct wl_client *client,
meta_window_set_wm_class (surface->window, app_id, app_id);
}
static void
xdg_surface_pong (struct wl_client *client,
struct wl_resource *resource,
guint32 serial)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
meta_window_pong (surface->window, serial);
}
static gboolean
begin_grab_op_on_surface (MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
@@ -792,7 +808,7 @@ xdg_surface_move (struct wl_client *client,
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
seat->pointer.focus != surface)
seat->pointer.focus_surface != surface)
return;
begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING);
@@ -838,7 +854,7 @@ xdg_surface_resize (struct wl_client *client,
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
seat->pointer.focus != surface)
seat->pointer.focus_surface != surface)
return;
begin_grab_op_on_surface (surface, seat, grab_op_for_edge (edges));
@@ -853,43 +869,45 @@ xdg_surface_set_output (struct wl_client *client,
}
static void
xdg_surface_set_fullscreen (struct wl_client *client,
struct wl_resource *resource)
xdg_surface_request_change_state (struct wl_client *client,
struct wl_resource *resource,
uint32_t state_type,
uint32_t value,
uint32_t serial)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
meta_window_make_fullscreen (surface->window);
surface->state_changed_serial = serial;
switch (state_type)
{
case XDG_SURFACE_STATE_TYPE_MAXIMIZED:
if (value)
meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
else
meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
break;
case XDG_SURFACE_STATE_TYPE_FULLSCREEN:
if (value)
meta_window_make_fullscreen (surface->window);
else
meta_window_unmake_fullscreen (surface->window);
}
}
static void
xdg_surface_unset_fullscreen (struct wl_client *client,
struct wl_resource *resource)
xdg_surface_ack_change_state (struct wl_client *client,
struct wl_resource *resource,
uint32_t state_type,
uint32_t value,
uint32_t serial)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
meta_window_unmake_fullscreen (surface->window);
}
static void
xdg_surface_set_maximized (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
}
static void
xdg_surface_unset_maximized (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
/* Do nothing for now. In the future, we'd imagine that
* we'd ignore attaches when we have a state pending that
* we haven't had the client ACK'd, to prevent a race
* condition when we have an in-flight attach when the
* client gets the new state. */
}
static void
@@ -905,33 +923,22 @@ xdg_surface_set_minimized (struct wl_client *client,
static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = {
xdg_surface_destroy,
xdg_surface_set_transient_for,
xdg_surface_set_margin,
xdg_surface_set_title,
xdg_surface_set_app_id,
xdg_surface_pong,
xdg_surface_move,
xdg_surface_resize,
xdg_surface_set_output,
xdg_surface_set_fullscreen,
xdg_surface_unset_fullscreen,
xdg_surface_set_maximized,
xdg_surface_unset_maximized,
xdg_surface_request_change_state,
xdg_surface_ack_change_state,
xdg_surface_set_minimized,
};
static void
use_unstable_version (struct wl_client *client,
struct wl_resource *resource,
int32_t version)
{
if (version != META_XDG_SHELL_VERSION)
g_warning ("Bad xdg_shell version: %d", version);
}
static void
get_xdg_surface (struct wl_client *client,
struct wl_resource *resource,
guint32 id,
struct wl_resource *surface_resource)
xdg_shell_get_xdg_surface (struct wl_client *client,
struct wl_resource *resource,
guint32 id,
struct wl_resource *surface_resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
@@ -967,33 +974,21 @@ xdg_popup_destroy (struct wl_client *client,
wl_resource_destroy (resource);
}
static void
xdg_popup_pong (struct wl_client *client,
struct wl_resource *resource,
uint32_t serial)
{
MetaWaylandSurfaceExtension *xdg_popup = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_popup, surface, xdg_popup);
meta_window_pong (surface->window, serial);
}
static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
xdg_popup_destroy,
xdg_popup_pong,
};
static void
get_xdg_popup (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *parent_resource,
struct wl_resource *seat_resource,
uint32_t serial,
int32_t x,
int32_t y,
uint32_t flags)
xdg_shell_get_xdg_popup (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *parent_resource,
struct wl_resource *seat_resource,
uint32_t serial,
int32_t x,
int32_t y,
uint32_t flags)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
@@ -1003,7 +998,7 @@ get_xdg_popup (struct wl_client *client,
if (parent_surf == NULL || parent_surf->window == NULL)
return;
meta_window_get_frame_rect (parent_surf->window, &parent_rect);
meta_window_get_rect (parent_surf->window, &parent_rect);
if (!create_surface_extension (&surface->xdg_popup, client, surface_resource, resource, id,
META_XDG_POPUP_VERSION,
@@ -1031,11 +1026,40 @@ get_xdg_popup (struct wl_client *client,
}
static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = {
use_unstable_version,
get_xdg_surface,
get_xdg_popup,
xdg_shell_use_unstable_version,
xdg_shell_get_xdg_surface,
xdg_shell_get_xdg_popup,
xdg_shell_pong,
};
typedef struct {
struct wl_resource *resource;
struct wl_listener client_destroy_listener;
} XdgShell;
static void
xdg_shell_handle_client_destroy (struct wl_listener *listener, void *data)
{
XdgShell *xdg_shell = wl_container_of (listener, xdg_shell, client_destroy_listener);
g_slice_free (XdgShell, xdg_shell);
}
static struct wl_resource *
get_xdg_shell_for_client (struct wl_client *client)
{
struct wl_listener *listener;
XdgShell *xdg_shell;
listener = wl_client_get_destroy_listener (client, xdg_shell_handle_client_destroy);
/* No xdg_shell has been bound for this client */
if (listener == NULL)
return NULL;
xdg_shell = wl_container_of (listener, xdg_shell, client_destroy_listener);
return xdg_shell->resource;
}
static void
bind_xdg_shell (struct wl_client *client,
void *data,
@@ -1043,10 +1067,23 @@ bind_xdg_shell (struct wl_client *client,
guint32 id)
{
struct wl_resource *resource;
XdgShell *xdg_shell;
resource = wl_resource_create (client, &xdg_shell_interface,
MIN (META_XDG_SHELL_VERSION, version), id);
if (version != 1)
{
g_warning ("using xdg-shell without stable version 1\n");
return;
}
xdg_shell = g_slice_new (XdgShell);
resource = wl_resource_create (client, &xdg_shell_interface, 1, id);
wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, data, NULL);
xdg_shell->resource = wl_resource_create (client, &xdg_shell_interface, 1, id);
wl_resource_set_implementation (xdg_shell->resource, &meta_wayland_xdg_shell_interface, data, NULL);
xdg_shell->client_destroy_listener.notify = xdg_shell_handle_client_destroy;
wl_client_add_destroy_listener (client, &xdg_shell->client_destroy_listener);
}
static void
@@ -1071,6 +1108,13 @@ set_dbus_properties (struct wl_client *client,
MetaWaylandSurfaceExtension *gtk_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (gtk_surface, surface, gtk_surface);
/* Broken client, let it die instead of us */
if (!surface->window)
{
meta_warning ("meta-wayland-surface: set_dbus_properties called with invalid window!\n");
return;
}
meta_window_set_gtk_dbus_properties (surface->window,
application_id,
unique_bus_name,
@@ -1417,8 +1461,7 @@ void
meta_wayland_init_shell (MetaWaylandCompositor *compositor)
{
if (wl_global_create (compositor->wayland_display,
&xdg_shell_interface,
META_XDG_SHELL_VERSION,
&xdg_shell_interface, 1,
compositor, bind_xdg_shell) == NULL)
g_error ("Failed to register a global xdg-shell object");
@@ -1438,34 +1481,95 @@ meta_wayland_init_shell (MetaWaylandCompositor *compositor)
void
meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int new_width,
int new_height,
int edges)
int new_height)
{
if (surface->xdg_surface.resource)
xdg_surface_send_configure (surface->xdg_surface.resource,
edges, new_width, new_height);
new_width, new_height);
}
static void
send_change_state (MetaWaylandSurface *surface,
uint32_t state_type,
uint32_t value)
{
if (surface->xdg_surface.resource)
{
uint32_t serial;
if (surface->state_changed_serial != 0)
{
serial = surface->state_changed_serial;
surface->state_changed_serial = 0;
}
else
{
struct wl_client *client = wl_resource_get_client (surface->xdg_surface.resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
}
xdg_surface_send_change_state (surface->xdg_surface.resource, state_type, value, serial);
}
}
void
meta_wayland_surface_focused_set (MetaWaylandSurface *surface)
meta_wayland_surface_send_maximized (MetaWaylandSurface *surface)
{
if (surface->xdg_surface.resource)
xdg_surface_send_focused_set (surface->xdg_surface.resource);
send_change_state (surface, XDG_SURFACE_STATE_TYPE_MAXIMIZED, TRUE);
}
void
meta_wayland_surface_focused_unset (MetaWaylandSurface *surface)
meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_TYPE_MAXIMIZED, FALSE);
}
void
meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_TYPE_FULLSCREEN, TRUE);
}
void
meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_TYPE_FULLSCREEN, FALSE);
}
void
meta_wayland_surface_activated (MetaWaylandSurface *surface)
{
if (surface->xdg_surface.resource)
xdg_surface_send_focused_unset (surface->xdg_surface.resource);
xdg_surface_send_activated (surface->xdg_surface.resource);
}
void
meta_wayland_surface_deactivated (MetaWaylandSurface *surface)
{
if (surface->xdg_surface.resource)
xdg_surface_send_deactivated (surface->xdg_surface.resource);
}
void
meta_wayland_surface_ping (MetaWaylandSurface *surface,
guint32 timestamp)
guint32 serial)
{
struct wl_client *client = wl_resource_get_client (surface->resource);
struct wl_resource *xdg_shell = get_xdg_shell_for_client (client);
if (xdg_shell == NULL)
{
g_warning ("Trying to ping a surface without an xdg_shell bound. How does this happen?");
return;
}
xdg_shell_send_ping (xdg_shell, serial);
}
void
meta_wayland_surface_delete (MetaWaylandSurface *surface)
{
if (surface->xdg_surface.resource)
xdg_surface_send_ping (surface->xdg_surface.resource, timestamp);
else if (surface->xdg_popup.resource)
xdg_popup_send_ping (surface->xdg_popup.resource, timestamp);
xdg_surface_send_delete (surface->xdg_surface.resource);
}

View File

@@ -59,6 +59,9 @@ typedef struct
/* wl_surface.frame */
struct wl_list frame_callback_list;
gboolean frame_extents_changed;
GtkBorder frame_extents;
} MetaWaylandDoubleBufferedState;
typedef struct
@@ -96,6 +99,8 @@ struct _MetaWaylandSurface
GSList *pending_placement_ops;
} sub;
uint32_t state_changed_serial;
/* All the pending state, that wl_surface.commit will apply. */
MetaWaylandDoubleBufferedState pending;
};
@@ -106,15 +111,22 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
struct wl_client *client,
guint32 id,
guint32 version);
void meta_wayland_surface_window_unmanaged (MetaWaylandSurface *surface);
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int width,
int height,
int edges);
int height);
void meta_wayland_surface_send_maximized (MetaWaylandSurface *surface);
void meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface);
void meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface);
void meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface);
void meta_wayland_surface_focused_set (MetaWaylandSurface *surface);
void meta_wayland_surface_focused_unset (MetaWaylandSurface *surface);
void meta_wayland_surface_activated (MetaWaylandSurface *surface);
void meta_wayland_surface_deactivated (MetaWaylandSurface *surface);
void meta_wayland_surface_ping (MetaWaylandSurface *surface,
guint32 serial);
void meta_wayland_surface_delete (MetaWaylandSurface *surface);
#endif

View File

@@ -41,7 +41,6 @@
#define META_WL_OUTPUT_VERSION 2
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 1
#define META_XDG_SHELL_VERSION 1
#define META_WL_SUBCOMPOSITOR_VERSION 1
/* Slave objects (version inherited from a master object) */

View File

@@ -600,31 +600,11 @@ meta_wayland_log_func (const char *fmt,
g_free (str);
}
static gboolean
are_we_native (int *out_drm_fd)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
if (cogl_renderer_get_winsys_id (cogl_renderer) == COGL_WINSYS_ID_EGL_KMS)
{
*out_drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
return TRUE;
}
else
{
return FALSE;
}
}
void
meta_wayland_init (void)
{
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
MetaMonitorManager *monitors;
char *display_name;
int drm_fd;
memset (compositor, 0, sizeof (MetaWaylandCompositor));
@@ -663,27 +643,24 @@ meta_wayland_init (void)
clutter_wayland_set_compositor_display (compositor->wayland_display);
if (getenv ("WESTON_LAUNCHER_SOCK"))
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
compositor->launcher = meta_launcher_new ();
#endif
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Failed to initialize Clutter");
if (are_we_native (&drm_fd))
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
GError *error = NULL;
if (!meta_launcher_set_drm_fd (compositor->launcher, drm_fd, &error))
{
g_error ("Failed to set DRM fd to weston-launch and become DRM master: %s", error->message);
g_error_free (error);
}
compositor->native = TRUE;
}
else
{
compositor->native = FALSE;
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
int drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
meta_launcher_set_drm_fd (compositor->launcher, drm_fd, NULL);
}
#endif
meta_monitor_manager_initialize ();
monitors = meta_monitor_manager_get ();
@@ -699,7 +676,7 @@ meta_wayland_init (void)
meta_wayland_data_device_manager_init (compositor->wayland_display);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display, compositor->native);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
meta_wayland_init_shell (compositor);
@@ -720,13 +697,10 @@ meta_wayland_init (void)
* and so EGL must be initialized by this point.
*/
if (!meta_xwayland_start (compositor))
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
g_error ("Failed to start X Wayland");
display_name = g_strdup_printf (":%d", compositor->xwayland_display_index);
set_gnome_env ("DISPLAY", display_name);
g_free (display_name);
set_gnome_env ("DISPLAY", compositor->xwayland_manager.display_name);
set_gnome_env ("WAYLAND_DISPLAY", compositor->display_name);
}
@@ -737,18 +711,12 @@ meta_wayland_finalize (void)
compositor = meta_wayland_compositor_get_default ();
meta_xwayland_stop (compositor);
meta_xwayland_stop (&compositor->xwayland_manager);
if (compositor->launcher)
meta_launcher_free (compositor->launcher);
}
gboolean
meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor)
{
return compositor->native;
}
gboolean
meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
int vt,

View File

@@ -25,12 +25,13 @@
#include <glib.h>
gboolean
meta_xwayland_start (MetaWaylandCompositor *compositor);
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *display);
void
meta_xwayland_complete_init (void);
void
meta_xwayland_stop (MetaWaylandCompositor *compositor);
meta_xwayland_stop (MetaXWaylandManager *manager);
#endif /* META_XWAYLAND_PRIVATE_H */

View File

@@ -63,20 +63,20 @@ bind_xserver (struct wl_client *client,
guint32 version,
guint32 id)
{
MetaWaylandCompositor *compositor = data;
MetaXWaylandManager *manager = data;
/* If it's a different client than the xserver we launched,
* don't start the wm. */
if (client != compositor->xwayland_client)
* just freeze up... */
if (client != manager->client)
return;
compositor->xserver_resource = wl_resource_create (client, &xserver_interface,
MIN (META_XSERVER_VERSION, version), id);
wl_resource_set_implementation (compositor->xserver_resource,
&xserver_implementation, compositor, NULL);
manager->xserver_resource = wl_resource_create (client, &xserver_interface,
MIN (META_XSERVER_VERSION, version), id);
wl_resource_set_implementation (manager->xserver_resource,
&xserver_implementation, manager, NULL);
xserver_send_listen_socket (compositor->xserver_resource, compositor->xwayland_abstract_fd);
xserver_send_listen_socket (compositor->xserver_resource, compositor->xwayland_unix_fd);
xserver_send_listen_socket (manager->xserver_resource, manager->abstract_fd);
xserver_send_listen_socket (manager->xserver_resource, manager->unix_fd);
/* Make sure xwayland will recieve the above sockets in a finite
* time before unblocking the initialization mainloop since we are
@@ -88,8 +88,8 @@ bind_xserver (struct wl_client *client,
* connections so we can quit the transient initialization mainloop
* and unblock meta_wayland_init() to continue initializing mutter.
* */
g_main_loop_quit (compositor->init_loop);
g_clear_pointer (&compositor->init_loop, g_main_loop_unref);
g_main_loop_quit (manager->init_loop);
g_clear_pointer (&manager->init_loop, g_main_loop_unref);
}
static char *
@@ -285,7 +285,8 @@ x_io_error (Display *display)
}
gboolean
meta_xwayland_start (MetaWaylandCompositor *compositor)
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *wl_display)
{
int display = 0;
char *lockfile = NULL;
@@ -293,15 +294,13 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
pid_t pid;
char **env;
char *fd_string;
char *display_name;
char *log_path;
char *args[11];
char *args[10];
GError *error;
wl_global_create (compositor->wayland_display,
&xserver_interface,
wl_global_create (wl_display, &xserver_interface,
META_XSERVER_VERSION,
compositor, bind_xserver);
manager, bind_xserver);
do
{
@@ -312,8 +311,8 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
return FALSE;
}
compositor->xwayland_abstract_fd = bind_to_abstract_socket (display);
if (compositor->xwayland_abstract_fd < 0)
manager->abstract_fd = bind_to_abstract_socket (display);
if (manager->abstract_fd < 0)
{
unlink (lockfile);
@@ -326,11 +325,11 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
return FALSE;
}
compositor->xwayland_unix_fd = bind_to_unix_socket (display);
if (compositor->xwayland_abstract_fd < 0)
manager->unix_fd = bind_to_unix_socket (display);
if (manager->abstract_fd < 0)
{
unlink (lockfile);
close (compositor->xwayland_abstract_fd);
close (manager->abstract_fd);
return FALSE;
}
@@ -338,8 +337,8 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
}
while (1);
compositor->xwayland_display_index = display;
compositor->xwayland_lockfile = lockfile;
manager->display_index = display;
manager->lockfile = lockfile;
/* We want xwayland to be a wayland client so we make a socketpair to setup a
* wayland protocol connection. */
@@ -355,21 +354,19 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
env = g_environ_setenv (env, "WAYLAND_SOCKET", fd_string, TRUE);
g_free (fd_string);
display_name = g_strdup_printf (":%d",
compositor->xwayland_display_index);
manager->display_name = g_strdup_printf (":%d", manager->display_index);
log_path = g_build_filename (g_get_user_cache_dir (), "xwayland.log", NULL);
args[0] = XWAYLAND_PATH;
args[1] = display_name;
args[1] = manager->display_name;
args[2] = "-wayland";
args[3] = "-rootless";
args[4] = "-retro";
args[5] = "-noreset";
args[6] = "-logfile";
args[7] = log_path;
args[8] = "-nolisten";
args[9] = "all";
args[10] = NULL;
args[4] = "-noreset";
args[5] = "-logfile";
args[6] = log_path;
args[7] = "-nolisten";
args[8] = "all";
args[9] = NULL;
error = NULL;
if (g_spawn_async (NULL, /* cwd */
@@ -387,10 +384,9 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
g_message ("forked X server, pid %d\n", pid);
close (sp[1]);
compositor->xwayland_client =
wl_client_create (compositor->wayland_display, sp[0]);
manager->client = wl_client_create (wl_display, sp[0]);
compositor->xwayland_pid = pid;
manager->pid = pid;
g_child_watch_add (pid, xserver_died, NULL);
}
else
@@ -399,15 +395,13 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
}
g_strfreev (env);
g_free (display_name);
g_free (log_path);
/* We need to run a mainloop until we know xwayland has a binding
* for our xserver interface at which point we can assume it's
* ready to start accepting connections. */
compositor->init_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (compositor->init_loop);
manager->init_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (manager->init_loop);
return TRUE;
}
@@ -425,16 +419,14 @@ meta_xwayland_complete_init (void)
}
void
meta_xwayland_stop (MetaWaylandCompositor *compositor)
meta_xwayland_stop (MetaXWaylandManager *manager)
{
char path[256];
snprintf (path, sizeof path, "/tmp/.X%d-lock",
compositor->xwayland_display_index);
snprintf (path, sizeof path, "/tmp/.X%d-lock", manager->display_index);
unlink (path);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d",
compositor->xwayland_display_index);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index);
unlink (path);
unlink (compositor->xwayland_lockfile);
unlink (manager->lockfile);
}