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...
This commit is contained in:
Jasper St. Pierre 2014-02-09 11:45:09 -05:00
parent c1f15348a5
commit b37ad66e9d
4 changed files with 182 additions and 166 deletions

View File

@ -40,19 +40,22 @@
<enum name="version"> <enum name="version">
<description summary="latest protocol version"> <description summary="latest protocol version">
Use this enum to check the protocol version, and it will be updated The 'current' member of this enum gives the version of the
automatically. protocol. Implementations can compare this to the version
they implement using static_assert to ensure the protocol and
implementation versions match.
</description> </description>
<entry name="current" value="2" summary="Always the latest version"/> <entry name="current" value="3" summary="Always the latest version"/>
</enum> </enum>
<request name="use_unstable_version"> <request name="use_unstable_version">
<description summary="enable use of this unstable version"> <description summary="enable use of this unstable version">
Use this request in order to enable use of this interface. Negotiate the unstable version of the interface. This
mechanism is in place to ensure client and server agree on the
Understand and agree that one is using an unstable interface, unstable versions of the protocol that they speak or exit
that will likely change in the future, breaking the API. cleanly if they don't agree. This request will go away once
the xdg-shell protocol is stable.
</description> </description>
<arg name="version" type="int"/> <arg name="version" type="int"/>
</request> </request>
@ -275,113 +278,87 @@
<arg name="output" type="object" interface="wl_output" allow-null="true"/> <arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request> </request>
<event name="request_set_fullscreen"> <enum name="state">
<description summary="server requests that the client set fullscreen"> <description summary="types of state on the surface">
Event sent from the compositor to the client requesting that the client The different state values used on the surface. This is designed for
goes to a fullscreen state. It's the client job to call set_fullscreen state values like maximized, fullscreen. It is paired with the
and really trigger the fullscreen state. 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> </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"> <request name="request_change_state">
<description summary="server requests that the client unset fullscreen"> <description summary="client requests to change a surface's state">
Event sent from the compositor to the client requesting that the client This asks the compositor to change the state. If the compositor wants
leaves the fullscreen state. It's the client job to call to change the state, it will send a change_state event with the same
unset_fullscreen and really leave the fullscreen state. state_type, value, and serial, and the event flow continues as if it
</description> it was initiated by the compositor.
</event>
If the compositor does not want to change the state, it will send a
<request name="set_fullscreen"> change_state to the client with the old value of the state.
<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.
</description> </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>
<request name="unset_fullscreen"> <event name="change_state">
<description summary="unset the surface state as fullscreen"> <description summary="compositor wants to change a surface's state">
Unset the surface fullscreen 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
Same negotiation as set_fullscreen must be used. guarantee that the compositor knows that the client has seen it.
</description> </description>
</request>
<event name="request_set_maximized"> <arg name="state_type" type="uint" summary="the state to set"/>
<description summary="server requests that the client set maximized"> <arg name="value" type="uint" summary="the value to change the state to"/>
Event sent from the compositor to the client requesting that the client <arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/>
goes to a maximized state. It's the client job to call set_maximized
and really trigger the maximized state.
</description>
</event> </event>
<event name="request_unset_maximized"> <request name="ack_change_state">
<description summary="server requests that the client unset maximized"> <description summary="ack a change_state event">
Event sent from the compositor to the client requesting that the client When a change_state event is received, a client should then ack it
leaves the maximized state. It's the client job to call unset_maximized using the ack_change_state request to ensure that the compositor
and really leave the maximized state. knows the client has seen the event.
</description>
</event> By this point, the state is confirmed, and the next attach should
contain the buffer drawn for the new state value.
<request name="set_maximized">
<description summary="set the surface state as maximized"> The values here need to be the same as the values in the cooresponding
Set the surface as maximized. change_state event.
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.
</description> </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>
<request name="set_minimized"> <request name="set_minimized">
<description summary="set the surface state as minimized"> <description summary="minimize the surface">
Set the surface minimized state. Minimize the surface.
Setting one state won't unset another state.
</description> </description>
</request> </request>

View File

@ -3120,6 +3120,9 @@ meta_window_maximize_internal (MetaWindow *window,
meta_window_recalc_features (window); meta_window_recalc_features (window);
set_net_wm_state (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_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally"); g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically"); g_object_notify (G_OBJECT (window), "maximized-vertically");
@ -3605,10 +3608,13 @@ meta_window_unmaximize_internal (MetaWindow *window,
set_net_wm_state (window); set_net_wm_state (window);
} }
g_object_freeze_notify (G_OBJECT (window)); if (window->surface && !window->maximized_horizontally && !window->maximized_vertically)
g_object_notify (G_OBJECT (window), "maximized-horizontally"); meta_wayland_surface_send_unmaximized (window->surface);
g_object_notify (G_OBJECT (window), "maximized-vertically");
g_object_thaw_notify (G_OBJECT (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));
} }
void void
@ -3711,6 +3717,9 @@ meta_window_make_fullscreen_internal (MetaWindow *window)
/* For the auto-minimize feature, if we fail to get focus */ /* For the auto-minimize feature, if we fail to get focus */
meta_screen_queue_check_fullscreen (window->screen); meta_screen_queue_check_fullscreen (window->screen);
if (window->surface)
meta_wayland_surface_send_fullscreened (window->surface);
g_object_notify (G_OBJECT (window), "fullscreen"); g_object_notify (G_OBJECT (window), "fullscreen");
} }
} }
@ -3767,6 +3776,9 @@ meta_window_unmake_fullscreen (MetaWindow *window)
meta_window_update_layer (window); meta_window_update_layer (window);
if (window->surface)
meta_wayland_surface_send_unfullscreened (window->surface);
g_object_notify (G_OBJECT (window), "fullscreen"); g_object_notify (G_OBJECT (window), "fullscreen");
} }
} }

View File

@ -336,22 +336,6 @@ toplevel_surface_commit (MetaWaylandSurface *surface,
if (pending->frame_extents_changed) if (pending->frame_extents_changed)
meta_window_set_custom_frame_extents (surface->window, &pending->frame_extents); meta_window_set_custom_frame_extents (surface->window, &pending->frame_extents);
if (pending->maximized.changed)
{
if (pending->maximized.value)
meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
else
meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
}
if (pending->fullscreen.changed)
{
if (pending->fullscreen.value)
meta_window_make_fullscreen (surface->window);
else
meta_window_unmake_fullscreen (surface->window);
}
} }
static void static void
@ -377,8 +361,6 @@ double_buffered_state_init (MetaWaylandDoubleBufferedState *state)
wl_list_init (&state->frame_callback_list); wl_list_init (&state->frame_callback_list);
state->frame_extents_changed = FALSE; state->frame_extents_changed = FALSE;
state->maximized.changed = FALSE;
state->fullscreen.changed = FALSE;
} }
static void static void
@ -861,43 +843,44 @@ xdg_surface_set_output (struct wl_client *client,
} }
static void static void
xdg_surface_set_fullscreen (struct wl_client *client, xdg_surface_request_change_state (struct wl_client *client,
struct wl_resource *resource) struct wl_resource *resource,
uint32_t state_type,
uint32_t value,
uint32_t serial)
{ {
MetaWaylandSurface *surface = wl_resource_get_user_data (resource); MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.fullscreen.changed = TRUE; surface->state_changed_serial = serial;
surface->pending.fullscreen.value = TRUE;
switch (state_type)
{
case XDG_SURFACE_STATE_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_FULLSCREEN:
if (value)
meta_window_make_fullscreen (surface->window);
else
meta_window_unmake_fullscreen (surface->window);
}
} }
static void static void
xdg_surface_unset_fullscreen (struct wl_client *client, xdg_surface_ack_change_state (struct wl_client *client,
struct wl_resource *resource) struct wl_resource *resource,
uint32_t state_type,
uint32_t value,
uint32_t serial)
{ {
MetaWaylandSurface *surface = wl_resource_get_user_data (resource); /* Do nothing for now. In the future, we'd imagine that
* we'd ignore attaches when we have a state pending that
surface->pending.fullscreen.changed = TRUE; * we haven't had the client ACK'd, to prevent a race
surface->pending.fullscreen.value = FALSE; * condition when we have an in-flight attach when the
} * client gets the new state. */
static void
xdg_surface_set_maximized (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.maximized.changed = TRUE;
surface->pending.maximized.value = TRUE;
}
static void
xdg_surface_unset_maximized (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.maximized.changed = TRUE;
surface->pending.maximized.value = FALSE;
} }
static void static void
@ -918,10 +901,8 @@ static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = {
xdg_surface_move, xdg_surface_move,
xdg_surface_resize, xdg_surface_resize,
xdg_surface_set_output, xdg_surface_set_output,
xdg_surface_set_fullscreen, xdg_surface_request_change_state,
xdg_surface_unset_fullscreen, xdg_surface_ack_change_state,
xdg_surface_set_maximized,
xdg_surface_unset_maximized,
xdg_surface_set_minimized, xdg_surface_set_minimized,
}; };
@ -1735,6 +1716,55 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
0, new_width, new_height); 0, 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_send_maximized (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, TRUE);
}
void
meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, FALSE);
}
void
meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, TRUE);
}
void
meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, FALSE);
}
void void
meta_wayland_surface_activated (MetaWaylandSurface *surface) meta_wayland_surface_activated (MetaWaylandSurface *surface)
{ {

View File

@ -41,12 +41,6 @@ struct _MetaWaylandBuffer
uint32_t ref_count; uint32_t ref_count;
}; };
typedef struct
{
guint changed : 1;
guint value : 1;
} MetaWaylandStateFlag;
typedef struct typedef struct
{ {
/* wl_surface.attach */ /* wl_surface.attach */
@ -67,9 +61,6 @@ typedef struct
gboolean frame_extents_changed; gboolean frame_extents_changed;
GtkBorder frame_extents; GtkBorder frame_extents;
MetaWaylandStateFlag fullscreen;
MetaWaylandStateFlag maximized;
} MetaWaylandDoubleBufferedState; } MetaWaylandDoubleBufferedState;
typedef struct typedef struct
@ -107,6 +98,8 @@ struct _MetaWaylandSurface
GSList *pending_placement_ops; GSList *pending_placement_ops;
} sub; } sub;
uint32_t state_changed_serial;
/* All the pending state, that wl_surface.commit will apply. */ /* All the pending state, that wl_surface.commit will apply. */
MetaWaylandDoubleBufferedState pending; MetaWaylandDoubleBufferedState pending;
}; };
@ -124,6 +117,10 @@ void meta_wayland_surface_window_unmanaged (MetaWaylandSurface *s
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int width, int width,
int height); 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_activated (MetaWaylandSurface *surface); void meta_wayland_surface_activated (MetaWaylandSurface *surface);
void meta_wayland_surface_deactivated (MetaWaylandSurface *surface); void meta_wayland_surface_deactivated (MetaWaylandSurface *surface);