forked from 12to11/12to11
Implement wp_viewporter support and fix scaling for fractional values
* 12to11.c (XLMain): Initialize wp_viewporter. * Imakefile (ETAGS): Remove unused variable. (SRCS, OBJS): Add wp_viewporter.c and wp_viewporter.o. (GENHEADERS): Remove unnecessary headers. (viewporter): New scanner target. * README: Document support for wp_viewporter. * compositor.h (struct _ViewportExt): New forward declaration. (struct _DrawParams): New fields for cropping and stretching. (struct _RenderFuncs): Describe how composite works. (struct _BufferFuncs): Make update_buffer_for_damage take DrawParams as an argument. (struct _State): New fields for viewporting. (struct _Surface): New field `viewport' and associated input delta. (struct _XdgRoleImplementationFuncs): New field `is_window_mapped'. Do not commit while unmapped. * dmabuf.c (XLInitDmabuf): Remove outdated comment. * dnd.c (HandleMotion): Use TruncateWindowToSurface. * egl.c (struct _EglBuffer): Add 3x3 reverse transformation matrix. (struct _CompositeProgram): Rename `scale' to `source'. (Index): New macro. (PickBetterVisual, FindVisual): Compensate for EGL picking a non-RGBA visual. (EglCompileCompositeProgram): Look for source, not scale. (ComputeTransformMatrix): New function. (Composite): Compute transformation matrix and draw using that. (BufferFromDmaBuf, BufferFromShm): Copy identity transform and stop setting scale. (ReverseTransformToBox): New function. (UpdateShmBufferIncrementally): Accept DrawParams and invert damage according to that. (UpdateBuffer, UpdateBufferForDamage): Pass draw params to the incremental buffer update function. * fns.c (XLExtendRegion): New function. * frame_clock.c (CurrentHighPrecisionTimestamp): Delete function. (HighPrecisionTimestamp, HighPrecisionTimestamp32): New functions. (PostEndFrame): Handle X server time truncation to 32 bits. (XLFrameClockFreeze): Remove trailing whitespace. * picture_renderer.c (GetSourceX, GetSourceY, CompareStretch): New functions. (MaybeApplyTransform): Check more values before applying transformations. Then, handle stretch and offset. * positioner.c (GetAdjustmentOffset, ApplyConstraintAdjustment) (XLPositionerCalculateGeometry): Scale coordinates using new functions. * renderer.c (RenderUpdateBufferForDamage): Accept DrawParams instead of scale. * shaders.txt (Composite Rectangle Fragment Shader RGBA) (Composite Rectangle Fragment Shader RGBX) (Composite Rectangle Fragment Shader External): Stop transforming texcoords. (Composite Rectangle Vertex Shader): Transform texcoords in the vertex shader instead. * subcompositor.c (IsViewported, SetViewported, ClearViewported): New functions. (struct _View): New fields for tracking viewports and fractional offsets. (ViewAttachBuffer): Do not garbage upon buffer size change if a viewport is set. (ViewMoveFractional): New function. (ViewDamage): Describe what the damage is and is not transformed by. (GetContentScale): New function. (ViewWidth, ViewHeight): Apply viewport. (ViewSetScale): Use ViewAfterSizeUpdate instead of duplicating code. (ViewSetViewport, ViewClearViewport): New functions. (ViewComputeTransform): Compute transform for viewports. New arg draw; use it to determine whether or not to include a fractional offset. (IntersectBoxes): Fix intersection calculation. (SubcompositorUpdate): Don't keep calling ViewWidth and ViewHeight in a loop. (SubcompositorExpose): Adjust for changes to buffer damage uploading. * subsurface.c (MoveFractional): New function. Handle fractional offsets after scaling. (MaybeUpdateOutputs, AfterParentCommit, Setup, Rescale): Use that function to move the subsurface instead. * surface.c (ApplyScale): Update comment. (ApplyViewport, CheckViewportValues): New functions. (HandleScaleChanged): Apply the viewport as well upon scale change. (ApplyDamage): Improve damage calculation for viewported surfaces. (SavePendingState, InternalCommit): Save and commit viewport state; check old values upon buffer commit. (InitState): Initialize viewport to initial values. (XLSurfaceRunFrameCallbacks): Handle overflows of 32-bit time at the 49-day mark. (SurfaceToWindow, ScaleToWindow, WindowToSurface, ScaleToSurface) (TruncateScaleToWindow, TruncateScaleToWindow) (TruncateWindowToSurface, TruncateScaleToSurface): New functions for handling scale. * xdg_popup.c (MoveWindow, IsWindowMapped, XLGetXdgPopup): * xdg_surface.c (IsRoleMapped, Commit, Subframe) (GetResizeDimensions, XLXdgRoleCalcNewWindowSize): * xdg_toplevel.c (IsWindowMapped, NoteConfigureTime, SendStates) (RecordStateSize, HandleWindowGeometryChange, NoteWindowPreResize) (XLGetXdgToplevel): Use them instead of manually multiplying with the factor.
This commit is contained in:
parent
dfcd969d3e
commit
4d2e85d002
19 changed files with 1266 additions and 275 deletions
1
12to11.c
1
12to11.c
|
@ -122,6 +122,7 @@ XLMain (int argc, char **argv)
|
||||||
XLInitIconSurfaces ();
|
XLInitIconSurfaces ();
|
||||||
XLInitPrimarySelection ();
|
XLInitPrimarySelection ();
|
||||||
XLInitExplicitSynchronization ();
|
XLInitExplicitSynchronization ();
|
||||||
|
XLInitWpViewporter ();
|
||||||
/* This has to come after the rest of the initialization. */
|
/* This has to come after the rest of the initialization. */
|
||||||
DetermineServerTime ();
|
DetermineServerTime ();
|
||||||
XLRunCompositor ();
|
XLRunCompositor ();
|
||||||
|
|
13
Imakefile
13
Imakefile
|
@ -8,8 +8,6 @@ SYS_LIBRARIES = MathLibrary ThreadsLibraries
|
||||||
DEPLIBS = $(DEPXLIB) $(DEPEXTENSIONLIB) $(DEPXRANDRLIB) $(DEPXRENDERLIB) \
|
DEPLIBS = $(DEPXLIB) $(DEPEXTENSIONLIB) $(DEPXRANDRLIB) $(DEPXRENDERLIB) \
|
||||||
$(DEPXFIXESLIB) $(DEPXILIB) $(DEPXKBFILELIB)
|
$(DEPXFIXESLIB) $(DEPXILIB) $(DEPXKBFILELIB)
|
||||||
|
|
||||||
ETAGS = etags
|
|
||||||
|
|
||||||
LOCAL_LIBRARIES = $(XLIB) $(EXTENSIONLIB) $(XCBLIB) $(XCB) $(XCB_SHM) \
|
LOCAL_LIBRARIES = $(XLIB) $(EXTENSIONLIB) $(XCBLIB) $(XCB) $(XCB_SHM) \
|
||||||
$(XRANDRLIB) $(PIXMAN) $(XRENDERLIB) $(XILIB) $(XKBFILELIB) $(XFIXESLIB) \
|
$(XRANDRLIB) $(PIXMAN) $(XRENDERLIB) $(XILIB) $(XKBFILELIB) $(XFIXESLIB) \
|
||||||
$(XCB_DRI3) $(XCB_SHAPE) $(WAYLAND_SERVER)
|
$(XCB_DRI3) $(XCB_SHAPE) $(WAYLAND_SERVER)
|
||||||
|
@ -22,7 +20,8 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
|
||||||
ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c \
|
ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.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
|
picture_renderer.c explicit_synchronization.c transform.c \
|
||||||
|
wp_viewporter.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,11 +29,10 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
||||||
ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o \
|
ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.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
|
picture_renderer.o explicit_synchronization.o transform.o \
|
||||||
|
wp_viewporter.o
|
||||||
|
|
||||||
GENHEADERS = transfer_atoms.h primary-selection-unstable-v1.h \
|
GENHEADERS = transfer_atoms.h
|
||||||
linux-dmabuf-unstable-v1.h xdg-shell.h \
|
|
||||||
linux-explicit-synchronization-unstable-v1.h
|
|
||||||
|
|
||||||
#ifdef HaveEglSupport
|
#ifdef HaveEglSupport
|
||||||
|
|
||||||
|
@ -111,6 +109,7 @@ ScannerTarget(linux-dmabuf-unstable-v1)
|
||||||
ScannerTarget(xdg-shell)
|
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
|
|
3
README
3
README
|
@ -3,7 +3,7 @@ preferably with a compositing manager running.
|
||||||
|
|
||||||
It is not yet complete. What is not yet implemented includes support
|
It is not yet complete. What is not yet implemented includes support
|
||||||
for touchscreens, input methods, device switching in dmabuf feedback,
|
for touchscreens, input methods, device switching in dmabuf feedback,
|
||||||
and the viewporter protocol extension.
|
and the single-pixel buffer protocol extension.
|
||||||
|
|
||||||
There are also problems with output reporting in subsurfaces.
|
There are also problems with output reporting in subsurfaces.
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ complete degree:
|
||||||
'wl_data_device_manager', version: 3
|
'wl_data_device_manager', version: 3
|
||||||
'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
|
||||||
|
|
||||||
When built with EGL, the following Wayland protocol is also supported:
|
When built with EGL, the following Wayland protocol is also supported:
|
||||||
|
|
||||||
|
|
89
compositor.h
89
compositor.h
|
@ -1,4 +1,4 @@
|
||||||
/* Wayland compositor running on top of an X serer.
|
/* Wayland compositor running on top of an X server.
|
||||||
|
|
||||||
Copyright (C) 2022 to various contributors.
|
Copyright (C) 2022 to various contributors.
|
||||||
|
|
||||||
|
@ -90,6 +90,10 @@ typedef struct _Seat Seat;
|
||||||
|
|
||||||
typedef struct _PDataSource PDataSource;
|
typedef struct _PDataSource PDataSource;
|
||||||
|
|
||||||
|
/* Forward declarations from wp_viewporter.c. */
|
||||||
|
|
||||||
|
typedef struct _ViewportExt ViewportExt;
|
||||||
|
|
||||||
/* Defined in 12to11.c. */
|
/* Defined in 12to11.c. */
|
||||||
|
|
||||||
extern Compositor compositor;
|
extern Compositor compositor;
|
||||||
|
@ -125,7 +129,13 @@ enum _Operation
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/* Scale has been set. */
|
/* Scale has been set. */
|
||||||
ScaleSet = 1,
|
ScaleSet = 1,
|
||||||
|
|
||||||
|
/* Offset has been set. */
|
||||||
|
OffsetSet = (1 << 2),
|
||||||
|
|
||||||
|
/* Stretch has been set. */
|
||||||
|
StretchSet = (1 << 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _DrawParams
|
struct _DrawParams
|
||||||
|
@ -135,6 +145,15 @@ struct _DrawParams
|
||||||
|
|
||||||
/* A scale factor to apply to the buffer. */
|
/* A scale factor to apply to the buffer. */
|
||||||
double scale;
|
double scale;
|
||||||
|
|
||||||
|
/* Offset from which to start sampling from the buffer, after
|
||||||
|
scaling. */
|
||||||
|
double off_x, off_y;
|
||||||
|
|
||||||
|
/* The crop, width and height of the buffer. The buffer will be
|
||||||
|
stretched or shrunk to this size, after being cropped to
|
||||||
|
crop and being offset by -off_x, -off_y. */
|
||||||
|
double crop_width, crop_height, stretch_width, stretch_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _SharedMemoryAttributes
|
struct _SharedMemoryAttributes
|
||||||
|
@ -261,7 +280,10 @@ struct _RenderFuncs
|
||||||
/* Composite width, height, from the given buffer onto the given
|
/* Composite width, height, from the given buffer onto the given
|
||||||
target, at x, y. The arguments are: buffer, target, operation,
|
target, at x, y. The arguments are: buffer, target, operation,
|
||||||
source_x, source_y, x, y, width, height, params. params
|
source_x, source_y, x, y, width, height, params. params
|
||||||
describes how to transform the given buffer. */
|
describes how to transform the given buffer.
|
||||||
|
|
||||||
|
Reads outside the texture contents should result in transparency
|
||||||
|
being composited. */
|
||||||
void (*composite) (RenderBuffer, RenderTarget, Operation, int, int,
|
void (*composite) (RenderBuffer, RenderTarget, Operation, int, int,
|
||||||
int, int, int, int, DrawParams *);
|
int, int, int, int, DrawParams *);
|
||||||
|
|
||||||
|
@ -360,10 +382,11 @@ struct _BufferFuncs
|
||||||
/* Notice that the given buffer has been damaged. May be NULL. If
|
/* Notice that the given buffer has been damaged. May be NULL. If
|
||||||
the given NULL damage, assume that the entire buffer has been
|
the given NULL damage, assume that the entire buffer has been
|
||||||
damaged. Must be called at least once before any rendering can
|
damaged. Must be called at least once before any rendering can
|
||||||
be performed on the buffer. 3rd arg is the scale by which to
|
be performed on the buffer. 3rd arg is a DrawParams struct
|
||||||
divide the buffer. */
|
describing a transform to inversely apply to the damage
|
||||||
|
region. */
|
||||||
void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *,
|
void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *,
|
||||||
float);
|
DrawParams *);
|
||||||
|
|
||||||
/* Return whether or not the buffer contents can be released early,
|
/* Return whether or not the buffer contents can be released early,
|
||||||
by being copied to an offscreen buffer. */
|
by being copied to an offscreen buffer. */
|
||||||
|
@ -410,7 +433,7 @@ extern Bool RenderValidateShmParams (uint32_t, uint32_t, uint32_t, int32_t,
|
||||||
extern void RenderFreeShmBuffer (RenderBuffer);
|
extern void RenderFreeShmBuffer (RenderBuffer);
|
||||||
extern void RenderFreeDmabufBuffer (RenderBuffer);
|
extern void RenderFreeDmabufBuffer (RenderBuffer);
|
||||||
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *,
|
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *,
|
||||||
float);
|
DrawParams *);
|
||||||
extern Bool RenderCanReleaseNow (RenderBuffer);
|
extern Bool RenderCanReleaseNow (RenderBuffer);
|
||||||
|
|
||||||
/* Defined in run.c. */
|
/* Defined in run.c. */
|
||||||
|
@ -503,6 +526,8 @@ extern int XLOpenShm (void);
|
||||||
|
|
||||||
extern void XLScaleRegion (pixman_region32_t *, pixman_region32_t *,
|
extern void XLScaleRegion (pixman_region32_t *, pixman_region32_t *,
|
||||||
float, float);
|
float, float);
|
||||||
|
extern void XLExtendRegion (pixman_region32_t *, pixman_region32_t *,
|
||||||
|
int, int);
|
||||||
extern Time XLGetServerTimeRoundtrip (void);
|
extern Time XLGetServerTimeRoundtrip (void);
|
||||||
|
|
||||||
extern RootWindowSelection *XLSelectInputFromRootWindow (unsigned long);
|
extern RootWindowSelection *XLSelectInputFromRootWindow (unsigned long);
|
||||||
|
@ -625,6 +650,11 @@ extern void ViewMove (View *, int, int);
|
||||||
extern void ViewDetach (View *);
|
extern void ViewDetach (View *);
|
||||||
extern void ViewMap (View *);
|
extern void ViewMap (View *);
|
||||||
extern void ViewUnmap (View *);
|
extern void ViewUnmap (View *);
|
||||||
|
extern void ViewMoveFractional (View *, double, double);
|
||||||
|
|
||||||
|
extern void ViewSetViewport (View *, double, double, double, double,
|
||||||
|
double, double);
|
||||||
|
extern void ViewClearViewport (View *);
|
||||||
|
|
||||||
extern void ViewSetData (View *, void *);
|
extern void ViewSetData (View *, void *);
|
||||||
extern void *ViewGetData (View *);
|
extern void *ViewGetData (View *);
|
||||||
|
@ -673,6 +703,8 @@ enum
|
||||||
PendingFrameCallbacks = (1 << 6),
|
PendingFrameCallbacks = (1 << 6),
|
||||||
PendingBufferScale = (1 << 7),
|
PendingBufferScale = (1 << 7),
|
||||||
PendingAttachments = (1 << 8),
|
PendingAttachments = (1 << 8),
|
||||||
|
PendingViewportSrc = (1 << 9),
|
||||||
|
PendingViewportDest = (1 << 10),
|
||||||
|
|
||||||
/* Flags here are stored in `pending' of the current state for
|
/* Flags here are stored in `pending' of the current state for
|
||||||
space reasons. */
|
space reasons. */
|
||||||
|
@ -717,6 +749,14 @@ struct _State
|
||||||
|
|
||||||
/* Attachment position. */
|
/* Attachment position. */
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
|
/* Viewport destination width and height. All viewport coordinates
|
||||||
|
and dimensions are specified in terms of the surface coordinate
|
||||||
|
system. */
|
||||||
|
int dest_width, dest_height;
|
||||||
|
|
||||||
|
/* Viewport source rectangle. */
|
||||||
|
double src_x, src_y, src_width, src_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum _ClientDataType ClientDataType;
|
typedef enum _ClientDataType ClientDataType;
|
||||||
|
@ -848,6 +888,13 @@ struct _Surface
|
||||||
/* The scale factor used to convert from surface coordinates to
|
/* The scale factor used to convert from surface coordinates to
|
||||||
window coordinates. */
|
window coordinates. */
|
||||||
double factor;
|
double factor;
|
||||||
|
|
||||||
|
/* Any associated viewport resource. */
|
||||||
|
ViewportExt *viewport;
|
||||||
|
|
||||||
|
/* Any associated input delta. This is used to compensate
|
||||||
|
for fractional subsurface placement while handling input. */
|
||||||
|
double input_delta_x, input_delta_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _RoleFuncs
|
struct _RoleFuncs
|
||||||
|
@ -917,6 +964,16 @@ extern void XLSurfaceMoveBy (Surface *, int, int);
|
||||||
extern Window XLWindowFromSurface (Surface *);
|
extern Window XLWindowFromSurface (Surface *);
|
||||||
extern void XLUpdateSurfaceOutputs (Surface *, int, int, int, int);
|
extern void XLUpdateSurfaceOutputs (Surface *, int, int, int, int);
|
||||||
|
|
||||||
|
extern void SurfaceToWindow (Surface *, double, double, double *, double *);
|
||||||
|
extern void ScaleToWindow (Surface *, double, double, double *, double *);
|
||||||
|
extern void WindowToSurface (Surface *, double, double, double *, double *);
|
||||||
|
extern void ScaleToSurface (Surface *, double, double, double *, double *);
|
||||||
|
|
||||||
|
extern void TruncateSurfaceToWindow (Surface *, int, int, int *, int *);
|
||||||
|
extern void TruncateScaleToWindow (Surface *, int, int, int *, int *);
|
||||||
|
extern void TruncateWindowToSurface (Surface *, int, int, int *, int *);
|
||||||
|
extern void TruncateScaleToSurface (Surface *, int, int, int *, int *);
|
||||||
|
|
||||||
/* Defined in output.c. */
|
/* Defined in output.c. */
|
||||||
|
|
||||||
extern int global_scale_factor;
|
extern int global_scale_factor;
|
||||||
|
@ -1016,6 +1073,7 @@ struct _XdgRoleImplementationFuncs
|
||||||
void (*handle_geometry_change) (Role *, XdgRoleImplementation *);
|
void (*handle_geometry_change) (Role *, XdgRoleImplementation *);
|
||||||
void (*post_resize) (Role *, XdgRoleImplementation *, int, int, int, int);
|
void (*post_resize) (Role *, XdgRoleImplementation *, int, int, int, int);
|
||||||
void (*commit_inside_frame) (Role *, XdgRoleImplementation *);
|
void (*commit_inside_frame) (Role *, XdgRoleImplementation *);
|
||||||
|
Bool (*is_window_mapped) (Role *, XdgRoleImplementation *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _XdgRoleImplementation
|
struct _XdgRoleImplementation
|
||||||
|
@ -1349,6 +1407,23 @@ extern void XLSyncRelease (SyncRelease *);
|
||||||
extern void XLWaitFence (Surface *);
|
extern void XLWaitFence (Surface *);
|
||||||
extern void XLInitExplicitSynchronization (void);
|
extern void XLInitExplicitSynchronization (void);
|
||||||
|
|
||||||
|
/* Defined in transform.c. */
|
||||||
|
|
||||||
|
/* N.B. the data is stored in column-major order. */
|
||||||
|
typedef float Matrix[9];
|
||||||
|
|
||||||
|
extern void MatrixMultiply (Matrix, Matrix, Matrix *);
|
||||||
|
extern void MatrixIdentity (Matrix *);
|
||||||
|
extern void MatrixTranslate (Matrix *, float, float);
|
||||||
|
extern void MatrixScale (Matrix *, float, float);
|
||||||
|
extern void MatrixExport (Matrix *, XTransform *);
|
||||||
|
|
||||||
|
/* Defined in wp_viewporter.c. */
|
||||||
|
|
||||||
|
extern void XLInitWpViewporter (void);
|
||||||
|
extern void XLWpViewportReportBadSize (ViewportExt *);
|
||||||
|
extern void XLWpViewportReportOutOfBuffer (ViewportExt *);
|
||||||
|
|
||||||
/* 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])
|
||||||
|
|
3
dmabuf.c
3
dmabuf.c
|
@ -1068,9 +1068,6 @@ XLInitDmabuf (void)
|
||||||
/* And try to create the format table. */
|
/* And try to create the format table. */
|
||||||
size = WriteFormatTable ();
|
size = WriteFormatTable ();
|
||||||
|
|
||||||
/* Create an unmapped, InputOnly window, that is used to receive
|
|
||||||
roundtrip events. */
|
|
||||||
|
|
||||||
global_dmabuf = wl_global_create (compositor.wl_display,
|
global_dmabuf = wl_global_create (compositor.wl_display,
|
||||||
&zwp_linux_dmabuf_v1_interface,
|
&zwp_linux_dmabuf_v1_interface,
|
||||||
/* If writing the format table
|
/* If writing the format table
|
||||||
|
|
10
dnd.c
10
dnd.c
|
@ -897,12 +897,10 @@ HandleMotion (Surface *toplevel, int x, int y, uint32_t action,
|
||||||
/* Compute the surface-relative coordinates and scale them. */
|
/* Compute the surface-relative coordinates and scale them. */
|
||||||
|
|
||||||
if (child)
|
if (child)
|
||||||
{
|
/* x_out and y_out are only used if dnd_state.child ends up
|
||||||
/* x_out and y_out are only used if dnd_state.child ends up
|
non-NULL. */
|
||||||
non-NULL. */
|
TruncateWindowToSurface (child, x - x_off, y - y_off,
|
||||||
*x_out = (x - x_off) / child->factor;
|
x_out, y_out);
|
||||||
*y_out = (y - y_off) / child->factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dnd_state.child == child)
|
if (dnd_state.child == child)
|
||||||
/* If nothing changed, don't do anything. */
|
/* If nothing changed, don't do anything. */
|
||||||
|
|
312
egl.c
312
egl.c
|
@ -123,6 +123,11 @@ struct _EglBuffer
|
||||||
/* The texture name of any generated texture. */
|
/* The texture name of any generated texture. */
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
|
|
||||||
|
/* 3x3 matrix that is used to transform texcoord into actual texture
|
||||||
|
coordinates. Note that GLfloat[9] should be the same type as
|
||||||
|
Matrix. */
|
||||||
|
GLfloat matrix[9];
|
||||||
|
|
||||||
/* The width and height of the buffer. */
|
/* The width and height of the buffer. */
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
|
@ -180,13 +185,17 @@ struct _CompositeProgram
|
||||||
/* The index of the texture uniform. */
|
/* The index of the texture uniform. */
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
|
|
||||||
/* The index of the scale uniform. */
|
/* The index of the source uniform. */
|
||||||
GLuint scale;
|
GLuint source;
|
||||||
|
|
||||||
/* The index of the invert_y uniform. */
|
/* The index of the invert_y uniform. */
|
||||||
GLuint invert_y;
|
GLuint invert_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This macro makes column major order easier to reason about for C
|
||||||
|
folks. */
|
||||||
|
#define Index(matrix, row, column) ((matrix)[(column) * 3 + (row)])
|
||||||
|
|
||||||
/* All known SHM formats. */
|
/* All known SHM formats. */
|
||||||
static FormatInfo known_shm_formats[] =
|
static FormatInfo known_shm_formats[] =
|
||||||
{
|
{
|
||||||
|
@ -531,6 +540,134 @@ EglInitGlFuncs (void)
|
||||||
IWaitSync = NULL;
|
IWaitSync = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Visual *
|
||||||
|
PickBetterVisual (Visual *visual, int *depth)
|
||||||
|
{
|
||||||
|
XRenderPictFormat target_format, *format, *found;
|
||||||
|
int i, num_x_formats, bpp, n_visuals, j;
|
||||||
|
EGLint alpha_size;
|
||||||
|
XPixmapFormatValues *formats;
|
||||||
|
XVisualInfo empty_template, *visuals;
|
||||||
|
|
||||||
|
/* First, see if there is already an alpha channel. */
|
||||||
|
format = XRenderFindVisualFormat (compositor.display, visual);
|
||||||
|
|
||||||
|
if (!format)
|
||||||
|
return visual;
|
||||||
|
|
||||||
|
if (format->type != PictTypeDirect)
|
||||||
|
/* Can this actually happen? */
|
||||||
|
return visual;
|
||||||
|
|
||||||
|
if (format->direct.alphaMask)
|
||||||
|
return visual;
|
||||||
|
|
||||||
|
/* Next, build the target format from the visual format. */
|
||||||
|
target_format.type = PictTypeDirect;
|
||||||
|
target_format.direct = format->direct;
|
||||||
|
|
||||||
|
/* Obtain the size of the alpha mask in the EGL config. */
|
||||||
|
if (!eglGetConfigAttrib (egl_display, egl_config,
|
||||||
|
EGL_ALPHA_SIZE, &alpha_size))
|
||||||
|
return visual;
|
||||||
|
|
||||||
|
if (alpha_size > 16)
|
||||||
|
/* If the alpha mask is too big, then use the chosen visual. */
|
||||||
|
return visual;
|
||||||
|
|
||||||
|
/* Add the alpha mask. */
|
||||||
|
for (i = 0; i < alpha_size; ++i)
|
||||||
|
target_format.direct.alphaMask |= 1 << i;
|
||||||
|
|
||||||
|
/* Look for matching picture formats with the same bpp and a larger
|
||||||
|
depth. */
|
||||||
|
formats = XListPixmapFormats (compositor.display, &num_x_formats);
|
||||||
|
|
||||||
|
if (!formats)
|
||||||
|
return visual;
|
||||||
|
|
||||||
|
/* Obtain the number of bits per pixel for the given depth. */
|
||||||
|
bpp = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < num_x_formats; ++i)
|
||||||
|
{
|
||||||
|
if (formats[i].depth == format->depth)
|
||||||
|
bpp = formats[i].bits_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bpp)
|
||||||
|
{
|
||||||
|
XFree (formats);
|
||||||
|
return visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a list of all visuals. */
|
||||||
|
empty_template.screen = DefaultScreen (compositor.display);
|
||||||
|
visuals = XGetVisualInfo (compositor.display, VisualScreenMask,
|
||||||
|
&empty_template, &n_visuals);
|
||||||
|
|
||||||
|
if (!visuals)
|
||||||
|
{
|
||||||
|
XFree (formats);
|
||||||
|
return visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, loop through each depth. */
|
||||||
|
|
||||||
|
for (i = 0; i < num_x_formats; ++i)
|
||||||
|
{
|
||||||
|
if (formats[i].depth > format->depth
|
||||||
|
&& formats[i].bits_per_pixel == bpp)
|
||||||
|
{
|
||||||
|
/* Try to find a matching picture format. */
|
||||||
|
target_format.depth = formats[i].depth;
|
||||||
|
|
||||||
|
found = XRenderFindFormat (compositor.display,
|
||||||
|
PictFormatType
|
||||||
|
| PictFormatDepth
|
||||||
|
| PictFormatRed
|
||||||
|
| PictFormatGreen
|
||||||
|
| PictFormatBlue
|
||||||
|
| PictFormatRedMask
|
||||||
|
| PictFormatBlueMask
|
||||||
|
| PictFormatGreenMask
|
||||||
|
| PictFormatAlphaMask,
|
||||||
|
&target_format, 0);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
/* Now try to find the corresponding visual. */
|
||||||
|
|
||||||
|
for (j = 0; j < n_visuals; ++j)
|
||||||
|
{
|
||||||
|
if (visuals[j].depth != formats[i].depth)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (XRenderFindVisualFormat (compositor.display,
|
||||||
|
visuals[j].visual) == found)
|
||||||
|
{
|
||||||
|
/* We got a usable visual with an alpha channel
|
||||||
|
otherwise matching the characteristics of the
|
||||||
|
visual specified by EGL. Return. */
|
||||||
|
*depth = formats[i].depth;
|
||||||
|
visual = visuals[j].visual;
|
||||||
|
|
||||||
|
XFree (visuals);
|
||||||
|
XFree (formats);
|
||||||
|
return visual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, nothing was found. Return the original visual
|
||||||
|
untouched, but free visuals. */
|
||||||
|
XFree (visuals);
|
||||||
|
XFree (formats);
|
||||||
|
return visual;
|
||||||
|
}
|
||||||
|
|
||||||
static Visual *
|
static Visual *
|
||||||
FindVisual (VisualID visual, int *depth)
|
FindVisual (VisualID visual, int *depth)
|
||||||
{
|
{
|
||||||
|
@ -568,6 +705,12 @@ FindVisual (VisualID visual, int *depth)
|
||||||
them. */
|
them. */
|
||||||
|
|
||||||
value = visuals->visual;
|
value = visuals->visual;
|
||||||
|
|
||||||
|
/* EGL does not know how to find visuals with an alpha channel, even
|
||||||
|
if we specify one in the framebuffer configuration. Detect when
|
||||||
|
that is the case, and pick a better visual. */
|
||||||
|
value = PickBetterVisual (value, &visuals->depth);
|
||||||
|
|
||||||
*depth = visuals->depth;
|
*depth = visuals->depth;
|
||||||
|
|
||||||
XLFree (visuals);
|
XLFree (visuals);
|
||||||
|
@ -735,8 +878,8 @@ EglCompileCompositeProgram (CompositeProgram *program,
|
||||||
"pos");
|
"pos");
|
||||||
program->texture = glGetUniformLocation (program->program,
|
program->texture = glGetUniformLocation (program->program,
|
||||||
"texture");
|
"texture");
|
||||||
program->scale = glGetUniformLocation (program->program,
|
program->source = glGetUniformLocation (program->program,
|
||||||
"scale");
|
"source");
|
||||||
program->invert_y = glGetUniformLocation (program->program,
|
program->invert_y = glGetUniformLocation (program->program,
|
||||||
"invert_y");
|
"invert_y");
|
||||||
|
|
||||||
|
@ -1162,6 +1305,39 @@ GetTextureTarget (EglBuffer *buffer)
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ComputeTransformMatrix (EglBuffer *buffer, DrawParams *params)
|
||||||
|
{
|
||||||
|
/* Update the transformation matrix of BUFFER. This is a 3x3
|
||||||
|
transformation matrix that maps from texcoords to actual
|
||||||
|
coordinates in the buffer. */
|
||||||
|
|
||||||
|
/* Copy over the identity transform. */
|
||||||
|
MatrixIdentity (&buffer->matrix);
|
||||||
|
|
||||||
|
/* Set the X and Y scales. */
|
||||||
|
if (params->flags & ScaleSet)
|
||||||
|
{
|
||||||
|
Index (buffer->matrix, 0, 0)
|
||||||
|
= (float) (1.0 / params->scale);
|
||||||
|
Index (buffer->matrix, 1, 1)
|
||||||
|
= (float) (1.0 / params->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the offsets. */
|
||||||
|
if (params->flags & OffsetSet)
|
||||||
|
MatrixTranslate (&buffer->matrix,
|
||||||
|
(float) (params->off_x / buffer->width),
|
||||||
|
(float) (params->off_y / buffer->height));
|
||||||
|
|
||||||
|
/* Set the stretch. */
|
||||||
|
if (params->flags & StretchSet)
|
||||||
|
/* Scale the buffer down by this much. */
|
||||||
|
MatrixScale (&buffer->matrix,
|
||||||
|
(float) (params->crop_width / params->stretch_width),
|
||||||
|
(float) (params->crop_height / params->stretch_height));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Composite (RenderBuffer buffer, RenderTarget target,
|
Composite (RenderBuffer buffer, RenderTarget target,
|
||||||
Operation op, int src_x, int src_y, int x, int y,
|
Operation op, int src_x, int src_y, int x, int y,
|
||||||
|
@ -1173,7 +1349,6 @@ Composite (RenderBuffer buffer, RenderTarget target,
|
||||||
EglBuffer *egl_buffer;
|
EglBuffer *egl_buffer;
|
||||||
CompositeProgram *program;
|
CompositeProgram *program;
|
||||||
GLenum tex_target;
|
GLenum tex_target;
|
||||||
GLfloat scale;
|
|
||||||
|
|
||||||
egl_target = target.pointer;
|
egl_target = target.pointer;
|
||||||
egl_buffer = buffer.pointer;
|
egl_buffer = buffer.pointer;
|
||||||
|
@ -1188,6 +1363,10 @@ Composite (RenderBuffer buffer, RenderTarget target,
|
||||||
/* Get the texturing target. */
|
/* Get the texturing target. */
|
||||||
tex_target = GetTextureTarget (egl_buffer);
|
tex_target = GetTextureTarget (egl_buffer);
|
||||||
|
|
||||||
|
/* Compute the transformation matrix to use to draw the given
|
||||||
|
buffer. */
|
||||||
|
ComputeTransformMatrix (egl_buffer, params);
|
||||||
|
|
||||||
/* dest rectangle on target. */
|
/* dest rectangle on target. */
|
||||||
x1 = x;
|
x1 = x;
|
||||||
y1 = y;
|
y1 = y;
|
||||||
|
@ -1233,18 +1412,17 @@ Composite (RenderBuffer buffer, RenderTarget target,
|
||||||
else
|
else
|
||||||
glDisable (GL_BLEND);
|
glDisable (GL_BLEND);
|
||||||
|
|
||||||
if (params->flags & ScaleSet)
|
|
||||||
scale = params->scale;
|
|
||||||
else
|
|
||||||
scale = 1.0f;
|
|
||||||
|
|
||||||
glActiveTexture (GL_TEXTURE0);
|
glActiveTexture (GL_TEXTURE0);
|
||||||
glBindTexture (tex_target, egl_buffer->texture);
|
glBindTexture (tex_target, egl_buffer->texture);
|
||||||
glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER,
|
||||||
|
GL_NEAREST);
|
||||||
|
glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER,
|
||||||
|
GL_NEAREST);
|
||||||
glUseProgram (program->program);
|
glUseProgram (program->program);
|
||||||
|
|
||||||
glUniform1i (program->texture, 0);
|
glUniform1i (program->texture, 0);
|
||||||
glUniform1f (program->scale, scale);
|
glUniformMatrix3fv (program->source, 1, GL_FALSE,
|
||||||
|
egl_buffer->matrix);
|
||||||
glUniform1i (program->invert_y, egl_buffer->flags & InvertY);
|
glUniform1i (program->invert_y, egl_buffer->flags & InvertY);
|
||||||
glVertexAttribPointer (program->position, 2, GL_FLOAT,
|
glVertexAttribPointer (program->position, 2, GL_FLOAT,
|
||||||
GL_FALSE, 0, verts);
|
GL_FALSE, 0, verts);
|
||||||
|
@ -1501,6 +1679,10 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
|
||||||
buffer->width = attributes->width;
|
buffer->width = attributes->width;
|
||||||
buffer->height = attributes->height;
|
buffer->height = attributes->height;
|
||||||
buffer->u.type = DmaBufBuffer;
|
buffer->u.type = DmaBufBuffer;
|
||||||
|
|
||||||
|
/* Copy over the identity transform. */
|
||||||
|
MatrixIdentity (&buffer->matrix);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
/* Find the DRM format in question so we can determine the right
|
/* Find the DRM format in question so we can determine the right
|
||||||
|
@ -1651,6 +1833,9 @@ BufferFromShm (SharedMemoryAttributes *attributes, Bool *error)
|
||||||
buffer->height = attributes->height;
|
buffer->height = attributes->height;
|
||||||
buffer->u.type = ShmBuffer;
|
buffer->u.type = ShmBuffer;
|
||||||
|
|
||||||
|
/* Copy over the identity transform. */
|
||||||
|
MatrixIdentity (&buffer->matrix);
|
||||||
|
|
||||||
/* Record the buffer data. */
|
/* Record the buffer data. */
|
||||||
|
|
||||||
buffer->u.shm.format = FindFormatInfo (attributes->format);
|
buffer->u.shm.format = FindFormatInfo (attributes->format);
|
||||||
|
@ -1990,10 +2175,52 @@ UpdateTexture (EglBuffer *buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
UpdateShmBufferIncrementally (EglBuffer *buffer, pixman_region32_t *damage)
|
ReverseTransformToBox (DrawParams *params, pixman_box32_t *box)
|
||||||
|
{
|
||||||
|
double x_factor, y_factor;
|
||||||
|
|
||||||
|
if (!params)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Apply the inverse of PARAMS to BOX, for use in damage
|
||||||
|
tracking. */
|
||||||
|
|
||||||
|
if (params->flags & ScaleSet)
|
||||||
|
{
|
||||||
|
box->x1 = floor (box->x1 / params->scale);
|
||||||
|
box->y1 = floor (box->y1 / params->scale);
|
||||||
|
box->x2 = ceil (box->x2 / params->scale);
|
||||||
|
box->y2 = ceil (box->y2 / params->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->flags & OffsetSet)
|
||||||
|
{
|
||||||
|
/* Since the offset can be a fractional value, also try to
|
||||||
|
include as much as possible in the box. */
|
||||||
|
box->x1 = floor (box->x1 + params->off_x);
|
||||||
|
box->y1 = floor (box->y1 + params->off_y);
|
||||||
|
box->x2 = ceil (box->x2 + params->off_x);
|
||||||
|
box->y2 = ceil (box->y2 + params->off_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->flags & StretchSet)
|
||||||
|
{
|
||||||
|
x_factor = params->crop_width / params->stretch_width;
|
||||||
|
y_factor = params->crop_height / params->stretch_height;
|
||||||
|
|
||||||
|
box->x1 = floor (box->x1 * x_factor);
|
||||||
|
box->y1 = floor (box->y1 * y_factor);
|
||||||
|
box->x2 = ceil (box->x2 * x_factor);
|
||||||
|
box->y2 = ceil (box->y2 * y_factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
UpdateShmBufferIncrementally (EglBuffer *buffer, pixman_region32_t *damage,
|
||||||
|
DrawParams *params)
|
||||||
{
|
{
|
||||||
GLenum target;
|
GLenum target;
|
||||||
pixman_box32_t *boxes;
|
pixman_box32_t *boxes, box;
|
||||||
int nboxes, i, width, height;
|
int nboxes, i, width, height;
|
||||||
void *data_ptr;
|
void *data_ptr;
|
||||||
size_t expected_data_size;
|
size_t expected_data_size;
|
||||||
|
@ -2018,34 +2245,39 @@ UpdateShmBufferIncrementally (EglBuffer *buffer, pixman_region32_t *damage)
|
||||||
the damage. */
|
the damage. */
|
||||||
for (i = 0; i < nboxes; ++i)
|
for (i = 0; i < nboxes; ++i)
|
||||||
{
|
{
|
||||||
if (boxes[i].x1 >= buffer->width
|
/* Get a copy of the box. */
|
||||||
|| boxes[i].y1 >= buffer->height)
|
box = boxes[i];
|
||||||
/* This box isn't contained in the buffer. */
|
|
||||||
continue;
|
/* Transform the box according to any transforms. */
|
||||||
|
ReverseTransformToBox (params, &box);
|
||||||
|
|
||||||
|
/* Clip the box X and Y to 0, 0. */
|
||||||
|
box.x1 = MIN (box.y1, 0);
|
||||||
|
box.y1 = MIN (box.y1, 0);
|
||||||
|
|
||||||
/* These computations are correct, since box->x2/box->y2 are
|
/* These computations are correct, since box->x2/box->y2 are
|
||||||
actually 1 pixel outside the last pixel in the box. */
|
actually 1 pixel outside the last pixel in the box. */
|
||||||
width = MIN (boxes[i].x2, buffer->width) - boxes[i].x1;
|
width = MIN (box.x2, buffer->width) - box.x1;
|
||||||
height = MIN (boxes[i].y2, buffer->height) - boxes[i].y1;
|
height = MIN (box.y2, buffer->height) - box.y1;
|
||||||
|
|
||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
/* The box is effectively empty because it straddles one of
|
/* The box is effectively empty because it straddles one of
|
||||||
the corners of the buffer. */
|
the corners of the buffer, or is outside of the buffer. */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* First, set the length of a single row. */
|
/* First, set the length of a single row. */
|
||||||
glPixelStorei (GL_UNPACK_ROW_LENGTH_EXT,
|
glPixelStorei (GL_UNPACK_ROW_LENGTH_EXT,
|
||||||
buffer->u.shm.stride / (buffer->u.shm.format->bpp / 8));
|
buffer->u.shm.stride / (buffer->u.shm.format->bpp / 8));
|
||||||
|
|
||||||
/* Next, skip boxes[i].x1 pixels of each row. */
|
/* Next, skip box.x1 pixels of each row. */
|
||||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS_EXT, boxes[i].x1);
|
glPixelStorei (GL_UNPACK_SKIP_PIXELS_EXT, box.x1);
|
||||||
|
|
||||||
/* And boxes[i].y1 rows. */
|
/* And box.y1 rows. */
|
||||||
glPixelStorei (GL_UNPACK_SKIP_ROWS_EXT, boxes[i].y1);
|
glPixelStorei (GL_UNPACK_SKIP_ROWS_EXT, box.y1);
|
||||||
|
|
||||||
/* Copy the image into the sub-texture. */
|
/* Copy the image into the sub-texture. */
|
||||||
glTexSubImage2D (target, 0, boxes[i].x1, boxes[i].y1,
|
glTexSubImage2D (target, 0, box.x1, box.y1, width, height,
|
||||||
width, height, buffer->u.shm.format->gl_format,
|
buffer->u.shm.format->gl_format,
|
||||||
buffer->u.shm.format->gl_type, data_ptr);
|
buffer->u.shm.format->gl_type, data_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2080,7 +2312,8 @@ EnsureTexture (EglBuffer *buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage)
|
UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage,
|
||||||
|
DrawParams *params)
|
||||||
{
|
{
|
||||||
EglBuffer *egl_buffer;
|
EglBuffer *egl_buffer;
|
||||||
|
|
||||||
|
@ -2106,8 +2339,9 @@ UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage)
|
||||||
{
|
{
|
||||||
case ShmBuffer:
|
case ShmBuffer:
|
||||||
/* Update the shared memory buffer incrementally, taking
|
/* Update the shared memory buffer incrementally, taking
|
||||||
into account the damaged area. */
|
into account the damaged area and transform. */
|
||||||
UpdateShmBufferIncrementally (egl_buffer, damage);
|
UpdateShmBufferIncrementally (egl_buffer, damage,
|
||||||
|
params);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2119,23 +2353,9 @@ UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
UpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
|
UpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
|
||||||
float scale)
|
DrawParams *params)
|
||||||
{
|
{
|
||||||
pixman_region32_t region;
|
UpdateBuffer (buffer, damage, params);
|
||||||
|
|
||||||
if (scale != 1.0f && damage)
|
|
||||||
{
|
|
||||||
/* Scale the damage, specified in scaled coordinates, down to
|
|
||||||
texture coordinates. */
|
|
||||||
|
|
||||||
pixman_region32_init (®ion);
|
|
||||||
XLScaleRegion (®ion, damage, 1.0f / scale,
|
|
||||||
1.0f / scale);
|
|
||||||
UpdateBuffer (buffer, ®ion);
|
|
||||||
pixman_region32_fini (®ion);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
UpdateBuffer (buffer, damage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
|
|
30
fns.c
30
fns.c
|
@ -380,6 +380,36 @@ XLScaleRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
||||||
XLFree (dst_rects);
|
XLFree (dst_rects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XLExtendRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
||||||
|
int extend_x, int extend_y)
|
||||||
|
{
|
||||||
|
int nrects, i;
|
||||||
|
pixman_box32_t *src_rects;
|
||||||
|
pixman_box32_t *dst_rects;
|
||||||
|
|
||||||
|
src_rects = pixman_region32_rectangles (src, &nrects);
|
||||||
|
|
||||||
|
if (nrects < 128)
|
||||||
|
dst_rects = alloca (nrects * sizeof *dst_rects);
|
||||||
|
else
|
||||||
|
dst_rects = XLMalloc (nrects * sizeof *dst_rects);
|
||||||
|
|
||||||
|
for (i = 0; i < nrects; ++i)
|
||||||
|
{
|
||||||
|
dst_rects[i].x1 = src_rects[i].x1;
|
||||||
|
dst_rects[i].x2 = src_rects[i].x2 + extend_x;
|
||||||
|
dst_rects[i].y1 = src_rects[i].y1;
|
||||||
|
dst_rects[i].y2 = src_rects[i].y2 + extend_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_fini (dst);
|
||||||
|
pixman_region32_init_rects (dst, dst_rects, nrects);
|
||||||
|
|
||||||
|
if (nrects >= 128)
|
||||||
|
XLFree (dst_rects);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
XLOpenShm (void)
|
XLOpenShm (void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -144,15 +144,45 @@ SetSyncCounter (XSyncCounter counter, uint64_t value)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t
|
static uint64_t
|
||||||
CurrentHighPrecisionTimestamp (void)
|
HighPrecisionTimestamp (struct timespec *clock)
|
||||||
{
|
{
|
||||||
struct timespec clock;
|
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
|
|
||||||
clock_gettime (CLOCK_MONOTONIC, &clock);
|
if (IntMultiplyWrapv (clock->tv_sec, 1000000, ×tamp)
|
||||||
|
|| IntAddWrapv (timestamp, clock->tv_nsec / 1000, ×tamp))
|
||||||
|
/* Overflow. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (IntMultiplyWrapv (clock.tv_sec, 1000000, ×tamp)
|
return timestamp;
|
||||||
|| IntAddWrapv (timestamp, clock.tv_nsec / 1000, ×tamp))
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
HighPrecisionTimestamp32 (struct timespec *clock)
|
||||||
|
{
|
||||||
|
uint64_t timestamp, milliseconds;
|
||||||
|
|
||||||
|
/* This function is like CurrentHighPrecisionTimestamp, but the X
|
||||||
|
server time portion is limited to 32 bits. First, the seconds
|
||||||
|
are converted to milliseconds. */
|
||||||
|
if (IntMultiplyWrapv (clock->tv_sec, 1000, &milliseconds))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Next, the nanosecond portion is also converted to
|
||||||
|
milliseconds. */
|
||||||
|
if (IntAddWrapv (milliseconds, clock->tv_nsec / 1000000,
|
||||||
|
&milliseconds))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Then, the milliseconds are truncated to 32 bits. */
|
||||||
|
milliseconds &= 0xffffffff;
|
||||||
|
|
||||||
|
/* Finally, add the milliseconds to the timestamp. */
|
||||||
|
if (IntMultiplyWrapv (milliseconds, 1000, ×tamp))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* And add the remaining nsec portion. */
|
||||||
|
if (IntAddWrapv (timestamp, (clock->tv_nsec % 1000000) / 1000,
|
||||||
|
×tamp))
|
||||||
/* Overflow. */
|
/* Overflow. */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -197,8 +227,8 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
|
||||||
static void
|
static void
|
||||||
PostEndFrame (FrameClock *clock)
|
PostEndFrame (FrameClock *clock)
|
||||||
{
|
{
|
||||||
uint64_t target, now;
|
uint64_t target, fallback, now, additional;
|
||||||
struct timespec timespec;
|
struct timespec timespec, current_time;
|
||||||
|
|
||||||
XLAssert (clock->end_frame_timer == NULL);
|
XLAssert (clock->end_frame_timer == NULL);
|
||||||
|
|
||||||
|
@ -206,11 +236,27 @@ PostEndFrame (FrameClock *clock)
|
||||||
|| !clock->presentation_time)
|
|| !clock->presentation_time)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Obtain the monotonic clock time. */
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, ¤t_time);
|
||||||
|
|
||||||
/* Calculate the time by which the next frame must be drawn. It is
|
/* Calculate the time by which the next frame must be drawn. It is
|
||||||
a multiple of the refresh rate with the vertical blanking
|
a multiple of the refresh rate with the vertical blanking
|
||||||
period added. */
|
period added. */
|
||||||
target = clock->last_frame_time + clock->presentation_time;
|
target = clock->last_frame_time + clock->presentation_time;
|
||||||
now = CurrentHighPrecisionTimestamp ();
|
now = HighPrecisionTimestamp (¤t_time);
|
||||||
|
additional = 0;
|
||||||
|
|
||||||
|
/* If now is more than UINT32_MAX * 1000, then this timestamp may
|
||||||
|
overflow the 32-bit X server time, depending on how the X
|
||||||
|
compositing manager implements timestamp generation. Generate a
|
||||||
|
fallback timestamp to use in that situation.
|
||||||
|
|
||||||
|
Use now << 10 instead of now / 1000; the difference is too small
|
||||||
|
to be noticeable. */
|
||||||
|
if (now << 10 > UINT32_MAX)
|
||||||
|
fallback = HighPrecisionTimestamp32 (¤t_time);
|
||||||
|
else
|
||||||
|
fallback = 0;
|
||||||
|
|
||||||
if (!now)
|
if (!now)
|
||||||
return;
|
return;
|
||||||
|
@ -218,7 +264,22 @@ PostEndFrame (FrameClock *clock)
|
||||||
/* If the last time the frame time was obtained was that long ago,
|
/* If the last time the frame time was obtained was that long ago,
|
||||||
return immediately. */
|
return immediately. */
|
||||||
if (now - clock->last_frame_time >= MaxPresentationAge)
|
if (now - clock->last_frame_time >= MaxPresentationAge)
|
||||||
return;
|
{
|
||||||
|
if ((fallback - clock->last_frame_time) <= MaxPresentationAge)
|
||||||
|
{
|
||||||
|
/* Some compositors wrap around once the X server time
|
||||||
|
overflows the 32-bit Time type. If now happens to be
|
||||||
|
within the limit after its millisecond portion is
|
||||||
|
truncated to 32 bits, continue, after setting the
|
||||||
|
additional value the difference between the truncated
|
||||||
|
value and the actual time. */
|
||||||
|
|
||||||
|
additional = now - fallback;
|
||||||
|
now = fallback;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (target < now)
|
while (target < now)
|
||||||
{
|
{
|
||||||
|
@ -226,15 +287,19 @@ PostEndFrame (FrameClock *clock)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the high precision timestamp to a timespec. */
|
|
||||||
if (!HighPrecisionTimestampToTimespec (target, ×pec))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Use 3/4ths of the presentation time. Any more and we risk the
|
/* Use 3/4ths of the presentation time. Any more and we risk the
|
||||||
counter value change signalling the end of the frame arriving
|
counter value change signalling the end of the frame arriving
|
||||||
after the presentation deadline. */
|
after the presentation deadline. */
|
||||||
target = target - (clock->presentation_time / 4 * 3);
|
target = target - (clock->presentation_time / 4 * 3);
|
||||||
|
|
||||||
|
/* Add the remainder of now if it was probably truncated by the
|
||||||
|
compositor. */
|
||||||
|
target += additional;
|
||||||
|
|
||||||
|
/* Convert the high precision timestamp to a timespec. */
|
||||||
|
if (!HighPrecisionTimestampToTimespec (target, ×pec))
|
||||||
|
return;
|
||||||
|
|
||||||
/* Schedule the timer marking the end of this frame for the target
|
/* Schedule the timer marking the end of this frame for the target
|
||||||
time. */
|
time. */
|
||||||
clock->end_frame_timer = AddTimerWithBaseTime (HandleEndFrame,
|
clock->end_frame_timer = AddTimerWithBaseTime (HandleEndFrame,
|
||||||
|
|
|
@ -325,16 +325,54 @@ GetScale (DrawParams *params)
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
GetSourceX (DrawParams *params)
|
||||||
|
{
|
||||||
|
if (params->flags & OffsetSet)
|
||||||
|
return params->off_x;
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
GetSourceY (DrawParams *params)
|
||||||
|
{
|
||||||
|
if (params->flags & OffsetSet)
|
||||||
|
return params->off_y;
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
CompareStretch (DrawParams *params, DrawParams *other)
|
||||||
|
{
|
||||||
|
if ((params->flags & StretchSet)
|
||||||
|
!= (other->flags & StretchSet))
|
||||||
|
return False;
|
||||||
|
|
||||||
|
if (params->flags & StretchSet)
|
||||||
|
return (other->crop_width == params->crop_width
|
||||||
|
&& other->crop_height == params->crop_height
|
||||||
|
&& other->stretch_width == params->stretch_width
|
||||||
|
&& other->stretch_height == params->stretch_height);
|
||||||
|
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
|
MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
|
||||||
{
|
{
|
||||||
XTransform transform;
|
XTransform transform;
|
||||||
|
Matrix ftransform;
|
||||||
|
|
||||||
if (GetScale (params) == GetScale (&buffer->params))
|
if (GetScale (params) == GetScale (&buffer->params)
|
||||||
|
&& GetSourceX (params) == GetSourceX (&buffer->params)
|
||||||
|
&& GetSourceY (params) == GetSourceY (&buffer->params)
|
||||||
|
&& CompareStretch (params, &buffer->params))
|
||||||
/* Nothing changed. */
|
/* Nothing changed. */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Otherwise, compute and apply the new transform. */
|
/* Otherwise, compute and apply the new transform. */
|
||||||
if (!params->flags)
|
if (!params->flags)
|
||||||
/* No transform of any kind is set, use the identity matrix. */
|
/* No transform of any kind is set, use the identity matrix. */
|
||||||
XRenderSetPictureTransform (compositor.display,
|
XRenderSetPictureTransform (compositor.display,
|
||||||
|
@ -342,14 +380,29 @@ MaybeApplyTransform (PictureBuffer *buffer, DrawParams *params)
|
||||||
&identity_transform);
|
&identity_transform);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memset (&transform, 0, sizeof transform);
|
MatrixIdentity (&ftransform);
|
||||||
|
|
||||||
transform.matrix[0][0] = XDoubleToFixed (1.0 / params->scale);
|
/* Note that these must be applied in the right order. First,
|
||||||
transform.matrix[1][1] = XDoubleToFixed (1.0 / params->scale);
|
the scale is applied. Then, the offset, and finally the
|
||||||
transform.matrix[2][2] = XDoubleToFixed (1);
|
stretch. */
|
||||||
|
if (params->flags & ScaleSet)
|
||||||
|
MatrixScale (&ftransform, 1.0 / GetScale (params),
|
||||||
|
1.0 / GetScale (params));
|
||||||
|
|
||||||
XRenderSetPictureTransform (compositor.display,
|
if (params->flags & OffsetSet)
|
||||||
buffer->picture,
|
MatrixTranslate (&ftransform, params->off_x, params->off_y);
|
||||||
|
|
||||||
|
if (params->flags & StretchSet)
|
||||||
|
MatrixScale (&ftransform,
|
||||||
|
params->crop_width / params->stretch_width,
|
||||||
|
params->crop_height / params->stretch_height);
|
||||||
|
|
||||||
|
/* Export the matrix to an XTransform. */
|
||||||
|
MatrixExport (&ftransform, &transform);
|
||||||
|
|
||||||
|
/* Set the transform. The transform maps from dest coords to
|
||||||
|
picture coords, so that [X Y 1] = TRANSFORM * [DX DY 1]. */
|
||||||
|
XRenderSetPictureTransform (compositor.display, buffer->picture,
|
||||||
&transform);
|
&transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
positioner.c
46
positioner.c
|
@ -60,7 +60,8 @@ struct _Positioner
|
||||||
int refcount;
|
int refcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Scale factor used during constraint adjustment calculation. */
|
/* Surface used to handle scaling during constraint adjustment
|
||||||
|
calculation. */
|
||||||
static double scale_adjustment_factor;
|
static double scale_adjustment_factor;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -673,8 +674,12 @@ GetAdjustmentOffset (Role *parent, int *off_x, int *off_y)
|
||||||
&parent_gy, NULL, NULL);
|
&parent_gy, NULL, NULL);
|
||||||
XLXdgRoleCurrentRootPosition (parent, &root_x, &root_y);
|
XLXdgRoleCurrentRootPosition (parent, &root_x, &root_y);
|
||||||
|
|
||||||
*off_x = root_x + parent_gx * parent->surface->factor;
|
/* Convert the gx and gy to the window coordinate system. */
|
||||||
*off_y = root_y + parent_gy * parent->surface->factor;
|
TruncateSurfaceToWindow (parent->surface, parent_gx, parent_gy,
|
||||||
|
&parent_gx, &parent_gy);
|
||||||
|
|
||||||
|
*off_x = root_x + parent_gx;
|
||||||
|
*off_y = root_y + parent_gy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -684,18 +689,19 @@ ApplyConstraintAdjustment (Positioner *positioner, Role *parent, int x,
|
||||||
{
|
{
|
||||||
int width, height, cx, cy, cwidth, cheight, off_x, off_y;
|
int width, height, cx, cy, cwidth, cheight, off_x, off_y;
|
||||||
|
|
||||||
width = positioner->width * scale_adjustment_factor;
|
width = positioner->width;
|
||||||
height = positioner->height * scale_adjustment_factor;
|
height = positioner->height;
|
||||||
|
|
||||||
|
/* Constraint calculations are simplest if we use scaled
|
||||||
|
coordinates, and then unscale them later. */
|
||||||
|
TruncateSurfaceToWindow (parent->surface, x, y, &x, &y);
|
||||||
|
TruncateScaleToWindow (parent->surface, width, height, &width,
|
||||||
|
&height);
|
||||||
|
|
||||||
/* Set the factor describing how to convert surface coordinates to
|
/* Set the factor describing how to convert surface coordinates to
|
||||||
window ones. */
|
window ones. */
|
||||||
scale_adjustment_factor = parent->surface->factor;
|
scale_adjustment_factor = parent->surface->factor;
|
||||||
|
|
||||||
/* Constraint calculations are simplest if we use scaled
|
|
||||||
coordinates, and then unscale them later. */
|
|
||||||
x *= scale_adjustment_factor;
|
|
||||||
y *= scale_adjustment_factor;
|
|
||||||
|
|
||||||
if (positioner->constraint_adjustment
|
if (positioner->constraint_adjustment
|
||||||
== XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
|
== XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
|
||||||
/* There is no constraint adjustment. */
|
/* There is no constraint adjustment. */
|
||||||
|
@ -740,10 +746,14 @@ ApplyConstraintAdjustment (Positioner *positioner, Role *parent, int x,
|
||||||
off_y, &y, &height);
|
off_y, &y, &height);
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
*x_out = x / scale_adjustment_factor;
|
/* Now, scale the coordinates back. */
|
||||||
*y_out = y / scale_adjustment_factor;
|
TruncateWindowToSurface (parent->surface, x, y, &x, &y);
|
||||||
*width_out = width / scale_adjustment_factor;
|
TruncateScaleToSurface (parent->surface, width, height, &width, &height);
|
||||||
*height_out = height / scale_adjustment_factor;
|
|
||||||
|
*x_out = x;
|
||||||
|
*y_out = y;
|
||||||
|
*width_out = width;
|
||||||
|
*height_out = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -754,8 +764,12 @@ XLPositionerCalculateGeometry (Positioner *positioner, Role *parent,
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
|
|
||||||
CalculatePosition (positioner, &x, &y);
|
CalculatePosition (positioner, &x, &y);
|
||||||
ApplyConstraintAdjustment (positioner, parent, x, y,
|
|
||||||
&x, &y, &width, &height);
|
if (parent->surface)
|
||||||
|
ApplyConstraintAdjustment (positioner, parent, x, y,
|
||||||
|
&x, &y, &width, &height);
|
||||||
|
else
|
||||||
|
width = positioner->width, height = positioner->height;
|
||||||
|
|
||||||
*x_out = x;
|
*x_out = x;
|
||||||
*y_out = y;
|
*y_out = y;
|
||||||
|
|
|
@ -241,12 +241,12 @@ RenderFreeDmabufBuffer (RenderBuffer buffer)
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
|
RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage,
|
||||||
float scale)
|
DrawParams *params)
|
||||||
{
|
{
|
||||||
if (!buffer_funcs.update_buffer_for_damage)
|
if (!buffer_funcs.update_buffer_for_damage)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer_funcs.update_buffer_for_damage (buffer, damage, scale);
|
buffer_funcs.update_buffer_for_damage (buffer, damage, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
|
|
18
shaders.txt
18
shaders.txt
|
@ -31,19 +31,19 @@ main (void)
|
||||||
attribute vec2 pos;
|
attribute vec2 pos;
|
||||||
attribute vec2 texcoord;
|
attribute vec2 texcoord;
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
|
uniform mat3 source;
|
||||||
|
|
||||||
void
|
void
|
||||||
main (void)
|
main (void)
|
||||||
{
|
{
|
||||||
gl_Position = vec4 (pos.x, pos.y, 1.0, 1.0);
|
gl_Position = vec4 (pos.x, pos.y, 1.0, 1.0);
|
||||||
v_texcoord = texcoord;
|
v_texcoord = (source * vec3 (texcoord, 1.0)).xy;
|
||||||
}
|
}
|
||||||
//==
|
//==
|
||||||
|
|
||||||
//== Composite Rectangle Fragment Shader RGBA
|
//== Composite Rectangle Fragment Shader RGBA
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
uniform float scale;
|
|
||||||
uniform bool invert_y;
|
uniform bool invert_y;
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ main (void)
|
||||||
{
|
{
|
||||||
vec2 texcoord;
|
vec2 texcoord;
|
||||||
|
|
||||||
texcoord = v_texcoord / scale;
|
texcoord = v_texcoord;
|
||||||
|
|
||||||
if (invert_y)
|
if (invert_y)
|
||||||
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
|
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
|
||||||
|
@ -64,7 +64,7 @@ main (void)
|
||||||
//== Composite Rectangle Fragment Shader RGBX
|
//== Composite Rectangle Fragment Shader RGBX
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
uniform float scale;
|
uniform mat3 source;
|
||||||
uniform bool invert_y;
|
uniform bool invert_y;
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
|
|
||||||
|
@ -73,14 +73,12 @@ main (void)
|
||||||
{
|
{
|
||||||
vec2 texcoord;
|
vec2 texcoord;
|
||||||
|
|
||||||
texcoord = v_texcoord / scale;
|
texcoord = v_texcoord;
|
||||||
|
|
||||||
if (invert_y)
|
if (invert_y)
|
||||||
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
|
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
|
||||||
|
|
||||||
gl_FragColor = vec4 (texture2D (texture,
|
gl_FragColor = vec4 (texture2D (texture, texcoord).rgb, 1.0);
|
||||||
texcoord).rgb,
|
|
||||||
1.0);
|
|
||||||
}
|
}
|
||||||
//==
|
//==
|
||||||
|
|
||||||
|
@ -89,7 +87,7 @@ main (void)
|
||||||
|
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
uniform samplerExternalOES texture;
|
uniform samplerExternalOES texture;
|
||||||
uniform float scale;
|
uniform mat3 source;
|
||||||
uniform bool invert_y;
|
uniform bool invert_y;
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
|
|
||||||
|
@ -98,7 +96,7 @@ main (void)
|
||||||
{
|
{
|
||||||
vec2 texcoord;
|
vec2 texcoord;
|
||||||
|
|
||||||
texcoord = v_texcoord / scale;
|
texcoord = v_texcoord;
|
||||||
|
|
||||||
if (invert_y)
|
if (invert_y)
|
||||||
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
|
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
|
||||||
|
|
292
subcompositor.c
292
subcompositor.c
|
@ -192,7 +192,11 @@ enum
|
||||||
{
|
{
|
||||||
/* This means that the view and all its inferiors should be
|
/* This means that the view and all its inferiors should be
|
||||||
skipped in bounds computation, input tracking, et cetera. */
|
skipped in bounds computation, input tracking, et cetera. */
|
||||||
ViewIsUnmapped = 1,
|
ViewIsUnmapped = 1,
|
||||||
|
/* This means that the view has a viewport specifying its size,
|
||||||
|
effectively decoupling its relation to the buffer width and
|
||||||
|
height. */
|
||||||
|
ViewIsViewported = 1 << 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IsViewUnmapped(view) \
|
#define IsViewUnmapped(view) \
|
||||||
|
@ -202,6 +206,13 @@ enum
|
||||||
#define ClearUnmapped(view) \
|
#define ClearUnmapped(view) \
|
||||||
((view)->flags &= ~ViewIsUnmapped)
|
((view)->flags &= ~ViewIsUnmapped)
|
||||||
|
|
||||||
|
#define IsViewported(view) \
|
||||||
|
((view)->flags & ViewIsViewported)
|
||||||
|
#define SetViewported(view) \
|
||||||
|
((view)->flags |= ViewIsViewported)
|
||||||
|
#define ClearViewported(view) \
|
||||||
|
((view)->flags &= ~ViewIsViewported)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct _List
|
struct _List
|
||||||
|
@ -273,6 +284,13 @@ struct _View
|
||||||
|
|
||||||
/* Flags; whether or not this view is unmapped, etc. */
|
/* Flags; whether or not this view is unmapped, etc. */
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
/* The viewport data. */
|
||||||
|
double src_x, src_y, crop_width, crop_height, dest_width, dest_height;
|
||||||
|
|
||||||
|
/* Fractional offset applied to the view contents and damage during
|
||||||
|
compositing. */
|
||||||
|
double fract_x, fract_y;
|
||||||
#else
|
#else
|
||||||
/* Label used during tests. */
|
/* Label used during tests. */
|
||||||
const char *label;
|
const char *label;
|
||||||
|
@ -749,7 +767,6 @@ ViewUpdateBoundsForInsert (View *view)
|
||||||
view);
|
view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_STATIC void
|
TEST_STATIC void
|
||||||
|
@ -1214,6 +1231,10 @@ main (int argc, char **argv)
|
||||||
|
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
|
|
||||||
|
/* Notice that VIEW's size has changed, while VIEW itself has not
|
||||||
|
moved. Recompute the max_x, min_x, min_y, and max_y of its
|
||||||
|
subcompositor. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ViewAfterSizeUpdate (View *view)
|
ViewAfterSizeUpdate (View *view)
|
||||||
{
|
{
|
||||||
|
@ -1272,7 +1293,11 @@ ViewAttachBuffer (View *view, ExtBuffer *buffer)
|
||||||
&& (XLBufferWidth (buffer) != XLBufferWidth (old)
|
&& (XLBufferWidth (buffer) != XLBufferWidth (old)
|
||||||
|| XLBufferHeight (buffer) != XLBufferHeight (old))))
|
|| XLBufferHeight (buffer) != XLBufferHeight (old))))
|
||||||
{
|
{
|
||||||
if (view->subcompositor)
|
if (view->subcompositor
|
||||||
|
/* If a viewport is specified, then the view width and
|
||||||
|
height are determined independently from the buffer
|
||||||
|
size. */
|
||||||
|
&& !IsViewported (view))
|
||||||
{
|
{
|
||||||
/* A new buffer was attached, so garbage the subcompositor
|
/* A new buffer was attached, so garbage the subcompositor
|
||||||
as well. */
|
as well. */
|
||||||
|
@ -1398,6 +1423,20 @@ ViewMove (View *view, int x, int y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ViewMoveFractional (View *view, double x, double y)
|
||||||
|
{
|
||||||
|
XLAssert (x < 1.0 && y < 1.0);
|
||||||
|
|
||||||
|
/* This does not necessitate adjustments to the view size, but does
|
||||||
|
require that the subcompositor be garbaged. */
|
||||||
|
view->fract_x = x;
|
||||||
|
view->fract_y = y;
|
||||||
|
|
||||||
|
if (view->subcompositor)
|
||||||
|
SetGarbaged (view->subcompositor);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ViewDetach (View *view)
|
ViewDetach (View *view)
|
||||||
{
|
{
|
||||||
|
@ -1477,8 +1516,9 @@ ViewFree (View *view)
|
||||||
void
|
void
|
||||||
ViewDamage (View *view, pixman_region32_t *damage)
|
ViewDamage (View *view, pixman_region32_t *damage)
|
||||||
{
|
{
|
||||||
pixman_region32_union (&view->damage,
|
/* This damage must be transformed by the viewport and scale, but
|
||||||
&view->damage,
|
must NOT be transformed by the subpixel (fractional) offset. */
|
||||||
|
pixman_region32_union (&view->damage, &view->damage,
|
||||||
damage);
|
damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1509,6 +1549,15 @@ ViewGetSubcompositor (View *view)
|
||||||
return view->subcompositor;
|
return view->subcompositor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
GetContentScale (int scale)
|
||||||
|
{
|
||||||
|
if (scale > 0)
|
||||||
|
return 1.0 / (scale + 1);
|
||||||
|
|
||||||
|
return -scale + 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ViewWidth (View *view)
|
ViewWidth (View *view)
|
||||||
{
|
{
|
||||||
|
@ -1517,12 +1566,20 @@ ViewWidth (View *view)
|
||||||
if (!view->buffer)
|
if (!view->buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (IsViewported (view))
|
||||||
|
/* The view has a viewport specified. view->dest_width and
|
||||||
|
view->dest_height can be fractional values. When that happens,
|
||||||
|
we simply use the ceiling and rely on the renderer to DTRT with
|
||||||
|
scaling. */
|
||||||
|
return ceil (view->dest_width
|
||||||
|
* GetContentScale (view->scale));
|
||||||
|
|
||||||
width = XLBufferWidth (view->buffer);
|
width = XLBufferWidth (view->buffer);
|
||||||
|
|
||||||
if (view->scale < 0)
|
if (view->scale < 0)
|
||||||
return width * (abs (view->scale) + 1);
|
return ceil (width * (abs (view->scale) + 1));
|
||||||
else
|
else
|
||||||
return width / (view->scale + 1);
|
return ceil (width / (view->scale + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1533,68 +1590,82 @@ ViewHeight (View *view)
|
||||||
if (!view->buffer)
|
if (!view->buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (IsViewported (view))
|
||||||
|
/* The view has a viewport specified. view->dest_width and
|
||||||
|
view->dest_height can be fractional values. When that happens,
|
||||||
|
we simply use the ceiling and rely on the renderer to DTRT with
|
||||||
|
scaling. */
|
||||||
|
return ceil (view->dest_height
|
||||||
|
* GetContentScale (view->scale));
|
||||||
|
|
||||||
height = XLBufferHeight (view->buffer);
|
height = XLBufferHeight (view->buffer);
|
||||||
|
|
||||||
if (view->scale < 0)
|
if (view->scale < 0)
|
||||||
return height * (abs (view->scale) + 1);
|
return ceil (height * (abs (view->scale) + 1));
|
||||||
else
|
else
|
||||||
return height / (view->scale + 1);
|
return ceil (height / (view->scale + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ViewSetScale (View *view, int scale)
|
ViewSetScale (View *view, int scale)
|
||||||
{
|
{
|
||||||
int doflags;
|
|
||||||
|
|
||||||
/* First, assume we will have to compute both max_x and max_y. */
|
|
||||||
doflags = DoMaxX | DoMaxY;
|
|
||||||
|
|
||||||
if (view->scale == scale)
|
if (view->scale == scale)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
view->scale = scale;
|
view->scale = scale;
|
||||||
|
|
||||||
if (view->subcompositor)
|
/* Recompute subcompositor bounds; they could've changed. */
|
||||||
{
|
ViewAfterSizeUpdate (view);
|
||||||
/* If the view is now wider than max_x and/or max_y, update those
|
|
||||||
now. */
|
|
||||||
|
|
||||||
if (view->subcompositor->max_x < ViewMaxX (view))
|
|
||||||
{
|
|
||||||
view->subcompositor->max_x = ViewMaxX (view);
|
|
||||||
|
|
||||||
/* We don't have to update max_x anymore. */
|
|
||||||
doflags &= ~DoMaxX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view->subcompositor->max_y < ViewMaxY (view))
|
|
||||||
{
|
|
||||||
view->subcompositor->max_y = ViewMaxY (view);
|
|
||||||
|
|
||||||
/* We don't have to update max_x anymore. */
|
|
||||||
doflags &= ~DoMaxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally, update the bounds. */
|
|
||||||
SubcompositorUpdateBounds (view->subcompositor,
|
|
||||||
doflags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static double
|
|
||||||
GetContentScale (int scale)
|
|
||||||
{
|
|
||||||
if (scale > 0)
|
|
||||||
return 1.0 / (scale + 1);
|
|
||||||
|
|
||||||
return -scale + 1;
|
void
|
||||||
|
ViewSetViewport (View *view, double src_x, double src_y,
|
||||||
|
double crop_width, double crop_height,
|
||||||
|
double dest_width, double dest_height)
|
||||||
|
{
|
||||||
|
SetViewported (view);
|
||||||
|
|
||||||
|
view->src_x = src_x;
|
||||||
|
view->src_y = src_y;
|
||||||
|
view->crop_width = crop_width;
|
||||||
|
view->crop_height = crop_height;
|
||||||
|
view->dest_width = dest_width;
|
||||||
|
view->dest_height = dest_height;
|
||||||
|
|
||||||
|
/* Update min_x and min_y. */
|
||||||
|
ViewAfterSizeUpdate (view);
|
||||||
|
|
||||||
|
/* Garbage the subcompositor as damage can no longer be trusted. */
|
||||||
|
if (view->subcompositor)
|
||||||
|
SubcompositorGarbage (view->subcompositor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ViewClearViewport (View *view)
|
||||||
|
{
|
||||||
|
ClearViewported (view);
|
||||||
|
|
||||||
|
/* Update min_x and min_y. */
|
||||||
|
ViewAfterSizeUpdate (view);
|
||||||
|
|
||||||
|
/* Garbage the subcompositor as damage can no longer be trusted. */
|
||||||
|
if (view->subcompositor)
|
||||||
|
SubcompositorGarbage (view->subcompositor);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ViewComputeTransform (View *view, DrawParams *params)
|
ViewComputeTransform (View *view, DrawParams *params, Bool draw)
|
||||||
{
|
{
|
||||||
|
/* Compute the effective transform of VIEW, then put it in PARAMS.
|
||||||
|
DRAW means whether or not the transform is intended for drawing;
|
||||||
|
when not set, the parameters are being used for damage tracking
|
||||||
|
instead. */
|
||||||
|
|
||||||
/* First, there is no transform. */
|
/* First, there is no transform. */
|
||||||
params->flags = 0;
|
params->flags = 0;
|
||||||
|
params->off_x = 0.0;
|
||||||
|
params->off_y = 0.0;
|
||||||
|
|
||||||
if (view->scale)
|
if (view->scale)
|
||||||
{
|
{
|
||||||
|
@ -1602,6 +1673,45 @@ ViewComputeTransform (View *view, DrawParams *params)
|
||||||
params->flags |= ScaleSet;
|
params->flags |= ScaleSet;
|
||||||
params->scale = GetContentScale (view->scale);
|
params->scale = GetContentScale (view->scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsViewported (view))
|
||||||
|
{
|
||||||
|
/* Set the viewport (a.k.a "stretch" and "offset" in the
|
||||||
|
rendering code). */
|
||||||
|
|
||||||
|
params->flags |= StretchSet;
|
||||||
|
params->flags |= OffsetSet;
|
||||||
|
|
||||||
|
params->off_x = view->src_x;
|
||||||
|
params->off_y = view->src_y;
|
||||||
|
params->crop_width = view->crop_width;
|
||||||
|
params->stretch_width = view->dest_width;
|
||||||
|
params->crop_height = view->crop_height;
|
||||||
|
params->stretch_height = view->dest_height;
|
||||||
|
|
||||||
|
/* If the crop width/height were not specified, use the current
|
||||||
|
buffer width/height. */
|
||||||
|
|
||||||
|
if (params->crop_width == -1)
|
||||||
|
{
|
||||||
|
params->crop_width = (XLBufferWidth (view->buffer)
|
||||||
|
* GetContentScale (view->scale));
|
||||||
|
params->crop_height = (XLBufferHeight (view->buffer)
|
||||||
|
* GetContentScale (view->scale));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((view->fract_x != 0.0 || view->fract_y != 0.0)
|
||||||
|
&& draw)
|
||||||
|
{
|
||||||
|
params->flags |= OffsetSet;
|
||||||
|
|
||||||
|
/* This is not entirely right. When applying a negative offset,
|
||||||
|
contents to the left of where the picture actually is can
|
||||||
|
appear to "shine through". */
|
||||||
|
params->off_x -= view->fract_x;
|
||||||
|
params->off_y -= view->fract_y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1740,7 +1850,7 @@ IntersectBoxes (pixman_box32_t *in, pixman_box32_t *other,
|
||||||
out->y2 = MIN (a.y2, b.y2);
|
out->y2 = MIN (a.y2, b.y2);
|
||||||
|
|
||||||
/* If the intersection is empty, return False. */
|
/* If the intersection is empty, return False. */
|
||||||
if (out->x2 - out->x1 <= 0 || out->y2 - out->y1 <= 0)
|
if (out->x2 - out->x1 < 0 || out->y2 - out->y1 < 0)
|
||||||
return False;
|
return False;
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
|
@ -1754,7 +1864,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
View *start, *original_start, *view, *first;
|
View *start, *original_start, *view, *first;
|
||||||
List *list;
|
List *list;
|
||||||
pixman_box32_t *boxes, *extents, temp_boxes;
|
pixman_box32_t *boxes, *extents, temp_boxes;
|
||||||
int nboxes, i, tx, ty;
|
int nboxes, i, tx, ty, view_width, view_height;
|
||||||
Operation op;
|
Operation op;
|
||||||
RenderBuffer buffer;
|
RenderBuffer buffer;
|
||||||
int min_x, min_y;
|
int min_x, min_y;
|
||||||
|
@ -1862,6 +1972,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
if (!view->buffer)
|
if (!view->buffer)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
|
/* Obtain the view width and height here. */
|
||||||
|
view_width = ViewWidth (view);
|
||||||
|
view_height = ViewHeight (view);
|
||||||
|
|
||||||
if (!start)
|
if (!start)
|
||||||
{
|
{
|
||||||
start = view;
|
start = view;
|
||||||
|
@ -1882,8 +1996,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
pixman_region32_intersect_rect (&temp, &view->opaque,
|
pixman_region32_intersect_rect (&temp, &view->opaque,
|
||||||
view->abs_x, view->abs_y,
|
view->abs_x, view->abs_y,
|
||||||
ViewWidth (view),
|
view_width, view_height);
|
||||||
ViewHeight (view));
|
|
||||||
|
|
||||||
if (IsOpaqueDirty (subcompositor))
|
if (IsOpaqueDirty (subcompositor))
|
||||||
pixman_region32_union (&total_opaque, &total_opaque, &temp);
|
pixman_region32_union (&total_opaque, &total_opaque, &temp);
|
||||||
|
@ -1922,8 +2035,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
pixman_region32_intersect_rect (&temp, &view->input,
|
pixman_region32_intersect_rect (&temp, &view->input,
|
||||||
view->abs_x, view->abs_y,
|
view->abs_x, view->abs_y,
|
||||||
ViewWidth (view),
|
view_width, view_height);
|
||||||
ViewHeight (view));
|
|
||||||
|
|
||||||
pixman_region32_union (&total_input, &total_input, &temp);
|
pixman_region32_union (&total_input, &total_input, &temp);
|
||||||
|
|
||||||
|
@ -1942,9 +2054,13 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
However, the function does not perform partial updates
|
However, the function does not perform partial updates
|
||||||
when the damage region is empty. */
|
when the damage region is empty. */
|
||||||
|
|
||||||
|
/* Compute the transform and put it in draw_params, so TRT
|
||||||
|
can be done in the rendering backend. */
|
||||||
|
ViewComputeTransform (view, &draw_params, False);
|
||||||
|
|
||||||
buffer = XLRenderBufferFromBuffer (view->buffer);
|
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||||
RenderUpdateBufferForDamage (buffer, &list->view->damage,
|
RenderUpdateBufferForDamage (buffer, &list->view->damage,
|
||||||
GetContentScale (list->view->scale));
|
&draw_params);
|
||||||
|
|
||||||
if (pixman_region32_not_empty (&list->view->damage))
|
if (pixman_region32_not_empty (&list->view->damage))
|
||||||
{
|
{
|
||||||
|
@ -1958,9 +2074,21 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
clipping. */
|
clipping. */
|
||||||
pixman_region32_intersect_rect (&temp, &list->view->damage,
|
pixman_region32_intersect_rect (&temp, &list->view->damage,
|
||||||
view->abs_x, view->abs_y,
|
view->abs_x, view->abs_y,
|
||||||
ViewWidth (view),
|
view_width, view_height);
|
||||||
ViewHeight (view));
|
|
||||||
|
|
||||||
|
/* If a fractional offset is set, extend the damage by 1
|
||||||
|
pixel to cover the offset. */
|
||||||
|
if (view->fract_x != 0.0 && view->fract_y != 0.0)
|
||||||
|
{
|
||||||
|
XLExtendRegion (&temp, &temp, 1, 1);
|
||||||
|
|
||||||
|
/* Intersect the region again. */
|
||||||
|
pixman_region32_intersect_rect (&temp, &temp, view->abs_x,
|
||||||
|
view->abs_y, view_width,
|
||||||
|
view_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Union the region with the update region. */
|
||||||
pixman_region32_union (&update_region, &temp, &update_region);
|
pixman_region32_union (&update_region, &temp, &update_region);
|
||||||
|
|
||||||
/* If the damage extends outside the area known to be
|
/* If the damage extends outside the area known to be
|
||||||
|
@ -2100,6 +2228,10 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
if (!view->buffer)
|
if (!view->buffer)
|
||||||
goto next_1;
|
goto next_1;
|
||||||
|
|
||||||
|
/* Get the view width and height here. */
|
||||||
|
view_width = ViewWidth (view);
|
||||||
|
view_height = ViewHeight (view);
|
||||||
|
|
||||||
buffer = XLRenderBufferFromBuffer (view->buffer);
|
buffer = XLRenderBufferFromBuffer (view->buffer);
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor))
|
if (IsGarbaged (subcompositor))
|
||||||
|
@ -2113,12 +2245,18 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
Note that if the subcompositor is not garbaged, then this
|
Note that if the subcompositor is not garbaged, then this
|
||||||
has already been done. */
|
has already been done. */
|
||||||
RenderUpdateBufferForDamage (buffer, NULL, 0.0f);
|
RenderUpdateBufferForDamage (buffer, NULL, NULL);
|
||||||
else if (age < 0 || age > 3)
|
else if (age < 0 || age >= 3)
|
||||||
/* The target contents are too old, but the damage can be
|
{
|
||||||
trusted. */
|
/* Compute the transform and put it in draw_params, so TRT
|
||||||
RenderUpdateBufferForDamage (buffer, &view->damage,
|
can be done in the rendering backend. */
|
||||||
GetContentScale (list->view->scale));
|
ViewComputeTransform (view, &draw_params, False);
|
||||||
|
|
||||||
|
/* The target contents are too old, but the damage can be
|
||||||
|
trusted. */
|
||||||
|
RenderUpdateBufferForDamage (buffer, &view->damage,
|
||||||
|
&draw_params);
|
||||||
|
}
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
|
@ -2126,7 +2264,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
with PictOpSrc so that transparency is applied correctly,
|
with PictOpSrc so that transparency is applied correctly,
|
||||||
if it contains the entire update region. */
|
if it contains the entire update region. */
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor) || age < 0 || age > 3)
|
if (IsGarbaged (subcompositor) || age < 0 || age >= 3)
|
||||||
{
|
{
|
||||||
extents = &temp_boxes;
|
extents = &temp_boxes;
|
||||||
|
|
||||||
|
@ -2149,7 +2287,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
/* Otherwise, fill the whole update region with
|
/* Otherwise, fill the whole update region with
|
||||||
transparency. */
|
transparency. */
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor) || age < 0 || age > 3)
|
if (IsGarbaged (subcompositor) || age < 0 || age >= 3)
|
||||||
{
|
{
|
||||||
/* Use the entire subcompositor bounds if
|
/* Use the entire subcompositor bounds if
|
||||||
garbaged. */
|
garbaged. */
|
||||||
|
@ -2174,7 +2312,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
first = view;
|
first = view;
|
||||||
|
|
||||||
/* Compute the transform and put it in draw_params. */
|
/* Compute the transform and put it in draw_params. */
|
||||||
ViewComputeTransform (view, &draw_params);
|
ViewComputeTransform (view, &draw_params, True);
|
||||||
|
|
||||||
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
if (!IsGarbaged (subcompositor) && (age >= 0 && age < 3))
|
||||||
{
|
{
|
||||||
|
@ -2190,8 +2328,8 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
temp_boxes.x1 = view->abs_x;
|
temp_boxes.x1 = view->abs_x;
|
||||||
temp_boxes.y1 = view->abs_y;
|
temp_boxes.y1 = view->abs_y;
|
||||||
temp_boxes.x2 = view->abs_x + ViewWidth (view);
|
temp_boxes.x2 = view->abs_x + view_width;
|
||||||
temp_boxes.y2 = view->abs_y + ViewHeight (view);
|
temp_boxes.y2 = view->abs_y + view_height;
|
||||||
|
|
||||||
if (IntersectBoxes (&boxes[i], &temp_boxes, &temp_boxes))
|
if (IntersectBoxes (&boxes[i], &temp_boxes, &temp_boxes))
|
||||||
RenderComposite (buffer, subcompositor->target, op,
|
RenderComposite (buffer, subcompositor->target, op,
|
||||||
|
@ -2226,9 +2364,9 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
/* dst-y. */
|
/* dst-y. */
|
||||||
view->abs_y - min_y + ty,
|
view->abs_y - min_y + ty,
|
||||||
/* width. */
|
/* width. */
|
||||||
ViewWidth (view),
|
view_width,
|
||||||
/* height, draw-params. */
|
/* height, draw-params. */
|
||||||
ViewHeight (view), &draw_params);
|
view_height, &draw_params);
|
||||||
|
|
||||||
/* Also adjust the opaque and input regions here. */
|
/* Also adjust the opaque and input regions here. */
|
||||||
|
|
||||||
|
@ -2248,8 +2386,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
|
|
||||||
pixman_region32_intersect_rect (&temp, &view->opaque,
|
pixman_region32_intersect_rect (&temp, &view->opaque,
|
||||||
view->abs_x, view->abs_y,
|
view->abs_x, view->abs_y,
|
||||||
ViewWidth (view),
|
view_width, view_height);
|
||||||
ViewHeight (view));
|
|
||||||
pixman_region32_union (&total_opaque, &temp, &total_opaque);
|
pixman_region32_union (&total_opaque, &temp, &total_opaque);
|
||||||
|
|
||||||
/* Translate it back. */
|
/* Translate it back. */
|
||||||
|
@ -2270,8 +2407,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
list->view->abs_y);
|
list->view->abs_y);
|
||||||
pixman_region32_intersect_rect (&temp, &view->input,
|
pixman_region32_intersect_rect (&temp, &view->input,
|
||||||
view->abs_x, view->abs_y,
|
view->abs_x, view->abs_y,
|
||||||
ViewWidth (view),
|
view_width, view_height);
|
||||||
ViewHeight (view));
|
|
||||||
pixman_region32_union (&total_input, &temp, &total_input);
|
pixman_region32_union (&total_input, &temp, &total_input);
|
||||||
|
|
||||||
/* Translate it back. */
|
/* Translate it back. */
|
||||||
|
@ -2292,7 +2428,7 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
||||||
complete:
|
complete:
|
||||||
|
|
||||||
if (IsGarbaged (subcompositor)
|
if (IsGarbaged (subcompositor)
|
||||||
|| ((age < 0 || age > 3)
|
|| ((age < 0 || age >= 3)
|
||||||
&& (IsInputDirty (subcompositor)
|
&& (IsInputDirty (subcompositor)
|
||||||
|| IsOpaqueDirty (subcompositor))))
|
|| IsOpaqueDirty (subcompositor))))
|
||||||
{
|
{
|
||||||
|
@ -2436,11 +2572,17 @@ SubcompositorExpose (Subcompositor *subcompositor, XEvent *event)
|
||||||
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
boxes = pixman_region32_rectangles (&temp, &nboxes);
|
||||||
|
|
||||||
/* Compute the transform. */
|
/* Compute the transform. */
|
||||||
ViewComputeTransform (view, &draw_params);
|
ViewComputeTransform (view, &draw_params, False);
|
||||||
|
|
||||||
/* Update the attached buffer from any damage. */
|
/* Update the attached buffer from any damage. */
|
||||||
RenderUpdateBufferForDamage (buffer, &list->view->damage,
|
RenderUpdateBufferForDamage (buffer, &list->view->damage,
|
||||||
GetContentScale (list->view->scale));
|
&draw_params);
|
||||||
|
|
||||||
|
/* If a fractional offset is set, recompute the transform again,
|
||||||
|
this time for drawing. */
|
||||||
|
if (list->view->fract_x != 0.0
|
||||||
|
|| list->view->fract_y != 0.0)
|
||||||
|
ViewComputeTransform (view, &draw_params, True);
|
||||||
|
|
||||||
for (i = 0; i < nboxes; ++i)
|
for (i = 0; i < nboxes; ++i)
|
||||||
RenderComposite (buffer, subcompositor->target, op,
|
RenderComposite (buffer, subcompositor->target, op,
|
||||||
|
|
55
subsurface.c
55
subsurface.c
|
@ -493,8 +493,10 @@ MaybeUpdateOutputs (Subsurface *subsurface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Compute the positions relative to the parent. */
|
/* Compute the positions relative to the parent. */
|
||||||
x = subsurface->current_substate.x * subsurface->parent->factor;
|
x = floor (subsurface->current_substate.x
|
||||||
y = subsurface->current_substate.y * subsurface->parent->factor;
|
* subsurface->parent->factor);
|
||||||
|
y = floor (subsurface->current_substate.y
|
||||||
|
* subsurface->parent->factor);
|
||||||
|
|
||||||
/* And the base X and Y. */
|
/* And the base X and Y. */
|
||||||
base_x = subsurface->role.surface->output_x;
|
base_x = subsurface->role.surface->output_x;
|
||||||
|
@ -525,6 +527,38 @@ MaybeUpdateOutputs (Subsurface *subsurface)
|
||||||
width, height);
|
width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
MoveFractional (Subsurface *subsurface)
|
||||||
|
{
|
||||||
|
double x, y;
|
||||||
|
int x_int, y_int;
|
||||||
|
|
||||||
|
/* Move the surface to a fractional window (subcompositor)
|
||||||
|
coordinate relative to the parent. This is done by placing the
|
||||||
|
surface at the floor of the coordinates, and then offsetting the
|
||||||
|
image and input by the remainder during rendering. */
|
||||||
|
SurfaceToWindow (subsurface->parent, subsurface->current_substate.x,
|
||||||
|
subsurface->current_substate.y, &x, &y);
|
||||||
|
|
||||||
|
x_int = floor (x);
|
||||||
|
y_int = floor (y);
|
||||||
|
|
||||||
|
/* Move the subsurface to x_int, y_int. */
|
||||||
|
ViewMove (subsurface->role.surface->view, x_int, y_int);
|
||||||
|
ViewMove (subsurface->role.surface->under, x_int, y_int);
|
||||||
|
|
||||||
|
/* Apply the fractional offset. */
|
||||||
|
ViewMoveFractional (subsurface->role.surface->view,
|
||||||
|
x - x_int, y - y_int);
|
||||||
|
ViewMoveFractional (subsurface->role.surface->under,
|
||||||
|
x - x_int, y - y_int);
|
||||||
|
|
||||||
|
/* And set the fractional offset on the surface for input handling
|
||||||
|
purposes. */
|
||||||
|
subsurface->role.surface->input_delta_x = x - x_int;
|
||||||
|
subsurface->role.surface->input_delta_y = y - y_int;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AfterParentCommit (Surface *surface, void *data)
|
AfterParentCommit (Surface *surface, void *data)
|
||||||
{
|
{
|
||||||
|
@ -540,17 +574,14 @@ AfterParentCommit (Surface *surface, void *data)
|
||||||
|
|
||||||
if (subsurface->pending_substate.flags & PendingPosition)
|
if (subsurface->pending_substate.flags & PendingPosition)
|
||||||
{
|
{
|
||||||
|
/* Apply the new position. */
|
||||||
subsurface->current_substate.x
|
subsurface->current_substate.x
|
||||||
= subsurface->pending_substate.x;
|
= subsurface->pending_substate.x;
|
||||||
subsurface->current_substate.y
|
subsurface->current_substate.y
|
||||||
= subsurface->pending_substate.y;
|
= subsurface->pending_substate.y;
|
||||||
|
|
||||||
/* The X and Y coordinates here are also parent-local and must
|
/* And move the views. */
|
||||||
be scaled by the global scale factor. */
|
MoveFractional (subsurface);
|
||||||
|
|
||||||
ViewMove (subsurface->role.surface->view,
|
|
||||||
subsurface->current_substate.x * subsurface->parent->factor,
|
|
||||||
subsurface->current_substate.y * subsurface->parent->factor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And any cached surface state too. */
|
/* And any cached surface state too. */
|
||||||
|
@ -680,6 +711,10 @@ Setup (Surface *surface, Role *role)
|
||||||
ViewGetSubcompositor (parent_view));
|
ViewGetSubcompositor (parent_view));
|
||||||
ViewInsert (parent_view, surface->view);
|
ViewInsert (parent_view, surface->view);
|
||||||
|
|
||||||
|
/* Now move the subsurface to its initial location (0, 0) */
|
||||||
|
if (subsurface->parent)
|
||||||
|
MoveFractional (subsurface);
|
||||||
|
|
||||||
/* Now add the subsurface to the parent's list of subsurfaces. */
|
/* Now add the subsurface to the parent's list of subsurfaces. */
|
||||||
subsurface->parent->subsurfaces
|
subsurface->parent->subsurfaces
|
||||||
= XLListPrepend (subsurface->parent->subsurfaces,
|
= XLListPrepend (subsurface->parent->subsurfaces,
|
||||||
|
@ -698,9 +733,7 @@ Rescale (Surface *surface, Role *role)
|
||||||
/* The scale factor changed; move the subsurface to the new correct
|
/* The scale factor changed; move the subsurface to the new correct
|
||||||
position. */
|
position. */
|
||||||
|
|
||||||
ViewMove (surface->view,
|
MoveFractional (subsurface);
|
||||||
subsurface->current_substate.x * subsurface->parent->factor,
|
|
||||||
subsurface->current_substate.y * subsurface->parent->factor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
336
surface.c
336
surface.c
|
@ -22,6 +22,7 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
#include "compositor.h"
|
#include "compositor.h"
|
||||||
|
|
||||||
|
@ -558,9 +559,7 @@ ApplyScale (Surface *surface)
|
||||||
D = C / L
|
D = C / L
|
||||||
|
|
||||||
D = (A * E) / (A / B)
|
D = (A * E) / (A / B)
|
||||||
D = B * E
|
D = B * E. */
|
||||||
|
|
||||||
Phew. */
|
|
||||||
|
|
||||||
b = scale;
|
b = scale;
|
||||||
g = global_scale_factor;
|
g = global_scale_factor;
|
||||||
|
@ -637,6 +636,161 @@ ApplyInputRegion (Surface *surface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ApplyViewport (Surface *surface)
|
||||||
|
{
|
||||||
|
State *state;
|
||||||
|
int dest_width, dest_height;
|
||||||
|
double crop_width, crop_height, src_x, src_y;
|
||||||
|
double max_width, max_height;
|
||||||
|
|
||||||
|
state = &surface->current_state;
|
||||||
|
|
||||||
|
/* If no values are specified, return and clear the viewport. */
|
||||||
|
if (state->src_x == -1 && state->dest_width == -1)
|
||||||
|
{
|
||||||
|
ViewClearViewport (surface->view);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the viewport. crop_width and crop_height describe the
|
||||||
|
amount by which to crop the surface contents, after conversion to
|
||||||
|
window geometry. dest_width and dest_height then describe how
|
||||||
|
large the surface should be. src_x and src_y describe the
|
||||||
|
origin at which to start sampling from the buffer. */
|
||||||
|
|
||||||
|
if (state->buffer)
|
||||||
|
{
|
||||||
|
max_width = XLBufferWidth (state->buffer);
|
||||||
|
max_height = XLBufferHeight (state->buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If state->buffer is not set then the source rectangle does
|
||||||
|
not have to be validated now. It will be validated later
|
||||||
|
once the buffer is attached. */
|
||||||
|
max_width = DBL_MAX;
|
||||||
|
max_height = DBL_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->src_x != -1.0)
|
||||||
|
{
|
||||||
|
/* This means a source rectangle has been specified. Set src_x
|
||||||
|
and src_y. */
|
||||||
|
src_x = state->src_x;
|
||||||
|
src_y = state->src_y;
|
||||||
|
|
||||||
|
/* Also set crop_width and crop_height. */
|
||||||
|
crop_width = state->src_width;
|
||||||
|
crop_height = state->src_height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set crop_width and crop_height to the default values, which
|
||||||
|
are the width and height of the buffer divided by the buffer
|
||||||
|
scale. */
|
||||||
|
src_x = 0;
|
||||||
|
src_y = 0;
|
||||||
|
|
||||||
|
crop_width = -1;
|
||||||
|
crop_height = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, either dest_width/dest_height are specified, or dest_width
|
||||||
|
and dest_height should be crop_width and crop_height. If the
|
||||||
|
latter, then crop_width and crop_height must be integer
|
||||||
|
values. */
|
||||||
|
|
||||||
|
if (state->dest_width != -1)
|
||||||
|
{
|
||||||
|
/* This means dest_width and dest_height have been explicitly
|
||||||
|
specified. */
|
||||||
|
dest_width = state->dest_width;
|
||||||
|
dest_height = state->dest_height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((rint (crop_width) != crop_width
|
||||||
|
|| rint (crop_height) != crop_height)
|
||||||
|
/* If the src_width and src_height were not specified
|
||||||
|
manually but were computed from the buffer scale, don't
|
||||||
|
complain that they are not integer values. The
|
||||||
|
underlying viewport code satisfactorily handles
|
||||||
|
fractional width and height anyway. */
|
||||||
|
&& state->src_x != 1.0)
|
||||||
|
goto bad_size;
|
||||||
|
|
||||||
|
dest_width = state->src_width;
|
||||||
|
dest_height = state->src_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now all of the fields above must be set. Verify that none of
|
||||||
|
them lie outside the buffer. */
|
||||||
|
if (state->src_x != -1
|
||||||
|
&& (src_x + crop_width - 1 >= max_width / state->buffer_scale
|
||||||
|
|| src_y + crop_height - 1 >= max_height / state->buffer_scale))
|
||||||
|
goto out_of_buffer;
|
||||||
|
|
||||||
|
/* Finally, set the viewport. Convert the values to window
|
||||||
|
coordinates. */
|
||||||
|
src_x *= surface->factor;
|
||||||
|
src_y *= surface->factor;
|
||||||
|
|
||||||
|
if (crop_width != -1)
|
||||||
|
{
|
||||||
|
crop_width *= surface->factor;
|
||||||
|
crop_height *= surface->factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_width *= surface->factor;
|
||||||
|
dest_height *= surface->factor;
|
||||||
|
|
||||||
|
/* And really set the viewport. */
|
||||||
|
ViewSetViewport (surface->view, src_x, src_y, crop_width,
|
||||||
|
crop_height, dest_width, dest_height);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
bad_size:
|
||||||
|
/* By this point, surface->viewport should be non-NULL; however, if
|
||||||
|
a synchronous subsurface applies invalid viewporter state,
|
||||||
|
commits it, destroys the wp_viewport resource, and the parent
|
||||||
|
commits, then the cached state applied due to the parent commit
|
||||||
|
will be invalid, but the viewport resource will no longer be
|
||||||
|
associated with the surface. I don't know what to do in that
|
||||||
|
case, so leave the behavior undefined. */
|
||||||
|
if (surface->viewport)
|
||||||
|
XLWpViewportReportBadSize (surface->viewport);
|
||||||
|
return;
|
||||||
|
|
||||||
|
out_of_buffer:
|
||||||
|
if (surface->viewport)
|
||||||
|
XLWpViewportReportOutOfBuffer (surface->viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
CheckViewportValues (Surface *surface)
|
||||||
|
{
|
||||||
|
State *state;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
state = &surface->current_state;
|
||||||
|
|
||||||
|
if (!surface->viewport || state->src_x == -1.0
|
||||||
|
|| !state->buffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* A buffer is attached and a viewport source rectangle is set;
|
||||||
|
check that it remains in bounds. */
|
||||||
|
|
||||||
|
width = XLBufferWidth (state->buffer);
|
||||||
|
height = XLBufferHeight (state->buffer);
|
||||||
|
|
||||||
|
if (state->src_x + state->src_width - 1 >= width / state->buffer_scale
|
||||||
|
|| state->src_y + state->src_height - 1 >= height / state->buffer_scale)
|
||||||
|
XLWpViewportReportBadSize (surface->viewport);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
HandleScaleChanged (void *data, int new_scale)
|
HandleScaleChanged (void *data, int new_scale)
|
||||||
{
|
{
|
||||||
|
@ -650,6 +804,7 @@ HandleScaleChanged (void *data, int new_scale)
|
||||||
ApplyScale (surface);
|
ApplyScale (surface);
|
||||||
ApplyInputRegion (surface);
|
ApplyInputRegion (surface);
|
||||||
ApplyOpaqueRegion (surface);
|
ApplyOpaqueRegion (surface);
|
||||||
|
ApplyViewport (surface);
|
||||||
|
|
||||||
/* Next, call any role-specific hooks. */
|
/* Next, call any role-specific hooks. */
|
||||||
if (surface->role && surface->role->funcs.rescale)
|
if (surface->role && surface->role->funcs.rescale)
|
||||||
|
@ -680,21 +835,44 @@ ApplyDamage (Surface *surface)
|
||||||
{
|
{
|
||||||
pixman_region32_t temp;
|
pixman_region32_t temp;
|
||||||
int scale;
|
int scale;
|
||||||
|
float x_factor, y_factor;
|
||||||
|
|
||||||
scale = GetEffectiveScale (surface->current_state.buffer_scale);
|
scale = GetEffectiveScale (surface->current_state.buffer_scale);
|
||||||
|
|
||||||
/* N.B. that this must come after the scale is applied. */
|
/* N.B. that this must come after the scale is applied. */
|
||||||
|
|
||||||
if (scale)
|
if (scale || surface->current_state.src_x != -1
|
||||||
|
|| surface->current_state.dest_width != -1)
|
||||||
{
|
{
|
||||||
pixman_region32_init (&temp);
|
pixman_region32_init (&temp);
|
||||||
|
|
||||||
|
if (!scale)
|
||||||
|
x_factor = y_factor = 1.0;
|
||||||
if (scale > 0)
|
if (scale > 0)
|
||||||
XLScaleRegion (&temp, &surface->current_state.damage,
|
x_factor = y_factor = 1.0 / (scale + 1);
|
||||||
1.0 / (scale + 1), 1.0 / (scale + 1));
|
|
||||||
else
|
else
|
||||||
|
x_factor = y_factor = abs (scale) + 1;
|
||||||
|
|
||||||
|
/* If a viewport dest size is set, add that to the scale as
|
||||||
|
well. */
|
||||||
|
if (surface->current_state.src_width != -1)
|
||||||
|
{
|
||||||
|
x_factor += (float) (surface->current_state.src_width
|
||||||
|
/ surface->current_state.dest_width);
|
||||||
|
y_factor += (float) (surface->current_state.src_height
|
||||||
|
/ surface->current_state.dest_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x_factor != 1.0f && y_factor != 1.0f)
|
||||||
XLScaleRegion (&temp, &surface->current_state.damage,
|
XLScaleRegion (&temp, &surface->current_state.damage,
|
||||||
abs (scale) + 1, abs (scale) + 1);
|
x_factor, y_factor);
|
||||||
|
|
||||||
|
/* If a viewport is set, translate the damage region by the
|
||||||
|
src_x and src_y. This is lossy. */
|
||||||
|
if (surface->current_state.src_x != -1.0)
|
||||||
|
pixman_region32_translate (&temp,
|
||||||
|
floor (surface->current_state.src_x),
|
||||||
|
floor (surface->current_state.src_y));
|
||||||
|
|
||||||
ViewDamage (surface->view, &temp);
|
ViewDamage (surface->view, &temp);
|
||||||
|
|
||||||
|
@ -767,6 +945,25 @@ SavePendingState (Surface *surface)
|
||||||
surface->cached_state.buffer_scale
|
surface->cached_state.buffer_scale
|
||||||
= surface->pending_state.buffer_scale;
|
= surface->pending_state.buffer_scale;
|
||||||
|
|
||||||
|
if (surface->pending_state.pending & PendingViewportDest)
|
||||||
|
{
|
||||||
|
surface->cached_state.dest_width
|
||||||
|
= surface->pending_state.dest_width;
|
||||||
|
surface->cached_state.dest_height
|
||||||
|
= surface->pending_state.dest_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface->pending_state.pending & PendingViewportSrc)
|
||||||
|
{
|
||||||
|
surface->cached_state.src_x = surface->pending_state.src_x;
|
||||||
|
surface->cached_state.src_y = surface->pending_state.src_y;
|
||||||
|
|
||||||
|
surface->cached_state.src_width
|
||||||
|
= surface->pending_state.src_width;
|
||||||
|
surface->cached_state.src_height
|
||||||
|
= surface->pending_state.src_height;
|
||||||
|
}
|
||||||
|
|
||||||
if (surface->pending_state.pending & PendingAttachments)
|
if (surface->pending_state.pending & PendingAttachments)
|
||||||
{
|
{
|
||||||
surface->cached_state.x = surface->pending_state.x;
|
surface->cached_state.x = surface->pending_state.x;
|
||||||
|
@ -860,6 +1057,11 @@ InternalCommit (Surface *surface, State *pending)
|
||||||
pending->buffer);
|
pending->buffer);
|
||||||
ApplyBuffer (surface);
|
ApplyBuffer (surface);
|
||||||
ClearBuffer (pending);
|
ClearBuffer (pending);
|
||||||
|
|
||||||
|
/* Check that any applied viewport source rectangles remain
|
||||||
|
valid. */
|
||||||
|
if (!(pending->pending & PendingViewportSrc))
|
||||||
|
CheckViewportValues (surface);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -889,6 +1091,29 @@ InternalCommit (Surface *surface, State *pending)
|
||||||
ApplyOpaqueRegion (surface);
|
ApplyOpaqueRegion (surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pending->pending & PendingViewportSrc
|
||||||
|
|| pending->pending & PendingViewportDest)
|
||||||
|
{
|
||||||
|
/* Copy the viewport data over to the current state. */
|
||||||
|
|
||||||
|
if (pending->pending & PendingViewportDest)
|
||||||
|
{
|
||||||
|
surface->current_state.dest_width = pending->dest_width;
|
||||||
|
surface->current_state.dest_height = pending->dest_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pending->pending & PendingViewportSrc)
|
||||||
|
{
|
||||||
|
surface->current_state.src_x = pending->src_x;
|
||||||
|
surface->current_state.src_y = pending->src_y;
|
||||||
|
surface->current_state.src_width = pending->src_width;
|
||||||
|
surface->current_state.src_height = pending->src_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And apply the viewport now. */
|
||||||
|
ApplyViewport (surface);
|
||||||
|
}
|
||||||
|
|
||||||
if (pending->pending & PendingAttachments)
|
if (pending->pending & PendingAttachments)
|
||||||
{
|
{
|
||||||
surface->current_state.x = pending->x;
|
surface->current_state.x = pending->x;
|
||||||
|
@ -1077,6 +1302,14 @@ InitState (State *state)
|
||||||
state->frame_callbacks.next = &state->frame_callbacks;
|
state->frame_callbacks.next = &state->frame_callbacks;
|
||||||
state->frame_callbacks.last = &state->frame_callbacks;
|
state->frame_callbacks.last = &state->frame_callbacks;
|
||||||
state->frame_callbacks.resource = NULL;
|
state->frame_callbacks.resource = NULL;
|
||||||
|
|
||||||
|
/* Initialize the viewport to the default undefined values. */
|
||||||
|
state->dest_width = -1;
|
||||||
|
state->dest_height = -1;
|
||||||
|
state->src_x = -1.0;
|
||||||
|
state->src_y = -1.0;
|
||||||
|
state->src_width = -1.0;
|
||||||
|
state->src_height = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1321,16 +1554,17 @@ XLStateDetachBuffer (State *state)
|
||||||
void
|
void
|
||||||
XLSurfaceRunFrameCallbacks (Surface *surface, struct timespec time)
|
XLSurfaceRunFrameCallbacks (Surface *surface, struct timespec time)
|
||||||
{
|
{
|
||||||
uint32_t ms_time;
|
uint64_t ms_time;
|
||||||
XLList *list;
|
XLList *list;
|
||||||
|
|
||||||
/* I don't know what else is reasonable in case of overflow. */
|
/* If ms_time is too large to fit in uint32_t, take the lower 32
|
||||||
|
bits. */
|
||||||
|
|
||||||
if (IntMultiplyWrapv (time.tv_sec, 1000, &ms_time))
|
if (IntMultiplyWrapv (time.tv_sec, 1000, &ms_time))
|
||||||
ms_time = UINT32_MAX;
|
ms_time = UINT64_MAX;
|
||||||
else if (IntAddWrapv (ms_time, time.tv_nsec / 1000000,
|
else if (IntAddWrapv (ms_time, time.tv_nsec / 1000000,
|
||||||
&ms_time))
|
&ms_time))
|
||||||
ms_time = UINT32_MAX;
|
ms_time = UINT64_MAX;
|
||||||
|
|
||||||
RunFrameCallbacks (&surface->current_state.frame_callbacks,
|
RunFrameCallbacks (&surface->current_state.frame_callbacks,
|
||||||
ms_time);
|
ms_time);
|
||||||
|
@ -1474,3 +1708,83 @@ XLSurfaceMoveBy (Surface *surface, int west, int north)
|
||||||
surface->role->funcs.move_by (surface, surface->role,
|
surface->role->funcs.move_by (surface, surface->role,
|
||||||
west, north);
|
west, north);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The following functions convert from window to surface
|
||||||
|
coordinates and vice versa:
|
||||||
|
|
||||||
|
SurfaceToWindow - take given surface coordinate, and return a
|
||||||
|
window relative coordinate.
|
||||||
|
ScaleToWindow - take given surface dimension, and return a
|
||||||
|
window relative dimension.
|
||||||
|
WindowToSurface - take given window coordinate, and return a
|
||||||
|
surface relative coordinate as a double.
|
||||||
|
ScaleToSurface - take given window dimension, and return a
|
||||||
|
surface relative dimension.
|
||||||
|
|
||||||
|
Functions prefixed by "truncate" return and accept integer values
|
||||||
|
instead of floating point ones; truncation is performed on
|
||||||
|
fractional values. */
|
||||||
|
|
||||||
|
void
|
||||||
|
SurfaceToWindow (Surface *surface, double x, double y,
|
||||||
|
double *x_out, double *y_out)
|
||||||
|
{
|
||||||
|
*x_out = x * surface->factor + surface->input_delta_x;
|
||||||
|
*y_out = y * surface->factor + surface->input_delta_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ScaleToWindow (Surface *surface, double width, double height,
|
||||||
|
double *width_out, double *height_out)
|
||||||
|
{
|
||||||
|
*width_out = width * surface->factor;
|
||||||
|
*height_out = height * surface->factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WindowToSurface (Surface *surface, double x, double y,
|
||||||
|
double *x_out, double *y_out)
|
||||||
|
{
|
||||||
|
*x_out = x / surface->factor - surface->input_delta_x;
|
||||||
|
*y_out = y / surface->factor - surface->input_delta_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ScaleToSurface (Surface *surface, double width, double height,
|
||||||
|
double *width_out, double *height_out)
|
||||||
|
{
|
||||||
|
*width_out = width / surface->factor;
|
||||||
|
*height_out = height / surface->factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TruncateSurfaceToWindow (Surface *surface, int x, int y,
|
||||||
|
int *x_out, int *y_out)
|
||||||
|
{
|
||||||
|
*x_out = x * surface->factor + surface->input_delta_x;
|
||||||
|
*y_out = y * surface->factor + surface->input_delta_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TruncateScaleToWindow (Surface *surface, int width, int height,
|
||||||
|
int *width_out, int *height_out)
|
||||||
|
{
|
||||||
|
*width_out = width * surface->factor;
|
||||||
|
*height_out = height * surface->factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TruncateWindowToSurface (Surface *surface, int x, int y,
|
||||||
|
int *x_out, int *y_out)
|
||||||
|
{
|
||||||
|
*x_out = x / surface->factor - surface->input_delta_x;
|
||||||
|
*y_out = y / surface->factor - surface->input_delta_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TruncateScaleToSurface (Surface *surface, int width, int height,
|
||||||
|
int *width_out, int *height_out)
|
||||||
|
{
|
||||||
|
*width_out = width / surface->factor;
|
||||||
|
*height_out = height / surface->factor;
|
||||||
|
}
|
||||||
|
|
26
xdg_popup.c
26
xdg_popup.c
|
@ -278,7 +278,6 @@ MoveWindow (XdgPopup *popup)
|
||||||
int root_x, root_y, parent_gx, parent_gy;
|
int root_x, root_y, parent_gx, parent_gy;
|
||||||
int geometry_x, geometry_y, x, y;
|
int geometry_x, geometry_y, x, y;
|
||||||
Window window;
|
Window window;
|
||||||
double parent_scale, current_scale;
|
|
||||||
|
|
||||||
/* No parent was specified. */
|
/* No parent was specified. */
|
||||||
if (!popup->parent)
|
if (!popup->parent)
|
||||||
|
@ -292,9 +291,6 @@ MoveWindow (XdgPopup *popup)
|
||||||
scale. */
|
scale. */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
parent_scale = popup->parent->surface->factor;
|
|
||||||
current_scale = popup->role->surface->factor;
|
|
||||||
|
|
||||||
window = XLWindowFromXdgRole (popup->role);
|
window = XLWindowFromXdgRole (popup->role);
|
||||||
|
|
||||||
XLXdgRoleGetCurrentGeometry (popup->parent, &parent_gx,
|
XLXdgRoleGetCurrentGeometry (popup->parent, &parent_gx,
|
||||||
|
@ -305,17 +301,17 @@ MoveWindow (XdgPopup *popup)
|
||||||
&root_y);
|
&root_y);
|
||||||
|
|
||||||
/* Parent geometry is relative to the parent coordinate system. */
|
/* Parent geometry is relative to the parent coordinate system. */
|
||||||
parent_gx *= parent_scale;
|
TruncateSurfaceToWindow (popup->parent->surface, parent_gx, parent_gy,
|
||||||
parent_gy *= parent_scale;
|
&parent_gx, &parent_gy);
|
||||||
|
|
||||||
/* geometry_x and geometry_y are relative to the local coordinate
|
/* geometry_x and geometry_y are relative to the local coordinate
|
||||||
system. */
|
system. */
|
||||||
geometry_x *= current_scale;
|
TruncateSurfaceToWindow (popup->role->surface, geometry_x,
|
||||||
geometry_y *= current_scale;
|
geometry_y, &geometry_x, &geometry_y);
|
||||||
|
|
||||||
/* X and Y are relative to the parent coordinate system. */
|
/* X and Y are relative to the parent coordinate system. */
|
||||||
x = popup->x * parent_scale;
|
TruncateSurfaceToWindow (popup->parent->surface, popup->x,
|
||||||
y = popup->y * parent_scale;
|
popup->y, &x, &y);
|
||||||
|
|
||||||
XMoveWindow (compositor.display, window,
|
XMoveWindow (compositor.display, window,
|
||||||
x + root_x + parent_gx - geometry_x,
|
x + root_x + parent_gx - geometry_x,
|
||||||
|
@ -754,6 +750,15 @@ HandleParentResize (void *data)
|
||||||
InternalReposition (popup);
|
InternalReposition (popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
IsWindowMapped (Role *role, XdgRoleImplementation *impl)
|
||||||
|
{
|
||||||
|
XdgPopup *popup;
|
||||||
|
|
||||||
|
popup = PopupFromRoleImpl (impl);
|
||||||
|
return popup->state & StateIsMapped;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct xdg_popup_interface xdg_popup_impl =
|
static const struct xdg_popup_interface xdg_popup_impl =
|
||||||
{
|
{
|
||||||
.destroy = Destroy,
|
.destroy = Destroy,
|
||||||
|
@ -798,6 +803,7 @@ XLGetXdgPopup (struct wl_client *client, struct wl_resource *resource,
|
||||||
popup->impl.funcs.ack_configure = AckConfigure;
|
popup->impl.funcs.ack_configure = AckConfigure;
|
||||||
popup->impl.funcs.note_size = NoteSize;
|
popup->impl.funcs.note_size = NoteSize;
|
||||||
popup->impl.funcs.handle_geometry_change = HandleGeometryChange;
|
popup->impl.funcs.handle_geometry_change = HandleGeometryChange;
|
||||||
|
popup->impl.funcs.is_window_mapped = IsWindowMapped;
|
||||||
|
|
||||||
if (parent_resource)
|
if (parent_resource)
|
||||||
{
|
{
|
||||||
|
|
|
@ -628,6 +628,13 @@ Unfreeze (XdgRole *role)
|
||||||
XLFrameClockUnfreeze (role->clock);
|
XLFrameClockUnfreeze (role->clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
IsRoleMapped (XdgRole *role)
|
||||||
|
{
|
||||||
|
return role->impl->funcs.is_window_mapped (&role->role,
|
||||||
|
role->impl);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Commit (Surface *surface, Role *role)
|
Commit (Surface *surface, Role *role)
|
||||||
{
|
{
|
||||||
|
@ -666,6 +673,12 @@ Commit (Surface *surface, Role *role)
|
||||||
ack_configure. */
|
ack_configure. */
|
||||||
xdg_role->state &= ~StateWaitingForAckCommit;
|
xdg_role->state &= ~StateWaitingForAckCommit;
|
||||||
|
|
||||||
|
/* If the window is unmapped, skip all of this code! Once the
|
||||||
|
window is mapped again, the compositor will send _NET_FRAME_DRAWN
|
||||||
|
should a frame still be in progress. */
|
||||||
|
if (!IsRoleMapped (xdg_role))
|
||||||
|
goto start_drawing;
|
||||||
|
|
||||||
/* A frame is already in progress, so instead say that an urgent
|
/* A frame is already in progress, so instead say that an urgent
|
||||||
update is needed immediately after the frame completes. In any
|
update is needed immediately after the frame completes. In any
|
||||||
case, don't run frame callbacks upon buffer release anymore. */
|
case, don't run frame callbacks upon buffer release anymore. */
|
||||||
|
@ -687,6 +700,8 @@ Commit (Surface *surface, Role *role)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_drawing:
|
||||||
|
|
||||||
/* If the frame clock is frozen but we are no longer waiting for the
|
/* If the frame clock is frozen but we are no longer waiting for the
|
||||||
configure event to be acknowledged by the client, unfreeze the
|
configure event to be acknowledged by the client, unfreeze the
|
||||||
frame clock. */
|
frame clock. */
|
||||||
|
@ -706,7 +721,13 @@ Commit (Surface *surface, Role *role)
|
||||||
callbacks are not provided by the frame clock while it is frozen.
|
callbacks are not provided by the frame clock while it is frozen.
|
||||||
|
|
||||||
If that happens, just run the frame callback immediately. */
|
If that happens, just run the frame callback immediately. */
|
||||||
if (XLFrameClockIsFrozen (xdg_role->clock))
|
if (XLFrameClockIsFrozen (xdg_role->clock)
|
||||||
|
/* If the window is not mapped, then the native frame clock will
|
||||||
|
not draw frames. Some clients do commit before the initial
|
||||||
|
configure event and wait for the frame callback to be called
|
||||||
|
after or before ack_configure, leading to the mapping commit
|
||||||
|
never being performed. */
|
||||||
|
|| !IsRoleMapped (xdg_role))
|
||||||
RunFrameCallbacksConditionally (xdg_role);
|
RunFrameCallbacksConditionally (xdg_role);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -843,6 +864,10 @@ Subframe (Surface *surface, Role *role)
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Similarly, return False if the role is unmapped. */
|
||||||
|
if (!IsRoleMapped (xdg_role))
|
||||||
|
return False;
|
||||||
|
|
||||||
/* If a frame is already in progress, return False. Then, require a
|
/* If a frame is already in progress, return False. Then, require a
|
||||||
late frame. */
|
late frame. */
|
||||||
if (XLFrameClockFrameInProgress (xdg_role->clock))
|
if (XLFrameClockFrameInProgress (xdg_role->clock))
|
||||||
|
@ -1167,8 +1192,8 @@ GetResizeDimensions (Surface *surface, Role *role, int *x_out,
|
||||||
{
|
{
|
||||||
XLXdgRoleGetCurrentGeometry (role, NULL, NULL, x_out, y_out);
|
XLXdgRoleGetCurrentGeometry (role, NULL, NULL, x_out, y_out);
|
||||||
|
|
||||||
*x_out *= surface->factor;
|
/* Scale these surface-local dimensions to window-local ones. */
|
||||||
*y_out *= surface->factor;
|
TruncateSurfaceToWindow (surface, *x_out, *y_out, x_out, y_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1481,10 +1506,15 @@ XLXdgRoleCalcNewWindowSize (Role *role, int width, int height,
|
||||||
SubcompositorBounds (xdg_role->subcompositor,
|
SubcompositorBounds (xdg_role->subcompositor,
|
||||||
&min_x, &min_y, &max_x, &max_y);
|
&min_x, &min_y, &max_x, &max_y);
|
||||||
|
|
||||||
/* Adjust the current_width and current_height by the global scale
|
/* Calculate the current width and height. */
|
||||||
|
current_width = (max_x - min_x + 1);
|
||||||
|
current_height = (max_y - min_y + 1);
|
||||||
|
|
||||||
|
/* Adjust the current_width and current_height by the scale
|
||||||
factor. */
|
factor. */
|
||||||
current_width = (max_x - min_x + 1) / role->surface->factor;
|
TruncateScaleToSurface (role->surface, current_width,
|
||||||
current_height = (max_y - min_y + 1) / role->surface->factor;
|
current_height, ¤t_width,
|
||||||
|
¤t_height);
|
||||||
|
|
||||||
XLXdgRoleGetCurrentGeometry (role, NULL, NULL, &geometry_width,
|
XLXdgRoleGetCurrentGeometry (role, NULL, NULL, &geometry_width,
|
||||||
&geometry_height);
|
&geometry_height);
|
||||||
|
|
|
@ -283,6 +283,15 @@ RunUnmapCallbacks (XdgToplevel *toplevel)
|
||||||
toplevel->unmap_callbacks.last = &toplevel->unmap_callbacks;
|
toplevel->unmap_callbacks.last = &toplevel->unmap_callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
IsWindowMapped (Role *role, XdgRoleImplementation *impl)
|
||||||
|
{
|
||||||
|
XdgToplevel *toplevel;
|
||||||
|
|
||||||
|
toplevel = ToplevelFromRoleImpl (impl);
|
||||||
|
return toplevel->state & StateIsMapped;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
WriteHints (XdgToplevel *toplevel)
|
WriteHints (XdgToplevel *toplevel)
|
||||||
{
|
{
|
||||||
|
@ -362,13 +371,9 @@ NoteConfigureTime (Timer *timer, void *data, struct timespec time)
|
||||||
{
|
{
|
||||||
XdgToplevel *toplevel;
|
XdgToplevel *toplevel;
|
||||||
int width, height, effective_width, effective_height;
|
int width, height, effective_width, effective_height;
|
||||||
double factor;
|
|
||||||
|
|
||||||
toplevel = data;
|
toplevel = data;
|
||||||
|
|
||||||
/* Obtain the scale factor. toplevel->role->surface should not be
|
|
||||||
NULL here, as the timer is cancelled upon role detachment. */
|
|
||||||
factor = toplevel->role->surface->factor;
|
|
||||||
|
|
||||||
/* If only the window state changed, call SendStates. */
|
/* If only the window state changed, call SendStates. */
|
||||||
if (!(toplevel->state & StatePendingConfigureSize))
|
if (!(toplevel->state & StatePendingConfigureSize))
|
||||||
|
@ -379,8 +384,14 @@ NoteConfigureTime (Timer *timer, void *data, struct timespec time)
|
||||||
if (toplevel->state & StatePendingConfigureStates)
|
if (toplevel->state & StatePendingConfigureStates)
|
||||||
WriteStates (toplevel);
|
WriteStates (toplevel);
|
||||||
|
|
||||||
effective_width = toplevel->configure_width / factor;
|
effective_width = toplevel->configure_width;
|
||||||
effective_height = toplevel->configure_height / factor;
|
effective_height = toplevel->configure_height;
|
||||||
|
|
||||||
|
/* toplevel->role->surface should not be NULL here, as the timer
|
||||||
|
is cancelled upon role detachment. */
|
||||||
|
TruncateScaleToSurface (toplevel->role->surface,
|
||||||
|
effective_width, effective_height,
|
||||||
|
&effective_width, &effective_height);
|
||||||
|
|
||||||
/* Compute the geometry for the configure event based on the
|
/* Compute the geometry for the configure event based on the
|
||||||
current size of the toplevel. */
|
current size of the toplevel. */
|
||||||
|
@ -482,24 +493,24 @@ static void
|
||||||
SendStates (XdgToplevel *toplevel)
|
SendStates (XdgToplevel *toplevel)
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
double factor;
|
|
||||||
|
|
||||||
WriteStates (toplevel);
|
WriteStates (toplevel);
|
||||||
|
|
||||||
/* Obtain the scale factor. toplevel->role->surface should not be
|
|
||||||
NULL here. */
|
|
||||||
factor = toplevel->role->surface->factor;
|
|
||||||
|
|
||||||
/* Adjust the width and height we're sending by the window
|
/* Adjust the width and height we're sending by the window
|
||||||
geometry. */
|
geometry. */
|
||||||
if (toplevel->state & StateMissingState)
|
if (toplevel->state & StateMissingState)
|
||||||
XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL,
|
XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL,
|
||||||
&width, &height);
|
&width, &height);
|
||||||
else
|
else
|
||||||
XLXdgRoleCalcNewWindowSize (toplevel->role,
|
{
|
||||||
toplevel->width / factor,
|
/* toplevel->role->surface should not be NULL here. */
|
||||||
toplevel->height / factor,
|
TruncateScaleToSurface (toplevel->role->surface,
|
||||||
&width, &height);
|
toplevel->width, toplevel->height,
|
||||||
|
&width, &height);
|
||||||
|
|
||||||
|
XLXdgRoleCalcNewWindowSize (toplevel->role, width,
|
||||||
|
height, &width, &height);
|
||||||
|
}
|
||||||
|
|
||||||
SendConfigure (toplevel, width, height);
|
SendConfigure (toplevel, width, height);
|
||||||
|
|
||||||
|
@ -515,15 +526,11 @@ RecordStateSize (XdgToplevel *toplevel)
|
||||||
{
|
{
|
||||||
Bool a, b;
|
Bool a, b;
|
||||||
int width, height;
|
int width, height;
|
||||||
double factor;
|
|
||||||
|
|
||||||
if (!toplevel->role->surface)
|
if (!toplevel->role->surface)
|
||||||
/* We can't get the scale factor in this case. */
|
/* We can't get the scale factor in this case. */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Obtain the scale factor. */
|
|
||||||
factor = toplevel->role->surface->factor;
|
|
||||||
|
|
||||||
/* Record the last known size of a toplevel before its state is
|
/* Record the last known size of a toplevel before its state is
|
||||||
changed. That way, we can send xdg_toplevel::configure with the
|
changed. That way, we can send xdg_toplevel::configure with the
|
||||||
right state, should the window manager send ConfigureNotify
|
right state, should the window manager send ConfigureNotify
|
||||||
|
@ -539,8 +546,10 @@ RecordStateSize (XdgToplevel *toplevel)
|
||||||
upon minimization. */
|
upon minimization. */
|
||||||
XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL,
|
XLXdgRoleGetCurrentGeometry (toplevel->role, NULL, NULL,
|
||||||
&width, &height);
|
&width, &height);
|
||||||
width *= factor;
|
|
||||||
height *= factor;
|
/* Scale the width and height to window dimensions. */
|
||||||
|
TruncateScaleToWindow (toplevel->role->surface, width, height,
|
||||||
|
&width, &height);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -795,11 +804,9 @@ HandleWindowGeometryChange (XdgToplevel *toplevel)
|
||||||
|
|
||||||
XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y,
|
XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y,
|
||||||
&width, &height);
|
&width, &height);
|
||||||
|
TruncateScaleToWindow (toplevel->role->surface, width, height,
|
||||||
width *= toplevel->role->surface->factor;
|
&width, &height);
|
||||||
height *= toplevel->role->surface->factor;
|
TruncateSurfaceToWindow (toplevel->role->surface, x, y, &x, &y);
|
||||||
x *= toplevel->role->surface->factor;
|
|
||||||
y *= toplevel->role->surface->factor;
|
|
||||||
|
|
||||||
dx = SubcompositorWidth (subcompositor) - width;
|
dx = SubcompositorWidth (subcompositor) - width;
|
||||||
dy = SubcompositorHeight (subcompositor) - height;
|
dy = SubcompositorHeight (subcompositor) - height;
|
||||||
|
@ -813,21 +820,25 @@ HandleWindowGeometryChange (XdgToplevel *toplevel)
|
||||||
/* Initially, specify PSize. After the first MapNotify, also
|
/* Initially, specify PSize. After the first MapNotify, also
|
||||||
specify PPosition so that subsurfaces won't move the window. */
|
specify PPosition so that subsurfaces won't move the window. */
|
||||||
|
|
||||||
hints->min_width = (toplevel->min_width
|
/* First, make hints->min_width and hints->min_height the min width
|
||||||
* toplevel->role->surface->factor
|
in terms of the window coordinate system. Then, add deltas. */
|
||||||
+ dx);
|
TruncateScaleToWindow (toplevel->role->surface, toplevel->min_width,
|
||||||
hints->min_height = (toplevel->min_height
|
toplevel->min_height, &hints->min_width,
|
||||||
* toplevel->role->surface->factor
|
&hints->min_height);
|
||||||
+ dy);
|
|
||||||
|
/* Add deltas. */
|
||||||
|
hints->min_width += dx;
|
||||||
|
hints->min_height += dy;
|
||||||
|
|
||||||
if (toplevel->max_width)
|
if (toplevel->max_width)
|
||||||
{
|
{
|
||||||
hints->max_width = (toplevel->max_width
|
/* Do the same with the max width. */
|
||||||
* toplevel->role->surface->factor
|
TruncateScaleToWindow (toplevel->role->surface, toplevel->max_width,
|
||||||
+ dx);
|
toplevel->max_height, &hints->max_width,
|
||||||
hints->max_height = (toplevel->max_height
|
&hints->max_height);
|
||||||
* toplevel->role->surface->factor
|
|
||||||
+ dy);
|
hints->max_width += dx;
|
||||||
|
hints->max_height += dy;
|
||||||
hints->flags |= PMaxSize;
|
hints->flags |= PMaxSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1373,10 +1384,13 @@ NoteWindowPreResize (Role *role, XdgRoleImplementation *impl,
|
||||||
XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y,
|
XLXdgRoleGetCurrentGeometry (toplevel->role, &x, &y,
|
||||||
&gwidth, &gheight);
|
&gwidth, &gheight);
|
||||||
|
|
||||||
dx = width - gwidth * toplevel->role->surface->factor;
|
/* Scale the window geometry to window dimensions. */
|
||||||
dy = height - gheight * toplevel->role->surface->factor;
|
TruncateScaleToWindow (toplevel->role->surface, gwidth, gheight,
|
||||||
x *= toplevel->role->surface->factor;
|
&gwidth, &gheight);
|
||||||
y *= toplevel->role->surface->factor;
|
TruncateSurfaceToWindow (toplevel->role->surface, x, y, &x, &y);
|
||||||
|
|
||||||
|
dx = width - gwidth;
|
||||||
|
dy = height - gheight;
|
||||||
|
|
||||||
ApplyGtkFrameExtents (toplevel, x, y, dx - x, dy - y);
|
ApplyGtkFrameExtents (toplevel, x, y, dx - x, dy - y);
|
||||||
}
|
}
|
||||||
|
@ -1966,6 +1980,7 @@ XLGetXdgToplevel (struct wl_client *client, struct wl_resource *resource,
|
||||||
toplevel->impl.funcs.handle_geometry_change = HandleGeometryChange;
|
toplevel->impl.funcs.handle_geometry_change = HandleGeometryChange;
|
||||||
toplevel->impl.funcs.post_resize = PostResize;
|
toplevel->impl.funcs.post_resize = PostResize;
|
||||||
toplevel->impl.funcs.commit_inside_frame = CommitInsideFrame;
|
toplevel->impl.funcs.commit_inside_frame = CommitInsideFrame;
|
||||||
|
toplevel->impl.funcs.is_window_mapped = IsWindowMapped;
|
||||||
|
|
||||||
/* Set up the sentinel node for the list of unmap callbacks. */
|
/* Set up the sentinel node for the list of unmap callbacks. */
|
||||||
toplevel->unmap_callbacks.next = &toplevel->unmap_callbacks;
|
toplevel->unmap_callbacks.next = &toplevel->unmap_callbacks;
|
||||||
|
|
Loading…
Add table
Reference in a new issue