Implement support for XDG window decoration

* 12to11.c (XLMain): Initialize window decoration.
* Imakefile (SRCS, OBJS): Add decoration.c and decoration.o.
* README: Document support for zdg_decoration_manager_v1.
* compositor.h: Update prototypes.
* xdg_toplevel.c (XdgDecoration, DecorationMode): New types.
(enum _DecorationMode): New structures.
(struct _XdgToplevel): New fields `decor' and `decoration'.
(struct _XdgDecoration): New struct.
(SendDecorationConfigure): New function.
(Commit): Apply decoration should it be dirty.
(HandleResourceDestroy): Detach decoration object.
(Destroy): Post error if decoration object would be orphaned.
(DestroyDecoration, SetMode, UnsetMode)
(HandleDecorationResourceDestroy, XLXdgToplevelGetDecoration):
New functions.
This commit is contained in:
oldosfan 2022-09-30 07:38:12 +00:00
parent e09fe5f5b5
commit a5f2c99939
5 changed files with 239 additions and 8 deletions

View file

@ -123,6 +123,7 @@ XLMain (int argc, char **argv)
XLInitPrimarySelection (); XLInitPrimarySelection ();
XLInitExplicitSynchronization (); XLInitExplicitSynchronization ();
XLInitWpViewporter (); XLInitWpViewporter ();
XLInitDecoration ();
/* This has to come after the rest of the initialization. */ /* This has to come after the rest of the initialization. */
DetermineServerTime (); DetermineServerTime ();
XLRunCompositor (); XLRunCompositor ();

View file

@ -21,7 +21,7 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c \ dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c \
icon_surface.c primary_selection.c renderer.c \ icon_surface.c primary_selection.c renderer.c \
picture_renderer.c explicit_synchronization.c transform.c \ picture_renderer.c explicit_synchronization.c transform.c \
wp_viewporter.c wp_viewporter.c decoration.c
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
surface.o region.o shm.o atoms.o subcompositor.o positioner.o \ surface.o region.o shm.o atoms.o subcompositor.o positioner.o \
@ -30,7 +30,7 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o \ dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o \
icon_surface.o primary_selection.o renderer.o \ icon_surface.o primary_selection.o renderer.o \
picture_renderer.o explicit_synchronization.o transform.o \ picture_renderer.o explicit_synchronization.o transform.o \
wp_viewporter.o wp_viewporter.o decoration.o
GENHEADERS = transfer_atoms.h GENHEADERS = transfer_atoms.h
@ -110,6 +110,7 @@ ScannerTarget(xdg-shell)
ScannerTarget(primary-selection-unstable-v1) ScannerTarget(primary-selection-unstable-v1)
ScannerTarget(linux-explicit-synchronization-unstable-v1) ScannerTarget(linux-explicit-synchronization-unstable-v1)
ScannerTarget(viewporter) ScannerTarget(viewporter)
ScannerTarget(xdg-decoration-unstable-v1)
/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */ /* Make OBJS depend on scanner headers, and depend on both them and SRCS. */
$(OBJS): $(GENHEADERS) $(OBJS): $(GENHEADERS)

1
README
View file

@ -65,6 +65,7 @@ complete degree:
'zwp_linux_dmabuf_v1', version: 4 'zwp_linux_dmabuf_v1', version: 4
'zwp_primary_selection_device_manager_v1', version: 1 'zwp_primary_selection_device_manager_v1', version: 1
'wp_viewporter', version: 1 'wp_viewporter', version: 1
'zxdg_decoration_manager_v1', version: 1
When built with EGL, the following Wayland protocol is also supported: When built with EGL, the following Wayland protocol is also supported:

View file

@ -1140,6 +1140,8 @@ extern void XLGetXdgToplevel (struct wl_client *, struct wl_resource *,
extern Bool XLHandleXEventForXdgToplevels (XEvent *); extern Bool XLHandleXEventForXdgToplevels (XEvent *);
extern Bool XLIsXdgToplevel (Window); extern Bool XLIsXdgToplevel (Window);
extern void XLInitXdgToplevels (void); extern void XLInitXdgToplevels (void);
extern void XLXdgToplevelGetDecoration (XdgRoleImplementation *,
struct wl_resource *, uint32_t);
/* Defined in xdg_popup.c. */ /* Defined in xdg_popup.c. */
@ -1426,6 +1428,10 @@ extern void XLInitWpViewporter (void);
extern void XLWpViewportReportBadSize (ViewportExt *); extern void XLWpViewportReportBadSize (ViewportExt *);
extern void XLWpViewportReportOutOfBuffer (ViewportExt *); extern void XLWpViewportReportOutOfBuffer (ViewportExt *);
/* Defined in decoration.c. */
extern void XLInitDecoration (void);
/* Utility functions that don't belong in a specific file. */ /* Utility functions that don't belong in a specific file. */
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0]) #define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])

View file

@ -25,15 +25,18 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include "compositor.h" #include "compositor.h"
#include "xdg-shell.h" #include "xdg-shell.h"
#include "xdg-decoration-unstable-v1.h"
#define ToplevelFromRoleImpl(impl) ((XdgToplevel *) (impl)) #define ToplevelFromRoleImpl(impl) ((XdgToplevel *) (impl))
typedef struct _XdgToplevel XdgToplevel; typedef struct _XdgToplevel XdgToplevel;
typedef struct _XdgDecoration XdgDecoration;
typedef struct _ToplevelState ToplevelState; typedef struct _ToplevelState ToplevelState;
typedef struct _PropMotifWmHints PropMotifWmHints; typedef struct _PropMotifWmHints PropMotifWmHints;
typedef struct _XdgUnmapCallback XdgUnmapCallback; typedef struct _XdgUnmapCallback XdgUnmapCallback;
typedef enum _How How; typedef enum _How How;
typedef enum _DecorationMode DecorationMode;
enum enum
{ {
@ -45,6 +48,7 @@ enum
StatePendingResize = (1 << 5), StatePendingResize = (1 << 5),
StatePendingConfigureSize = (1 << 6), StatePendingConfigureSize = (1 << 6),
StatePendingConfigureStates = (1 << 7), StatePendingConfigureStates = (1 << 7),
StateDecorationModeDirty = (1 << 8),
}; };
enum enum
@ -68,6 +72,12 @@ enum _How
Toggle = 2, Toggle = 2,
}; };
enum _DecorationMode
{
DecorationModeClient = 0,
DecorationModeWindowManager = 1,
};
struct _XdgUnmapCallback struct _XdgUnmapCallback
{ {
/* Function run when the toplevel is unmapped or detached. */ /* Function run when the toplevel is unmapped or detached. */
@ -218,6 +228,21 @@ struct _XdgToplevel
/* The width and height used by that timer if /* The width and height used by that timer if
StatePendingConfigureSize is set. */ StatePendingConfigureSize is set. */
int configure_width, configure_height; int configure_width, configure_height;
/* Any decoration resource associated with this toplevel. */
XdgDecoration *decoration;
/* The decoration mode. */
DecorationMode decor;
};
struct _XdgDecoration
{
/* The associated resource. */
struct wl_resource *resource;
/* The associated toplevel. */
XdgToplevel *toplevel;
}; };
/* iconv context used to convert between UTF-8 and Latin-1. */ /* iconv context used to convert between UTF-8 and Latin-1. */
@ -361,6 +386,39 @@ SendConfigure (XdgToplevel *toplevel, unsigned int width,
toplevel->conf_serial = serial; toplevel->conf_serial = serial;
} }
static void
SendDecorationConfigure (XdgToplevel *toplevel)
{
uint32_t serial;
/* This should never be NULL when called! */
XLAssert (toplevel->decoration != NULL);
serial = wl_display_next_serial (compositor.wl_display);
#define ServerSide ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
#define ClientSide ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
if (toplevel->decor == DecorationModeClient)
zxdg_toplevel_decoration_v1_send_configure (toplevel->decoration->resource,
ClientSide);
else
zxdg_toplevel_decoration_v1_send_configure (toplevel->decoration->resource,
ServerSide);
#undef ServerSide
#undef ClientSide
XLXdgRoleSendConfigure (toplevel->role, serial);
toplevel->conf_reply = True;
toplevel->conf_serial = serial;
/* This means that the decoration should be reapplied upon the next
commit. */
toplevel->state |= StateDecorationModeDirty;
}
/* Forward declaration. */ /* Forward declaration. */
static void SendStates (XdgToplevel *); static void SendStates (XdgToplevel *);
@ -1094,6 +1152,20 @@ Commit (Role *role, Surface *surface, XdgRoleImplementation *impl)
if (!(toplevel->state & StateIsMapped)) if (!(toplevel->state & StateIsMapped))
Map (toplevel); Map (toplevel);
} }
if (!toplevel->conf_reply
&& toplevel->state & StateDecorationModeDirty)
{
/* The decoration is dirty and all configure events were
aknowledged; apply the new decoration. */
if (toplevel->decor == DecorationModeWindowManager)
SetDecorated (toplevel, True);
else
SetDecorated (toplevel, False);
toplevel->state &= ~StateDecorationModeDirty;
}
} }
static void static void
@ -1459,12 +1531,15 @@ HandleResourceDestroy (struct wl_resource *resource)
toplevel = wl_resource_get_user_data (resource); toplevel = wl_resource_get_user_data (resource);
toplevel->resource = NULL; toplevel->resource = NULL;
/* If there is an attached decoration resource, detach it. */
if (toplevel->decoration)
toplevel->decoration->toplevel = NULL;
DestroyBacking (toplevel); DestroyBacking (toplevel);
} }
static void static void
Destroy (struct wl_client *client, Destroy (struct wl_client *client, struct wl_resource *resource)
struct wl_resource *resource)
{ {
XdgToplevel *toplevel; XdgToplevel *toplevel;
@ -1474,6 +1549,14 @@ Destroy (struct wl_client *client,
XLXdgRoleDetachImplementation (toplevel->role, XLXdgRoleDetachImplementation (toplevel->role,
&toplevel->impl); &toplevel->impl);
/* If the resource still has a decoration applied, then this is an
error. */
if (toplevel->decoration)
wl_resource_post_error (resource,
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED,
"the attached decoration would be orphaned by"
" the destruction of this resource");
else
wl_resource_destroy (resource); wl_resource_destroy (resource);
} }
@ -2129,3 +2212,142 @@ XLIsXdgToplevel (Window window)
{ {
return XLLookUpXdgToplevel (window) != NULL; return XLLookUpXdgToplevel (window) != NULL;
} }
static void
DestroyDecoration (struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
SetMode (struct wl_client *client, struct wl_resource *resource,
uint32_t mode)
{
XdgDecoration *decoration;
decoration = wl_resource_get_user_data (resource);
if (!decoration->toplevel)
return;
switch (mode)
{
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
decoration->toplevel->decor = DecorationModeClient;
break;
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
decoration->toplevel->decor = DecorationModeWindowManager;
break;
default:
wl_resource_post_error (resource, WL_DISPLAY_ERROR_IMPLEMENTATION,
"trying to set bogus decoration mode %u",
mode);
return;
}
SendDecorationConfigure (decoration->toplevel);
}
static void
UnsetMode (struct wl_client *client, struct wl_resource *resource)
{
XdgDecoration *decoration;
decoration = wl_resource_get_user_data (resource);
if (!decoration->toplevel)
return;
/* Default to using window manager decorations. */
decoration->toplevel->decor = DecorationModeWindowManager;
SendDecorationConfigure (decoration->toplevel);
}
static struct zxdg_toplevel_decoration_v1_interface decoration_impl =
{
.destroy = DestroyDecoration,
.set_mode = SetMode,
.unset_mode = UnsetMode,
};
static void
HandleDecorationResourceDestroy (struct wl_resource *resource)
{
XdgDecoration *decoration;
decoration = wl_resource_get_user_data (resource);
/* Detach the decoration from the toplevel if the latter still
exists. */
if (decoration->toplevel)
decoration->toplevel->decoration = NULL;
/* Free the decoration. */
XLFree (decoration);
}
void
XLXdgToplevelGetDecoration (XdgRoleImplementation *impl,
struct wl_resource *resource,
uint32_t id)
{
XdgToplevel *toplevel;
XdgDecoration *decoration;
toplevel = ToplevelFromRoleImpl (impl);
/* See if a decoration object is already attached. */
if (toplevel->decoration)
{
#define AlreadyConstructed ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED
wl_resource_post_error (resource, AlreadyConstructed,
"the given toplevel already has a decoration"
"object.");
#undef AlreadyConstructed
return;
}
/* See if a buffer is already attached. */
if (toplevel->role->surface
&& toplevel->role->surface->current_state.buffer)
{
#define UnconfiguredBuffer ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER
wl_resource_post_error (resource, UnconfiguredBuffer,
"given toplevel already has attached buffer");
#undef UnconfiguredBuffer
return;
}
decoration = XLSafeMalloc (sizeof *decoration);
if (!decoration)
{
wl_resource_post_no_memory (resource);
return;
}
memset (decoration, 0, sizeof *decoration);
decoration->resource
= wl_resource_create (wl_resource_get_client (resource),
&zxdg_toplevel_decoration_v1_interface,
wl_resource_get_version (resource), id);
if (!decoration->resource)
{
XLFree (decoration);
wl_resource_post_no_memory (resource);
return;
}
/* Now attach the decoration to the toplevel and vice versa. */
toplevel->decoration = decoration;
decoration->toplevel = toplevel;
/* And set the implementation. */
wl_resource_set_implementation (decoration->resource, &decoration_impl,
decoration, HandleDecorationResourceDestroy);
}