xdg-shell: upgrade to support current version (weston-1.6.0)

Many inprovements on windows's decorations,

Also handle compositor events
(test: Super+Shift+F , Super+Shift+M)

The protocol file is a raw copy of

Source: http://cgit.freedesktop.org/wayland/weston/plain/protocol/xdg-shell.xml?id=1.6.0

Task-number: QTBUG-38633/related
Change-Id: I667ec52c8a7e34d74b60174a671c89671f841d6b
Reviewed-by: Giulio Camuffo <giulio.camuffo@jollamobile.com>
This commit is contained in:
Philippe Coval 2014-11-05 16:13:17 +01:00 committed by Philippe Coval
parent 7b722dcd07
commit 934b4bb9a5
3 changed files with 155 additions and 187 deletions

View File

@ -45,7 +45,7 @@
they implement using static_assert to ensure the protocol and they implement using static_assert to ensure the protocol and
implementation versions match. implementation versions match.
</description> </description>
<entry name="current" value="3" summary="Always the latest version"/> <entry name="current" value="4" summary="Always the latest version"/>
</enum> </enum>
@ -137,11 +137,8 @@
</description> </description>
</request> </request>
<request name="set_transient_for"> <request name="set_parent">
<description summary="surface is a child of another surface"> <description summary="surface is a child of another surface">
Setting a surface as transient of another means that it is child
of another surface.
Child surfaces are stacked above their parents, and will be Child surfaces are stacked above their parents, and will be
unmapped if the parent is unmapped too. They should not appear unmapped if the parent is unmapped too. They should not appear
on task bars and alt+tab. on task bars and alt+tab.
@ -149,32 +146,6 @@
<arg name="parent" type="object" interface="wl_surface" allow-null="true"/> <arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
</request> </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"> <request name="set_title">
<description summary="set surface title"> <description summary="set surface title">
Set a short title for the surface. Set a short title for the surface.
@ -201,6 +172,26 @@
<arg name="app_id" type="string"/> <arg name="app_id" type="string"/>
</request> </request>
<request name="show_window_menu">
<description summary="show the window menu">
Clients implementing client-side decorations might want to show
a context menu when right-clicking on the decorations, giving the
user a menu that they can use to maximize or minimize the window.
This request asks the compositor to pop up such a window menu at
the given position, relative to the parent surface. There are
no guarantees as to what the window menu contains.
Your surface must have focus on the seat passed in to pop up the
window menu.
</description>
<arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/>
<arg name="serial" type="uint" summary="serial of the event to pop up the window for"/>
<arg name="x" type="int" summary="the x position to pop up the window menu at"/>
<arg name="y" type="int" summary="the y position to pop up the window menu at"/>
</request>
<request name="move"> <request name="move">
<description summary="start an interactive move"> <description summary="start an interactive move">
Start a pointer-driven move of the surface. Start a pointer-driven move of the surface.
@ -244,46 +235,12 @@
<arg name="edges" type="uint" summary="which edge or corner is being dragged"/> <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
</request> </request>
<event name="configure">
<description summary="suggest resize">
The configure event asks the client to resize its surface.
The size is a hint, in the sense that the client is free to
ignore it if it doesn't resize, pick a smaller size (to
satisfy aspect ratio or resize in steps of NxM pixels).
The client is free to dismiss all but the last configure
event it received.
The width and height arguments specify the size of the window
in surface local coordinates.
</description>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</event>
<request name="set_output">
<description summary="set the default output used by this surface">
Set the default output used by this surface when it is first mapped.
If this value is NULL (default), it's up to the compositor to choose
which display will be used to map this surface.
When fullscreen or maximized state are set on this surface, and it
wasn't mapped yet, the output set with this method will be used.
Otherwise, the output where the surface is currently mapped will be
used.
</description>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<enum name="state"> <enum name="state">
<description summary="types of state on the surface"> <description summary="types of state on the surface">
The different state values used on the surface. This is designed for The different state values used on the surface. This is designed for
state values like maximized, fullscreen. It is paired with the state values like maximized, fullscreen. It is paired with the
request_change_state event to ensure that both the client and the configure event to ensure that both the client and the compositor
compositor setting the state can be synchronized. setting the state can be synchronized.
States set in this way are double-buffered. They will get applied on States set in this way are double-buffered. They will get applied on
the next commit. the next commit.
@ -300,89 +257,101 @@
0x1000 - 0x1FFF: GNOME 0x1000 - 0x1FFF: GNOME
</description> </description>
<entry name="maximized" value="1" summary="the surface is maximized"> <entry name="maximized" value="1" summary="the surface is maximized">
A non-zero value indicates the surface is maximized. Otherwise, The surface is maximized. The window geometry specified in the configure
the surface is unmaximized. event must be obeyed by the client.
</entry> </entry>
<entry name="fullscreen" value="2" summary="the surface is fullscreen"> <entry name="fullscreen" value="2" summary="the surface is fullscreen">
A non-zero value indicates the surface is fullscreen. Otherwise, The surface is fullscreen. The window geometry specified in the configure
the surface is not fullscreen. event must be obeyed by the client.
</entry>
<entry name="resizing" value="3">
The surface is being resized. The window geometry specified in the
configure event is a maximum; the client cannot resize beyond it.
Clients that have aspect ratio or cell sizing configuration can use
a smaller size, however.
</entry>
<entry name="activated" value="4">
Client window decorations should be painted as if the window is
active. Do not assume this means that the window actually has
keyboard or pointer focus.
</entry> </entry>
</enum> </enum>
<request name="request_change_state"> <event name="configure">
<description summary="client requests to change a surface's state"> <description summary="suggest a surface change">
This asks the compositor to change the state. If the compositor wants The configure event asks the client to resize its surface.
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 The width and height arguments specify a hint to the window
change_state to the client with the old value of the state. about how its surface should be resized in window geometry
</description> coordinates. The states listed in the event specify how the
<arg name="state_type" type="uint" summary="the state to set"/> width/height arguments should be interpreted.
<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>
<event name="change_state"> A client should arrange a new surface, and then send a
<description summary="compositor wants to change a surface's state"> ack_configure request with the serial sent in this configure
This event tells the client to change a surface's state. The client event before attaching a new surface.
should respond with an ack_change_state request to the compositor to
guarantee that the compositor knows that the client has seen it. If the client receives multiple configure events before it
can respond to one, it is free to discard all but the last
event it received.
</description> </description>
<arg name="state_type" type="uint" summary="the state to set"/> <arg name="width" type="int"/>
<arg name="value" type="uint" summary="the value to change the state to"/> <arg name="height" type="int"/>
<arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/> <arg name="states" type="array"/>
<arg name="serial" type="uint"/>
</event> </event>
<request name="ack_change_state"> <request name="ack_configure">
<description summary="ack a change_state event"> <description summary="ack a configure event">
When a change_state event is received, a client should then ack it When a configure event is received, a client should then ack it
using the ack_change_state request to ensure that the compositor using the ack_configure request to ensure that the compositor
knows the client has seen the event. knows the client has seen the event.
By this point, the state is confirmed, and the next attach should By this point, the state is confirmed, and the next attach should
contain the buffer drawn for the new state value. contain the buffer drawn for the configure event you are acking.
The values here need to be the same as the values in the cooresponding
change_state event.
</description> </description>
<arg name="state_type" type="uint" summary="the state to set"/> <arg name="serial" type="uint" summary="a serial to configure for"/>
<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_window_geometry">
<description summary="minimize the surface"> <description summary="set the new window geometry">
Minimize the surface. The window geometry of a window is its "visible bounds" from the
user's perspective. Client-side decorations often have invisible
portions like drop-shadows which should be ignored for the
purposes of aligning, placing and constraining windows.
The default value is the full bounds of the surface, including any
subsurfaces. Once the window geometry of the surface is set once,
it is not possible to unset it, and it will remain the same until
set_window_geometry is called again, even if a new subsurface or
buffer is attached.
If responding to a configure event, the window geometry in here
must respect the sizing negotiations specified by the states in
the configure event.
</description> </description>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</request> </request>
<event name="activated"> <request name="set_maximized" />
<description summary="surface was activated"> <request name="unset_maximized" />
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="deactivated"> <request name="set_fullscreen">
<description summary="surface was deactivated"> <description summary="set the window as fullscreen on a monitor">
The deactivate event is sent when this surface has been Make the surface fullscreen.
deactivated, which means that the surface lost user attention.
Window decorations should be updated accordingly. You should You can specify an output that you would prefer to be fullscreen.
not use this event for anything but the style of decorations If this value is NULL, it's up to the compositor to choose which
you display, use wl_keyboard.enter and wl_keyboard.leave for display will be used to map this surface.
determining keyboard focus.
</description> </description>
</event> <arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<request name="unset_fullscreen" />
<request name="set_minimized" />
<event name="close"> <event name="close">
<description summary="surface wants to be closed"> <description summary="surface wants to be closed">

View File

@ -48,7 +48,6 @@
#include "qwaylandscreen_p.h" #include "qwaylandscreen_p.h"
#include "qwaylandextendedsurface_p.h" #include "qwaylandextendedsurface_p.h"
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -94,36 +93,32 @@ void QWaylandXdgSurface::move(QWaylandInputDevice *inputDevice)
void QWaylandXdgSurface::setMaximized() void QWaylandXdgSurface::setMaximized()
{ {
if (!m_maximized) if (!m_maximized)
request_change_state(XDG_SURFACE_STATE_MAXIMIZED, true, 0); set_maximized();
} }
void QWaylandXdgSurface::setFullscreen() void QWaylandXdgSurface::setFullscreen()
{ {
if (!m_fullscreen) if (!m_fullscreen)
request_change_state(XDG_SURFACE_STATE_FULLSCREEN, true, 0); set_fullscreen(Q_NULLPTR);
} }
void QWaylandXdgSurface::setNormal() void QWaylandXdgSurface::setNormal()
{ {
if (m_fullscreen || m_maximized || m_minimized) { if (m_fullscreen || m_maximized || m_minimized) {
if (m_maximized) { if (m_maximized) {
request_change_state(XDG_SURFACE_STATE_MAXIMIZED, false, 0); unset_maximized();
} }
if (m_fullscreen) { if (m_fullscreen) {
request_change_state(XDG_SURFACE_STATE_FULLSCREEN, false, 0); unset_fullscreen();
} }
m_fullscreen = m_maximized = m_minimized = false; m_fullscreen = m_maximized = m_minimized = false;
setTopLevel();
QMargins m = m_window->frameMargins();
m_window->configure(0, m_size.width() + m.left() + m.right(), m_size.height() + m.top() + m.bottom());
} }
} }
void QWaylandXdgSurface::setMinimized() void QWaylandXdgSurface::setMinimized()
{ {
m_minimized = true; m_minimized = true;
m_size = m_window->window()->geometry().size();
set_minimized(); set_minimized();
} }
@ -138,22 +133,7 @@ void QWaylandXdgSurface::updateTransientParent(QWindow *parent)
if (!parent_wayland_window) if (!parent_wayland_window)
return; return;
// set_transient expects a position relative to the parent set_parent(parent_wayland_window->object());
QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
QWindow *parentWin = m_window->window()->transientParent();
transientPos -= parentWin->geometry().topLeft();
if (parent_wayland_window->decoration()) {
transientPos.setX(transientPos.x() + parent_wayland_window->decoration()->margins().left());
transientPos.setY(transientPos.y() + parent_wayland_window->decoration()->margins().top());
}
uint32_t flags = 0;
Qt::WindowFlags wf = m_window->window()->flags();
if (wf.testFlag(Qt::ToolTip)
|| wf.testFlag(Qt::WindowTransparentForInput))
flags |= XDG_SURFACE_SET_TRANSIENT_FOR;
set_transient_for(parent_wayland_window->object());
} }
void QWaylandXdgSurface::setTitle(const QString & title) void QWaylandXdgSurface::setTitle(const QString & title)
@ -196,44 +176,64 @@ void QWaylandXdgSurface::sendProperty(const QString &name, const QVariant &value
m_extendedWindow->updateGenericProperty(name, value); m_extendedWindow->updateGenericProperty(name, value);
} }
void QWaylandXdgSurface::xdg_surface_configure(int32_t width, int32_t height) void QWaylandXdgSurface::xdg_surface_configure(int32_t width, int32_t height, struct wl_array *states,uint32_t serial)
{ {
m_window->configure(0 , width, height); uint32_t *state = 0;
} bool aboutToMaximize = false;
bool aboutToFullScreen = false;
void QWaylandXdgSurface::xdg_surface_change_state(uint32_t state, state = (uint32_t*) states->data;
uint32_t value,
uint32_t serial)
{
if (state == XDG_SURFACE_STATE_MAXIMIZED for (uint32_t i=0; i < states->size; i++)
|| state == XDG_SURFACE_STATE_FULLSCREEN) { {
if (value) { switch (*(state+i)) {
m_size = m_window->window()->geometry().size(); case XDG_SURFACE_STATE_MAXIMIZED:
} else { aboutToMaximize = true;
QMargins m = m_window->frameMargins(); break;
m_window->configure(0, m_size.width() + m.left() + m.right(), m_size.height() + m.top() + m.bottom()); case XDG_SURFACE_STATE_FULLSCREEN:
aboutToFullScreen = true;
break;
case XDG_SURFACE_STATE_RESIZING:
m_margins = m_window->frameMargins();
width -= m_margins.left() + m_margins.right();
height -= m_margins.top() + m_margins.bottom();
m_size = QSize(width,height);
break;
case XDG_SURFACE_STATE_ACTIVATED:
// TODO: here about the missing window activation
break;
default:
break;
} }
} }
switch (state) { if (!m_fullscreen && aboutToFullScreen) {
case XDG_SURFACE_STATE_MAXIMIZED: m_fullscreen = true;
m_maximized = value; m_size = m_window->window()->geometry().size();
break; m_window->window()->showFullScreen();
case XDG_SURFACE_STATE_FULLSCREEN: } else if (m_fullscreen && !aboutToFullScreen) {
m_fullscreen = value; m_fullscreen = false;
break; m_window->window()->showNormal();
} else if (!m_maximized && aboutToMaximize) {
m_maximized = true;
m_size = m_window->window()->geometry().size();
m_window->window()->showMaximized();
} else if (m_maximized && !aboutToMaximize) {
m_maximized = false;
m_window->window()->showNormal();
} }
xdg_surface_ack_change_state(object(), state, value, serial); if (width == 0 && height == 0) {
} width = m_size.width();
height = m_size.height();
}
void QWaylandXdgSurface::xdg_surface_activated() if (width > 0 && height > 0) {
{ m_margins = m_window->frameMargins();
} m_window->configure(0, width + m_margins.left() + m_margins.right(), height + m_margins.top() + m_margins.bottom());
}
void QWaylandXdgSurface::xdg_surface_deactivated() xdg_surface_ack_configure(object(), serial);
{
} }
void QWaylandXdgSurface::xdg_surface_close() void QWaylandXdgSurface::xdg_surface_close()

View File

@ -43,6 +43,7 @@
#define QWAYLANDXDGSURFACE_H #define QWAYLANDXDGSURFACE_H
#include <QtCore/QSize> #include <QtCore/QSize>
#include <QtCore/QMargins>
#include <wayland-client.h> #include <wayland-client.h>
@ -99,15 +100,13 @@ private:
bool m_minimized; bool m_minimized;
bool m_fullscreen; bool m_fullscreen;
QSize m_size; QSize m_size;
QMargins m_margins;
QWaylandExtendedSurface *m_extendedWindow; QWaylandExtendedSurface *m_extendedWindow;
void xdg_surface_configure(int32_t width, void xdg_surface_configure(int32_t width,
int32_t height) Q_DECL_OVERRIDE; int32_t height,
void xdg_surface_change_state(uint32_t state, struct wl_array *states,
uint32_t value, uint32_t serial) Q_DECL_OVERRIDE;
uint32_t serial) Q_DECL_OVERRIDE;
void xdg_surface_activated() Q_DECL_OVERRIDE;
void xdg_surface_deactivated() Q_DECL_OVERRIDE;
void xdg_surface_close() Q_DECL_OVERRIDE; void xdg_surface_close() Q_DECL_OVERRIDE;
friend class QWaylandWindow; friend class QWaylandWindow;