forked from 12to11/12to11

EGL support is still incomplete; stuff like scaling is missing. * 12to11.c (PickVisual, XLMain): Remove function. Initialize renderers, and rely on that to initialize the visuals. * 12to11.man: Document new environment variables. * Imakefile (SRCS, OBJS): Add picture_renderer.c and renderer.c and their associated objects. (GENHEADERS): New variable for generated headers. (EGL_SRCS, EGL_OBJS): New variables. (LOCAL_LIBRARIES, SRCS, OBJS, DEFINES): [HaveEglSupport]: Add EGL defines, libraries, and objects.:(shaders.h): New rule. (depend, cleandir): Depend on generated headers and SRCs. $($(OBJS)): Depend on $(GENHEADERS). * README: Write how to build with EGL support and update content descriptions. * buffer.c (XLPictureFromBuffer): Delete function. (XLRenderBufferFromBuffer): New function. (XLPixmapFromBuffer): Delete function. * compositor.h (enum _Operation, struct _SharedMemoryAttributes) (struct _DmaBufAttributes, union _RenderTarget) (union _RenderBuffer, struct _RenderFuncs, struct _DrmFormat) (struct _ShmFormat, struct _BufferFuncs, struct _ExtBufferFuncs): New structures. (Fallthrough): New define. Define to __attribute__ ((fallthrough)) wherever supported. Replace uses of Picture with RenderBuffer. * dmabuf.c (struct _DrmFormatInfo): Remove structures. (struct _BufferParams): Remove link. (struct _Buffer): Replace pixmap and picture with render buffer object. (dri3_opcode, all_formats, pending_success, next_roundtrip_id) (round_trip_window): Delete. (ReleaseBufferParams, HandleParamsResourceDestroy, ForceRoundTrip) (DepthForFormat, XLHandleErrorForDmabuf, PictFormatForFormat) (DestroyBacking, GetPictureFunc, GetPixmapFunc, GetBufferFunc) (CreateBufferFor, ModifierHigh, FinishBufferCreation) (XLHandleOneXEventForDmabuf, CreateHeader, Create, CreateImmed) (FindFormatMatching, FindSupportedModifiers, FindSupportedFormats) (SendSupportedFormats, HandleBind, InitDrmDevice, WriteFormatTable) (ReallyInitDmabuf, ReadSupportedFormats, XLInitDmabuf): Remove various functions and reimplement as a wrapper around the renderer abstraction, instead of DRI3. * fns.c (struct _Busfault): New structure. (busfault_tree, bus_handler_installed): New variables. (GetHeight, FixHeights, RotateLeft, RotateRight, RebalanceBusfault) (RecordBusfault, DetectBusfault, DeleteMin, RemoveBusfault) (HandleBusfault, MaybeInstallBusHandler, BlockSigbus) (UnblockSigbus, XLRecordBusfault, XLRemoveBusfaults): New functions to store non-overlapping regions of mapped memory in an AVL tree, and to ignore SIGBUS events that trap within. * icon_surface.c (struct _IconSurface): Replace picture with rendering target. (ReleaseBacking, XLGetIconSurface): Use rendering targets instead of pictures. * libraries.def: Add defines for EGL. * run.c (HandleOneXEvent): Replace old dmabuf code with renderer code. * seat.c (CursorFromRole, PictureForCursor, ApplyCursor) (UpdateCursorFromSubcompositor, Subframe, EndSubframe): Rewrite cursor code to use rendering targets and not pictures. * shm.c (Buffer, DereferencePool): Remove SIGBUS protection. (DereferenceBuffer): Reimplement in terms of renderer functions. (GetPictureFunc): Delete function. (GetBufferFunc): New function. (GetPixmapFunc): Delete function. (PrintBuffer): Remove now-broken implementation. (DepthForFormat, PictFormatForFormat): Delete functions, as they are now part of the rendering backend. (IsFormatSupported): New function. (CreateBuffer): Reimplement in terms of renderer functions. (ResizePool): Change SIGBUS protection for resize. (CreatePool): Protect buffer data from SIGBUS should a client truncate the file. (PostFormats): Reimplement in terms of RenderGetShmFormats. (XLInitShm): Stop initializing MIT-SHM. * subcompositor.c (IsTargetAttached): New flag and associated macros. (struct _View): Remove useless field. (struct _Subcompositor): Change target to RenderTarget. Add fields for prior damage. (MakeSubcompositor): Initialize new fields. (SubcompositorSetTarget): Accept RenderTarget, not picture, and set target attached flag. (ViewGetTransform): Delete function. (ViewApplyTransform): New function. (FillBoxesWithTransparency): Reimplement in terms of renderer functions. (StorePreviousDamage): New function. (SubcompositorUpdate): Reimplement in terms of renderer functions. Also, learn to deal with situations where the buffer reflects the state 1 to 2 swaps ago. (SubcompositorExpose): Reimplement in terms of renderer functions. (SubcompositorFree): Free new fields. (SubcompositorInit): Remove no longer required initialization of identity matrix. * xdata.c (ReceiveBody): Fix coding style. * xdg_surface.c (struct _XdgRole, ReleaseBacking, XLGetXdgSurface): Switch from pictures to RenderTargets. * xerror.c (ErrorHandler): Handle errors for picture renderer instead of dmabuf.c.
512 lines
12 KiB
C
512 lines
12 KiB
C
/* Wayland compositor running on top of an X server.
|
|
|
|
Copyright (C) 2022 to various contributors.
|
|
|
|
This file is part of 12to11.
|
|
|
|
12to11 is free software: you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
12to11 is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
/* Generic "icon surface" role. */
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "compositor.h"
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#define IconSurfaceFromRole(role) ((IconSurface *) role)
|
|
|
|
enum
|
|
{
|
|
StateLateFrame = 1,
|
|
StateIsMapped = (1 << 1),
|
|
StateIsReleased = (1 << 2),
|
|
};
|
|
|
|
struct _IconSurface
|
|
{
|
|
/* The role object itself. */
|
|
Role role;
|
|
|
|
/* The window used by this role. */
|
|
Window window;
|
|
|
|
/* The rendering target associated with this role. */
|
|
RenderTarget target;
|
|
|
|
/* The subcompositor associated with this role. */
|
|
Subcompositor *subcompositor;
|
|
|
|
/* The frame clock associated with this role. */
|
|
FrameClock *clock;
|
|
|
|
/* The number of references to this role. */
|
|
int refcount;
|
|
|
|
/* Some state. */
|
|
int state;
|
|
|
|
/* The position of this icon surface relative to the root
|
|
window. */
|
|
int x, y;
|
|
|
|
/* The last known bounds of this icon surface. */
|
|
int min_x, min_y, max_x, max_y;
|
|
};
|
|
|
|
/* Hash table of all icon surfaces. */
|
|
static XLAssocTable *surfaces;
|
|
|
|
static void
|
|
WriteRedirectProperty (IconSurface *icon)
|
|
{
|
|
unsigned long bypass_compositor;
|
|
|
|
bypass_compositor = 2;
|
|
XChangeProperty (compositor.display, icon->window,
|
|
_NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL,
|
|
32, PropModeReplace,
|
|
(unsigned char *) &bypass_compositor, 1);
|
|
}
|
|
|
|
static void
|
|
ReleaseBacking (IconSurface *icon)
|
|
{
|
|
if (--icon->refcount)
|
|
return;
|
|
|
|
/* Release all allocated resources. */
|
|
RenderDestroyRenderTarget (icon->target);
|
|
XDestroyWindow (compositor.display, icon->window);
|
|
|
|
/* And the association. */
|
|
XLDeleteAssoc (surfaces, icon->window);
|
|
|
|
/* There shouldn't be any children of the subcompositor at this
|
|
point. */
|
|
SubcompositorFree (icon->subcompositor);
|
|
|
|
/* The frame clock is no longer useful. */
|
|
XLFreeFrameClock (icon->clock);
|
|
|
|
/* And since there are no C level references to the icon surface
|
|
anymore, it can be freed. */
|
|
XLFree (icon);
|
|
}
|
|
|
|
static void
|
|
Teardown (Surface *surface, Role *role)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
icon = IconSurfaceFromRole (role);
|
|
role->surface = NULL;
|
|
|
|
/* Unparent the surface's views as well. */
|
|
ViewUnparent (surface->view);
|
|
ViewUnparent (surface->under);
|
|
|
|
/* Detach the surface's views from the subcompositor. */
|
|
ViewSetSubcompositor (surface->view, NULL);
|
|
ViewSetSubcompositor (surface->under, NULL);
|
|
|
|
/* Release the backing data. */
|
|
ReleaseBacking (icon);
|
|
}
|
|
|
|
static Bool
|
|
Setup (Surface *surface, Role *role)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
/* Set role->surface here, since this is where the refcounting is
|
|
done as well. */
|
|
role->surface = surface;
|
|
|
|
icon = IconSurfaceFromRole (role);
|
|
ViewSetSubcompositor (surface->view,
|
|
icon->subcompositor);
|
|
ViewSetSubcompositor (surface->under,
|
|
icon->subcompositor);
|
|
|
|
/* Make sure the under view ends up beneath surface->view. */
|
|
SubcompositorInsert (icon->subcompositor,
|
|
surface->under);
|
|
SubcompositorInsert (icon->subcompositor,
|
|
surface->view);
|
|
|
|
/* Retain the backing data. */
|
|
icon->refcount++;
|
|
|
|
return True;
|
|
}
|
|
|
|
static void
|
|
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
|
{
|
|
/* Icon surfaces are not supposed to change much, so doing an XSync
|
|
here is okay. */
|
|
XSync (compositor.display, False);
|
|
|
|
/* Now really release the buffer. */
|
|
XLReleaseBuffer (buffer);
|
|
}
|
|
|
|
static void
|
|
UpdateOutputs (IconSurface *icon)
|
|
{
|
|
int x_off, y_off;
|
|
|
|
if (!icon->role.surface)
|
|
return;
|
|
|
|
x_off = icon->role.surface->current_state.x;
|
|
y_off = icon->role.surface->current_state.y;
|
|
|
|
XLUpdateSurfaceOutputs (icon->role.surface,
|
|
icon->x + icon->min_x + x_off,
|
|
icon->y + icon->min_y + y_off,
|
|
icon->max_x - icon->min_x + 1,
|
|
icon->max_y - icon->min_y + 1);
|
|
}
|
|
|
|
static void
|
|
NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
|
{
|
|
IconSurface *icon;
|
|
int x, y;
|
|
|
|
icon = data;
|
|
|
|
if (min_x != icon->min_x || min_y != icon->min_y
|
|
|| max_x != icon->max_x || max_y != icon->max_y)
|
|
{
|
|
x = icon->x + icon->role.surface->current_state.x;
|
|
y = icon->y + icon->role.surface->current_state.y;
|
|
|
|
/* If the bounds changed, move the window to the right
|
|
position. */
|
|
XMoveResizeWindow (compositor.display, icon->window,
|
|
x + min_x, y + min_y, max_x - min_x + 1,
|
|
max_y - min_y + 1);
|
|
|
|
/* Update the outputs that this surface is inside. */
|
|
UpdateOutputs (icon);
|
|
|
|
/* Save the new bounds. */
|
|
icon->min_x = min_x;
|
|
icon->min_y = min_y;
|
|
icon->max_x = max_x;
|
|
icon->max_y = max_y;
|
|
}
|
|
}
|
|
|
|
static void
|
|
RunFrameCallbacks (Surface *surface)
|
|
{
|
|
struct timespec time;
|
|
|
|
/* Surface can be NULL for various reasons, especially events
|
|
arriving after the icon surface is detached. */
|
|
if (!surface)
|
|
return;
|
|
|
|
clock_gettime (CLOCK_MONOTONIC, &time);
|
|
XLSurfaceRunFrameCallbacks (surface, time);
|
|
}
|
|
|
|
static void
|
|
AfterFrame (FrameClock *clock, void *data)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
icon = data;
|
|
|
|
if (icon->state & StateLateFrame)
|
|
{
|
|
icon->state &= ~StateLateFrame;
|
|
|
|
/* Since we are running late, make the compositor draw the frame
|
|
now. */
|
|
XLFrameClockStartFrame (clock, True);
|
|
SubcompositorUpdate (icon->subcompositor);
|
|
XLFrameClockEndFrame (clock);
|
|
|
|
return;
|
|
}
|
|
|
|
RunFrameCallbacks (icon->role.surface);
|
|
}
|
|
|
|
static void
|
|
MaybeMapWindow (IconSurface *icon)
|
|
{
|
|
if (icon->state & StateIsMapped)
|
|
return;
|
|
|
|
if (icon->state & StateIsReleased)
|
|
return;
|
|
|
|
XMapRaised (compositor.display, icon->window);
|
|
icon->state |= StateIsMapped;
|
|
|
|
UpdateOutputs (icon);
|
|
}
|
|
|
|
static void
|
|
MaybeUnmapWindow (IconSurface *icon)
|
|
{
|
|
if (!(icon->state & StateIsMapped))
|
|
return;
|
|
|
|
XUnmapWindow (compositor.display, icon->window);
|
|
icon->state &= ~StateIsMapped;
|
|
|
|
if (icon->role.surface)
|
|
XLClearOutputs (icon->role.surface);
|
|
}
|
|
|
|
static void
|
|
MoveWindowTo (IconSurface *icon, int x, int y)
|
|
{
|
|
int x_off, y_off;
|
|
|
|
if (icon->x == x && icon->y == y)
|
|
return;
|
|
|
|
icon->x = x;
|
|
icon->y = y;
|
|
x_off = icon->role.surface->current_state.x;
|
|
y_off = icon->role.surface->current_state.y;
|
|
|
|
XMoveWindow (compositor.display, icon->window,
|
|
icon->x + icon->min_x + x_off,
|
|
icon->y + icon->min_y + y_off);
|
|
UpdateOutputs (icon);
|
|
}
|
|
|
|
static void
|
|
Commit (Surface *surface, Role *role)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
icon = IconSurfaceFromRole (role);
|
|
|
|
if (XLFrameClockFrameInProgress (icon->clock))
|
|
{
|
|
/* A frame is already in progress; schedule another one for
|
|
later. */
|
|
icon->state |= StateLateFrame;
|
|
}
|
|
else
|
|
{
|
|
/* Start a frame and update the icon surface now. */
|
|
XLFrameClockStartFrame (icon->clock, False);
|
|
SubcompositorUpdate (icon->subcompositor);
|
|
XLFrameClockEndFrame (icon->clock);
|
|
}
|
|
|
|
/* Move the window if any offset was specified. */
|
|
if (surface->pending_state.pending & PendingAttachments)
|
|
MoveWindowTo (icon, icon->x, icon->y);
|
|
|
|
/* Map or unmap the window according to whether or not the surface
|
|
has an attached buffer. */
|
|
if (surface->current_state.buffer)
|
|
MaybeMapWindow (icon);
|
|
else
|
|
MaybeUnmapWindow (icon);
|
|
}
|
|
|
|
static Bool
|
|
Subframe (Surface *surface, Role *role)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
icon = IconSurfaceFromRole (role);
|
|
|
|
if (XLFrameClockFrameInProgress (icon->clock))
|
|
{
|
|
/* A frame is already in progress; schedule another one for
|
|
later. */
|
|
icon->state |= StateLateFrame;
|
|
return False;
|
|
}
|
|
|
|
/* I guess subsurface updates don't count as urgent frames? */
|
|
XLFrameClockStartFrame (icon->clock, False);
|
|
return True;
|
|
}
|
|
|
|
static void
|
|
EndSubframe (Surface *surface, Role *role)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
icon = IconSurfaceFromRole (role);
|
|
XLFrameClockEndFrame (icon->clock);
|
|
}
|
|
|
|
static Window
|
|
GetWindow (Surface *surface, Role *role)
|
|
{
|
|
/* XLWindowFromSurface is used to obtain a window for input-related
|
|
purposes. Icon surfaces cannot be subject to input, so don't
|
|
return the backing window. */
|
|
return None;
|
|
}
|
|
|
|
IconSurface *
|
|
XLGetIconSurface (Surface *surface)
|
|
{
|
|
IconSurface *role;
|
|
XSetWindowAttributes attrs;
|
|
unsigned int flags;
|
|
|
|
role = XLCalloc (1, sizeof *role);
|
|
role->refcount = 1;
|
|
|
|
role->role.funcs.commit = Commit;
|
|
role->role.funcs.teardown = Teardown;
|
|
role->role.funcs.setup = Setup;
|
|
role->role.funcs.release_buffer = ReleaseBuffer;
|
|
role->role.funcs.subframe = Subframe;
|
|
role->role.funcs.end_subframe = EndSubframe;
|
|
role->role.funcs.get_window = GetWindow;
|
|
|
|
/* Make an override-redirect window to use as the icon surface. */
|
|
flags = (CWColormap | CWBorderPixel | CWEventMask
|
|
| CWOverrideRedirect);
|
|
attrs.colormap = compositor.colormap;
|
|
attrs.border_pixel = border_pixel;
|
|
attrs.event_mask = (ExposureMask | StructureNotifyMask);
|
|
attrs.override_redirect = 1;
|
|
|
|
role->window = XCreateWindow (compositor.display,
|
|
DefaultRootWindow (compositor.display),
|
|
0, 0, 1, 1, 0, compositor.n_planes,
|
|
InputOutput, compositor.visual, flags,
|
|
&attrs);
|
|
|
|
/* Add _NET_WM_SYNC_REQUEST to the list of supported protocols. */
|
|
XSetWMProtocols (compositor.display, role->window,
|
|
&_NET_WM_SYNC_REQUEST, 1);
|
|
|
|
/* Set _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_DND. */
|
|
XChangeProperty (compositor.display, role->window,
|
|
_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
|
|
PropModeReplace,
|
|
(unsigned char *) &_NET_WM_WINDOW_TYPE_DND, 1);
|
|
|
|
/* Create a target associated with the window. */
|
|
role->target = RenderTargetFromWindow (role->window);
|
|
|
|
/* Create a subcompositor associated with the window. */
|
|
role->subcompositor = MakeSubcompositor ();
|
|
role->clock = XLMakeFrameClockForWindow (role->window);
|
|
|
|
/* Set the subcompositor target and some callbacks. */
|
|
SubcompositorSetTarget (role->subcompositor, &role->target);
|
|
SubcompositorSetBoundsCallback (role->subcompositor,
|
|
NoteBounds, role);
|
|
|
|
/* Clear the input region of the window. */
|
|
XShapeCombineRectangles (compositor.display, role->window,
|
|
ShapeInput, 0, 0, NULL, 0, ShapeSet,
|
|
Unsorted);
|
|
|
|
XLMakeAssoc (surfaces, role->window, role);
|
|
|
|
/* Tell the compositing manager to never un-redirect this window.
|
|
If it does, frame synchronization will not work. */
|
|
WriteRedirectProperty (role);
|
|
|
|
/* Initialize frame callbacks. */
|
|
XLFrameClockAfterFrame (role->clock, AfterFrame, role);
|
|
|
|
if (!XLSurfaceAttachRole (surface, &role->role))
|
|
abort ();
|
|
|
|
return role;
|
|
}
|
|
|
|
Bool
|
|
XLHandleOneXEventForIconSurfaces (XEvent *event)
|
|
{
|
|
IconSurface *icon;
|
|
|
|
if (event->type == ClientMessage
|
|
&& ((event->xclient.message_type == _NET_WM_FRAME_DRAWN
|
|
|| event->xclient.message_type == _NET_WM_FRAME_TIMINGS)
|
|
|| (event->xclient.message_type == WM_PROTOCOLS
|
|
&& event->xclient.data.l[0] == _NET_WM_SYNC_REQUEST)))
|
|
{
|
|
icon = XLLookUpAssoc (surfaces, event->xclient.window);
|
|
|
|
if (icon)
|
|
{
|
|
XLFrameClockHandleFrameEvent (icon->clock, event);
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
if (event->type == Expose)
|
|
{
|
|
icon = XLLookUpAssoc (surfaces, event->xexpose.window);
|
|
|
|
if (icon)
|
|
{
|
|
SubcompositorExpose (icon->subcompositor, event);
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
void
|
|
XLMoveIconSurface (IconSurface *surface, int root_x, int root_y)
|
|
{
|
|
MoveWindowTo (surface, root_x, root_y);
|
|
}
|
|
|
|
void
|
|
XLInitIconSurfaces (void)
|
|
{
|
|
/* This assoc table is rather small, since the amount of icon
|
|
surfaces alive at any given time is also low. */
|
|
surfaces = XLCreateAssocTable (25);
|
|
}
|
|
|
|
void
|
|
XLReleaseIconSurface (IconSurface *icon)
|
|
{
|
|
/* Unmap the surface and mark it as released, meaning it will not be
|
|
mapped again in the future. */
|
|
MaybeUnmapWindow (icon);
|
|
icon->state |= StateIsReleased;
|
|
|
|
/* Release the icon surface. */
|
|
ReleaseBacking (icon);
|
|
}
|
|
|
|
Bool
|
|
XLIsWindowIconSurface (Window window)
|
|
{
|
|
return XLLookUpAssoc (surfaces, window) != NULL;
|
|
}
|