2019-12-17 15:07:07 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2011-2014 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
|
|
|
* and its documentation for any purpose is hereby granted without
|
|
|
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
|
|
|
* and that both that copyright notice and this permission notice
|
|
|
|
|
* appear in supporting documentation, and that the name of the
|
|
|
|
|
* copyright holders not be used in advertising or publicity
|
|
|
|
|
* pertaining to distribution of the software without specific,
|
|
|
|
|
* written prior permission. The copyright holders make no
|
|
|
|
|
* representations about the suitability of this software for any
|
|
|
|
|
* purpose. It is provided "as is" without express or implied
|
|
|
|
|
* warranty.
|
|
|
|
|
*
|
|
|
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
|
|
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
|
|
|
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <dix-config.h>
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
#include <float.h>
|
2023-11-02 10:25:46 +01:00
|
|
|
#include <math.h>
|
2022-12-20 12:15:15 +01:00
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
#include <X11/X.h>
|
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
|
|
2024-03-01 18:52:58 +01:00
|
|
|
#include "dix/dix_priv.h"
|
2024-05-13 17:43:01 +02:00
|
|
|
#include "dix/property_priv.h"
|
2024-03-01 18:52:58 +01:00
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
#include "compositeext.h"
|
|
|
|
|
#include "compint.h"
|
|
|
|
|
#include "inputstr.h"
|
|
|
|
|
#include "propertyst.h"
|
|
|
|
|
|
|
|
|
|
#include "xwayland-types.h"
|
2019-12-17 17:40:21 +01:00
|
|
|
#include "xwayland-input.h"
|
2024-01-18 17:10:57 +01:00
|
|
|
#include "xwayland-pixmap.h"
|
2019-12-17 17:18:11 +01:00
|
|
|
#include "xwayland-present.h"
|
2019-12-18 10:03:43 +01:00
|
|
|
#include "xwayland-screen.h"
|
2019-12-17 15:07:07 +01:00
|
|
|
#include "xwayland-window.h"
|
|
|
|
|
#include "xwayland-window-buffers.h"
|
|
|
|
|
#include "xwayland-shm.h"
|
2023-04-06 11:34:51 +02:00
|
|
|
#include "xwayland-dmabuf.h"
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-12-20 12:15:15 +01:00
|
|
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
2022-10-17 17:58:01 +02:00
|
|
|
#include "tearing-control-v1-client-protocol.h"
|
2019-12-17 15:07:07 +01:00
|
|
|
#include "viewporter-client-protocol.h"
|
2020-02-22 17:25:15 +01:00
|
|
|
#include "xdg-shell-client-protocol.h"
|
2022-09-24 16:13:04 +00:00
|
|
|
#include "xwayland-shell-v1-client-protocol.h"
|
2023-11-27 14:40:25 +01:00
|
|
|
#include "fractional-scale-v1-client-protocol.h"
|
2023-08-15 15:32:47 -07:00
|
|
|
#include "linux-drm-syncobj-v1-client-protocol.h"
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-09-23 09:23:02 +02:00
|
|
|
#define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
|
|
|
|
|
|
2023-07-24 17:39:51 +02:00
|
|
|
#define MAX_ROOTFUL_WIDTH 32767
|
|
|
|
|
#define MAX_ROOTFUL_HEIGHT 32767
|
|
|
|
|
#define MIN_ROOTFUL_WIDTH 320
|
|
|
|
|
#define MIN_ROOTFUL_HEIGHT 200
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
#define FRACTIONAL_SCALE_DENOMINATOR 120
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
static DevPrivateKeyRec xwl_window_private_key;
|
|
|
|
|
static DevPrivateKeyRec xwl_damage_private_key;
|
2022-05-04 14:25:29 +02:00
|
|
|
static const char *xwl_surface_tag = "xwl-surface";
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2023-07-24 16:39:03 +02:00
|
|
|
static Bool xwl_window_attach_buffer(struct xwl_window *);
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
struct xwl_window *
|
|
|
|
|
xwl_window_get(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
return dixLookupPrivate(&window->devPrivates, &xwl_window_private_key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static DamagePtr
|
|
|
|
|
window_get_damage(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
return dixLookupPrivate(&window->devPrivates, &xwl_damage_private_key);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-19 16:39:13 +01:00
|
|
|
RegionPtr
|
|
|
|
|
xwl_window_get_damage_region(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
2023-12-22 19:00:42 +01:00
|
|
|
return DamageRegion(window_get_damage(xwl_window->surface_window));
|
2024-02-19 16:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
struct xwl_window *
|
|
|
|
|
xwl_window_from_window(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window;
|
|
|
|
|
|
|
|
|
|
while (window) {
|
|
|
|
|
xwl_window = xwl_window_get(window);
|
|
|
|
|
if (xwl_window)
|
|
|
|
|
return xwl_window;
|
|
|
|
|
|
|
|
|
|
window = window->parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-04 14:25:29 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_set_xwayland_tag(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
wl_proxy_set_tag((struct wl_proxy *)xwl_window->surface, &xwl_surface_tag);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 16:39:30 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_clear_xwayland_tag(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
wl_proxy_set_tag((struct wl_proxy *)xwl_window->surface, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-04 14:25:29 +02:00
|
|
|
Bool
|
|
|
|
|
is_surface_from_xwl_window(struct wl_surface *surface)
|
|
|
|
|
{
|
|
|
|
|
return wl_proxy_get_tag((struct wl_proxy *) surface) == &xwl_surface_tag;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-26 09:37:23 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
|
|
|
|
|
const char *debug_msg)
|
|
|
|
|
{
|
2023-03-31 16:01:20 +02:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
DamagePtr damage;
|
|
|
|
|
|
2023-04-26 09:37:23 +02:00
|
|
|
xwl_window->allow_commits = allow;
|
|
|
|
|
DebugF("XWAYLAND: win %d allow_commits = %d (%s)\n",
|
2023-12-22 16:54:40 +01:00
|
|
|
xwl_window->toplevel->drawable.id, allow, debug_msg);
|
2023-03-31 16:01:20 +02:00
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
damage = window_get_damage(xwl_window->surface_window);
|
2023-03-31 16:01:20 +02:00
|
|
|
if (allow &&
|
|
|
|
|
xorg_list_is_empty(&xwl_window->link_damage) &&
|
|
|
|
|
damage &&
|
|
|
|
|
RegionNotEmpty(DamageRegion(damage))) {
|
|
|
|
|
xorg_list_add(&xwl_window->link_damage,
|
|
|
|
|
&xwl_screen->damage_window_list);
|
|
|
|
|
}
|
2023-04-26 09:37:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_set_allow_commits_from_property(struct xwl_window *xwl_window,
|
|
|
|
|
PropertyPtr prop)
|
|
|
|
|
{
|
|
|
|
|
static Bool warned = FALSE;
|
|
|
|
|
CARD32 *propdata;
|
|
|
|
|
|
|
|
|
|
if (prop->propertyName != xwl_window->xwl_screen->allow_commits_prop)
|
|
|
|
|
FatalError("Xwayland internal error: prop mismatch in %s.\n", __func__);
|
|
|
|
|
|
|
|
|
|
if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) {
|
|
|
|
|
/* Not properly set, so fall back to safe and glitchy */
|
|
|
|
|
xwl_window_set_allow_commits(xwl_window, TRUE, "WM fault");
|
|
|
|
|
|
|
|
|
|
if (!warned) {
|
|
|
|
|
LogMessageVerb(X_WARNING, 0, "Window manager is misusing property %s.\n",
|
|
|
|
|
NameForAtom(prop->propertyName));
|
|
|
|
|
warned = TRUE;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
propdata = prop->data;
|
|
|
|
|
xwl_window_set_allow_commits(xwl_window, !!propdata[0], "from property");
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
void
|
|
|
|
|
xwl_window_update_property(struct xwl_window *xwl_window,
|
|
|
|
|
PropertyStateRec *propstate)
|
|
|
|
|
{
|
|
|
|
|
switch (propstate->state) {
|
|
|
|
|
case PropertyNewValue:
|
|
|
|
|
xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PropertyDelete:
|
|
|
|
|
xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-10 14:55:57 +01:00
|
|
|
static void
|
|
|
|
|
need_source_validate_dec(struct xwl_screen *xwl_screen)
|
|
|
|
|
{
|
|
|
|
|
xwl_screen->need_source_validate--;
|
|
|
|
|
|
|
|
|
|
if (!xwl_screen->need_source_validate)
|
|
|
|
|
xwl_screen->screen->SourceValidate = xwl_screen->SourceValidate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_source_validate(DrawablePtr drawable, int x, int y, int width, int height,
|
|
|
|
|
unsigned int sub_window_mode)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window;
|
|
|
|
|
WindowPtr window, iterator;
|
|
|
|
|
RegionRec region;
|
|
|
|
|
BoxRec box;
|
|
|
|
|
|
|
|
|
|
if (sub_window_mode != IncludeInferiors ||
|
|
|
|
|
drawable->type != DRAWABLE_WINDOW)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
window = (WindowPtr)drawable;
|
|
|
|
|
xwl_window = xwl_window_from_window(window);
|
|
|
|
|
if (!xwl_window || !xwl_window->surface_window_damage ||
|
|
|
|
|
!RegionNotEmpty(xwl_window->surface_window_damage))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (iterator = xwl_window->toplevel;
|
|
|
|
|
;
|
|
|
|
|
iterator = iterator->firstChild) {
|
|
|
|
|
if (iterator == xwl_window->surface_window)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (iterator == window)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
box.x1 = x;
|
|
|
|
|
box.y1 = y;
|
|
|
|
|
box.x2 = x + width;
|
|
|
|
|
box.y2 = y + height;
|
|
|
|
|
RegionInit(®ion, &box, 1);
|
|
|
|
|
RegionIntersect(®ion, ®ion, xwl_window->surface_window_damage);
|
|
|
|
|
|
|
|
|
|
if (RegionNotEmpty(®ion)) {
|
|
|
|
|
ScreenPtr screen = drawable->pScreen;
|
|
|
|
|
PixmapPtr dst_pix, src_pix;
|
|
|
|
|
BoxPtr pbox;
|
|
|
|
|
GCPtr pGC;
|
|
|
|
|
int nbox;
|
|
|
|
|
|
|
|
|
|
dst_pix = screen->GetWindowPixmap(window);
|
|
|
|
|
pGC = GetScratchGC(dst_pix->drawable.depth, screen);
|
|
|
|
|
if (!pGC)
|
|
|
|
|
FatalError("GetScratchGC failed for depth %d", dst_pix->drawable.depth);
|
|
|
|
|
ValidateGC(&dst_pix->drawable, pGC);
|
|
|
|
|
|
|
|
|
|
src_pix = screen->GetWindowPixmap(xwl_window->surface_window);
|
|
|
|
|
|
|
|
|
|
RegionSubtract(xwl_window->surface_window_damage,
|
|
|
|
|
xwl_window->surface_window_damage,
|
|
|
|
|
®ion);
|
|
|
|
|
|
|
|
|
|
if (!RegionNotEmpty(xwl_window->surface_window_damage))
|
|
|
|
|
need_source_validate_dec(xwl_window->xwl_screen);
|
|
|
|
|
|
|
|
|
|
#if defined(COMPOSITE)
|
|
|
|
|
if (dst_pix->screen_x || dst_pix->screen_y)
|
|
|
|
|
RegionTranslate(®ion, -dst_pix->screen_x, -dst_pix->screen_y);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
pbox = RegionRects(®ion);
|
|
|
|
|
nbox = RegionNumRects(®ion);
|
|
|
|
|
while (nbox--) {
|
|
|
|
|
(void) (*pGC->ops->CopyArea) (&src_pix->drawable,
|
|
|
|
|
&dst_pix->drawable,
|
|
|
|
|
pGC,
|
|
|
|
|
pbox->x1, pbox->y1,
|
|
|
|
|
pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
|
|
|
|
|
pbox->x1, pbox->y1);
|
2024-04-11 15:46:37 +02:00
|
|
|
pbox++;
|
2024-01-10 14:55:57 +01:00
|
|
|
}
|
|
|
|
|
FreeScratchGC(pGC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegionUninit(®ion);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
need_source_validate_inc(struct xwl_screen *xwl_screen)
|
|
|
|
|
{
|
|
|
|
|
if (!xwl_screen->need_source_validate) {
|
|
|
|
|
ScreenPtr screen = xwl_screen->screen;
|
|
|
|
|
|
|
|
|
|
xwl_screen->SourceValidate = screen->SourceValidate;
|
|
|
|
|
screen->SourceValidate = xwl_source_validate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xwl_screen->need_source_validate++;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
static void
|
|
|
|
|
damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
|
|
|
|
|
{
|
2024-02-08 18:18:06 +01:00
|
|
|
struct xwl_window *xwl_window = data;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2024-02-22 12:21:29 +01:00
|
|
|
PixmapPtr window_pixmap;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-01-10 14:55:57 +01:00
|
|
|
if (xwl_window->surface_window_damage &&
|
|
|
|
|
RegionNotEmpty(pRegion)) {
|
|
|
|
|
if (!RegionNotEmpty(xwl_window->surface_window_damage))
|
|
|
|
|
need_source_validate_inc(xwl_screen);
|
|
|
|
|
|
|
|
|
|
RegionUnion(xwl_window->surface_window_damage,
|
|
|
|
|
xwl_window->surface_window_damage,
|
|
|
|
|
DamageRegion(pDamage));
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-28 10:52:03 +01:00
|
|
|
if (xwl_screen->ignore_damage)
|
2019-12-17 15:07:07 +01:00
|
|
|
return;
|
|
|
|
|
|
2023-02-05 14:38:32 +07:00
|
|
|
if (xorg_list_is_empty(&xwl_window->link_damage))
|
|
|
|
|
xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list);
|
2024-02-22 12:21:29 +01:00
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->surface_window);
|
2024-02-22 12:21:29 +01:00
|
|
|
if (xwl_is_client_pixmap(window_pixmap))
|
2024-09-30 17:59:14 +02:00
|
|
|
dixDestroyPixmap(xwl_window_swap_pixmap(xwl_window, FALSE), 0);
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
damage_destroy(DamagePtr pDamage, void *data)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Bool
|
2024-02-08 18:18:06 +01:00
|
|
|
register_damage(struct xwl_window *xwl_window)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2023-12-22 19:00:42 +01:00
|
|
|
WindowPtr surface_window = xwl_window->surface_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
DamagePtr damage;
|
|
|
|
|
|
|
|
|
|
damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty,
|
2023-12-22 19:00:42 +01:00
|
|
|
FALSE, surface_window->drawable.pScreen, xwl_window);
|
2019-12-17 15:07:07 +01:00
|
|
|
if (damage == NULL) {
|
|
|
|
|
ErrorF("Failed creating damage\n");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
DamageRegister(&surface_window->drawable, damage);
|
|
|
|
|
dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, damage);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2024-02-08 18:18:06 +01:00
|
|
|
unregister_damage(struct xwl_window *xwl_window)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2023-12-22 19:00:42 +01:00
|
|
|
WindowPtr surface_window = xwl_window->surface_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
DamagePtr damage;
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
damage = dixLookupPrivate(&surface_window->devPrivates, &xwl_damage_private_key);
|
2019-12-17 15:07:07 +01:00
|
|
|
if (!damage)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
DamageUnregister(damage);
|
|
|
|
|
DamageDestroy(damage);
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, NULL);
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
static Bool
|
|
|
|
|
xwl_window_update_fractional_scale(struct xwl_window *xwl_window,
|
|
|
|
|
int fractional_scale_numerator)
|
|
|
|
|
{
|
|
|
|
|
int old_scale_numerator = xwl_window->fractional_scale_numerator;
|
|
|
|
|
|
|
|
|
|
xwl_window->fractional_scale_numerator = fractional_scale_numerator;
|
|
|
|
|
|
|
|
|
|
return (old_scale_numerator != fractional_scale_numerator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
xwl_window_get_fractional_scale_factor(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
return (double) xwl_window->fractional_scale_numerator /
|
|
|
|
|
(double) FRACTIONAL_SCALE_DENOMINATOR;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-27 15:05:42 +01:00
|
|
|
static Bool
|
2019-12-17 15:07:07 +01:00
|
|
|
xwl_window_has_viewport_enabled(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
return (xwl_window->viewport != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_disable_viewport(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
assert (xwl_window->viewport);
|
|
|
|
|
|
|
|
|
|
DebugF("XWAYLAND: disabling viewport\n");
|
|
|
|
|
wp_viewport_destroy(xwl_window->viewport);
|
|
|
|
|
xwl_window->viewport = NULL;
|
2023-11-27 15:02:08 +01:00
|
|
|
xwl_window->viewport_scale_x = 1.0;
|
|
|
|
|
xwl_window->viewport_scale_y = 1.0;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
/* Enable the viewport for fractional scale support with Xwayland rootful.
|
|
|
|
|
* Fractional scale support is not used with Xwayland rootful fullscreen (which
|
|
|
|
|
* sets its own XRandR resolution) so we can use the viewport for either
|
|
|
|
|
* fullscreen mode or fractional scale.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_enable_viewport_for_fractional_scale(struct xwl_window *xwl_window,
|
|
|
|
|
int width, int height)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
int buffer_width, buffer_height;
|
|
|
|
|
double scale;
|
|
|
|
|
|
|
|
|
|
scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
buffer_width = round((double) width / scale);
|
|
|
|
|
buffer_height = round((double) height / scale);
|
|
|
|
|
|
|
|
|
|
if (!xwl_window_has_viewport_enabled(xwl_window))
|
|
|
|
|
xwl_window->viewport = wp_viewporter_get_viewport(xwl_screen->viewporter,
|
|
|
|
|
xwl_window->surface);
|
|
|
|
|
|
|
|
|
|
DebugF("XWAYLAND: enabling viewport for fractional scale %dx%d -> %dx%d\n",
|
|
|
|
|
width, height, buffer_width, buffer_height);
|
|
|
|
|
wp_viewport_set_source(xwl_window->viewport,
|
|
|
|
|
wl_fixed_from_int(0),
|
|
|
|
|
wl_fixed_from_int(0),
|
|
|
|
|
wl_fixed_from_int(width),
|
|
|
|
|
wl_fixed_from_int(height));
|
|
|
|
|
wp_viewport_set_destination(xwl_window->viewport,
|
|
|
|
|
buffer_width,
|
|
|
|
|
buffer_height);
|
|
|
|
|
|
|
|
|
|
xwl_window->viewport_scale_x = scale;
|
|
|
|
|
xwl_window->viewport_scale_y = scale;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-22 11:06:59 +01:00
|
|
|
/* Enable the viewport for Xwayland rootful fullscreen, to match the XRandR
|
|
|
|
|
* resolution with the actual output size.
|
|
|
|
|
*/
|
2019-12-17 15:07:07 +01:00
|
|
|
static void
|
2023-11-22 11:06:59 +01:00
|
|
|
xwl_window_enable_viewport_for_output(struct xwl_window *xwl_window,
|
|
|
|
|
struct xwl_output *xwl_output,
|
|
|
|
|
struct xwl_emulated_mode *emulated_mode)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2023-11-02 10:25:46 +01:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
int width, height;
|
|
|
|
|
|
2020-01-03 17:12:14 +01:00
|
|
|
if (!xwl_window_has_viewport_enabled(xwl_window)) {
|
|
|
|
|
DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n",
|
|
|
|
|
emulated_mode->width, emulated_mode->height,
|
|
|
|
|
xwl_output->width, xwl_output->height);
|
|
|
|
|
xwl_window->viewport = wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter,
|
|
|
|
|
xwl_window->surface);
|
|
|
|
|
}
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2023-11-02 10:25:46 +01:00
|
|
|
width = emulated_mode->width / xwl_screen->global_surface_scale;
|
|
|
|
|
height = emulated_mode->height / xwl_screen->global_surface_scale;
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
wp_viewport_set_source(xwl_window->viewport,
|
|
|
|
|
wl_fixed_from_int(0),
|
|
|
|
|
wl_fixed_from_int(0),
|
2023-11-02 10:25:46 +01:00
|
|
|
wl_fixed_from_int(width),
|
|
|
|
|
wl_fixed_from_int(height));
|
2019-12-17 15:07:07 +01:00
|
|
|
wp_viewport_set_destination(xwl_window->viewport,
|
|
|
|
|
xwl_output->width,
|
|
|
|
|
xwl_output->height);
|
|
|
|
|
|
2023-11-28 14:45:55 +01:00
|
|
|
xwl_window->viewport_scale_x = (float) width / xwl_output->width;
|
|
|
|
|
xwl_window->viewport_scale_y = (float) height / xwl_output->height;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Bool
|
2020-01-27 11:08:00 +01:00
|
|
|
window_is_wm_window(WindowPtr window)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2020-01-27 11:08:00 +01:00
|
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2020-01-27 11:08:00 +01:00
|
|
|
return CLIENT_ID(window->drawable.id) == xwl_screen->wm_client_id;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-15 10:07:58 +01:00
|
|
|
static WindowPtr
|
|
|
|
|
window_get_client_toplevel(WindowPtr window)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2020-01-15 10:07:58 +01:00
|
|
|
assert(window);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
/* If the toplevel window is owned by the window-manager, then the
|
2020-01-03 17:27:28 +01:00
|
|
|
* actual client toplevel window has been reparented to some window-manager
|
|
|
|
|
* decoration/wrapper windows. In that case recurse by checking the client
|
|
|
|
|
* of the first *and only* child of the decoration/wrapper window.
|
2019-12-17 15:07:07 +01:00
|
|
|
*/
|
2020-11-06 10:14:19 +01:00
|
|
|
while (window_is_wm_window(window)) {
|
|
|
|
|
if (!window->firstChild || window->firstChild != window->lastChild)
|
2019-12-17 15:07:07 +01:00
|
|
|
return NULL; /* Should never happen, skip resolution emulation */
|
2020-11-06 10:14:19 +01:00
|
|
|
|
|
|
|
|
window = window->firstChild;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-15 10:07:58 +01:00
|
|
|
return window;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
xwayland: Make sure output is suitable for fullscreen
Since commit d370f1e58, Xwayland can optionally be started rootful and
fullscreen.
To do so, it will setup a viewport to scale the root window to match the
size of the output.
However, if the rootful Xwayland window receives an xdg-surface configure
event before the output definition is complete, as with e.g. the labwc
Wayland compositor, we might end up trying to setup a viewport with a
destination size of 0x0 which is a protocol violation, and that kills
Xwayland.
To avoid that issue, only setup the viewport if the output size is
meaningful.
Also, please note that once the output definition is complete, i.e. when
the "done" event is eventually received, we shall recompute the size for
fullscreen again, hence achieving the desired fullscreen state.
Fixes: d370f1e58 - xwayland: add fullscreen mode for rootful
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1717
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1621>
2024-07-24 15:19:41 +02:00
|
|
|
static Bool
|
|
|
|
|
is_output_suitable_for_fullscreen(struct xwl_output *xwl_output)
|
|
|
|
|
{
|
|
|
|
|
if (xwl_output == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (xwl_output->width == 0 || xwl_output->height == 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 12:04:29 +02:00
|
|
|
static struct xwl_output *
|
|
|
|
|
xwl_window_get_output(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
struct xwl_output *xwl_output;
|
|
|
|
|
|
2023-12-04 16:28:31 +01:00
|
|
|
xwl_output = xwl_output_get_output_from_name(xwl_screen, xwl_screen->output_name);
|
xwayland: Make sure output is suitable for fullscreen
Since commit d370f1e58, Xwayland can optionally be started rootful and
fullscreen.
To do so, it will setup a viewport to scale the root window to match the
size of the output.
However, if the rootful Xwayland window receives an xdg-surface configure
event before the output definition is complete, as with e.g. the labwc
Wayland compositor, we might end up trying to setup a viewport with a
destination size of 0x0 which is a protocol violation, and that kills
Xwayland.
To avoid that issue, only setup the viewport if the output size is
meaningful.
Also, please note that once the output definition is complete, i.e. when
the "done" event is eventually received, we shall recompute the size for
fullscreen again, hence achieving the desired fullscreen state.
Fixes: d370f1e58 - xwayland: add fullscreen mode for rootful
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1717
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1621>
2024-07-24 15:19:41 +02:00
|
|
|
if (is_output_suitable_for_fullscreen(xwl_output))
|
2023-12-04 16:28:31 +01:00
|
|
|
return xwl_output;
|
2022-05-12 12:04:29 +02:00
|
|
|
|
2023-12-04 16:28:31 +01:00
|
|
|
xwl_output = xwl_output_from_wl_output(xwl_screen, xwl_window->wl_output);
|
xwayland: Make sure output is suitable for fullscreen
Since commit d370f1e58, Xwayland can optionally be started rootful and
fullscreen.
To do so, it will setup a viewport to scale the root window to match the
size of the output.
However, if the rootful Xwayland window receives an xdg-surface configure
event before the output definition is complete, as with e.g. the labwc
Wayland compositor, we might end up trying to setup a viewport with a
destination size of 0x0 which is a protocol violation, and that kills
Xwayland.
To avoid that issue, only setup the viewport if the output size is
meaningful.
Also, please note that once the output definition is complete, i.e. when
the "done" event is eventually received, we shall recompute the size for
fullscreen again, hence achieving the desired fullscreen state.
Fixes: d370f1e58 - xwayland: add fullscreen mode for rootful
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1717
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1621>
2024-07-24 15:19:41 +02:00
|
|
|
if (is_output_suitable_for_fullscreen(xwl_output))
|
2022-05-12 12:04:29 +02:00
|
|
|
return xwl_output;
|
|
|
|
|
|
|
|
|
|
return xwl_screen_get_first_output(xwl_screen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
|
xwl_window_should_enable_viewport_fullscreen(struct xwl_window *xwl_window,
|
|
|
|
|
struct xwl_output **xwl_output_ret,
|
|
|
|
|
struct xwl_emulated_mode *emulated_mode_ret)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
struct xwl_output *xwl_output;
|
|
|
|
|
|
|
|
|
|
xwl_output = xwl_window_get_output(xwl_window);
|
|
|
|
|
if (!xwl_output)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
*xwl_output_ret = xwl_output;
|
|
|
|
|
emulated_mode_ret->server_output_id = 0;
|
2024-02-06 14:51:56 +01:00
|
|
|
emulated_mode_ret->width = xwl_screen_get_width(xwl_screen);
|
|
|
|
|
emulated_mode_ret->height = xwl_screen_get_height(xwl_screen);
|
2022-05-12 12:04:29 +02:00
|
|
|
emulated_mode_ret->from_vidmode = FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
static Bool
|
|
|
|
|
xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
|
|
|
|
|
struct xwl_output **xwl_output_ret,
|
2022-05-12 16:02:09 +02:00
|
|
|
struct xwl_emulated_mode *emulated_mode_ret)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
struct xwl_emulated_mode *emulated_mode;
|
|
|
|
|
struct xwl_output *xwl_output;
|
|
|
|
|
ClientPtr owner;
|
2020-01-15 10:07:58 +01:00
|
|
|
WindowPtr window;
|
2020-01-03 17:55:28 +01:00
|
|
|
DrawablePtr drawable;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-05-12 12:04:29 +02:00
|
|
|
if (!xwl_screen_has_viewport_support(xwl_screen))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (xwl_screen->fullscreen)
|
|
|
|
|
return xwl_window_should_enable_viewport_fullscreen(xwl_window,
|
|
|
|
|
xwl_output_ret,
|
|
|
|
|
emulated_mode_ret);
|
|
|
|
|
|
|
|
|
|
if (!xwl_screen->rootless)
|
2019-12-17 15:07:07 +01:00
|
|
|
return FALSE;
|
|
|
|
|
|
2023-12-22 16:54:40 +01:00
|
|
|
window = window_get_client_toplevel(xwl_window->toplevel);
|
2020-01-15 10:07:58 +01:00
|
|
|
if (!window)
|
2019-12-17 15:07:07 +01:00
|
|
|
return FALSE;
|
|
|
|
|
|
2020-01-15 10:07:58 +01:00
|
|
|
owner = wClient(window);
|
2020-01-03 17:55:28 +01:00
|
|
|
drawable = &window->drawable;
|
2020-01-15 10:07:58 +01:00
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
/* 1. Test if the window matches the emulated mode on one of the outputs
|
|
|
|
|
* This path gets hit by most games / libs (e.g. SDL, SFML, OGRE)
|
|
|
|
|
*/
|
|
|
|
|
xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) {
|
|
|
|
|
emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner);
|
|
|
|
|
if (!emulated_mode)
|
|
|
|
|
continue;
|
|
|
|
|
|
2020-01-03 17:55:28 +01:00
|
|
|
if (drawable->x == xwl_output->x &&
|
|
|
|
|
drawable->y == xwl_output->y &&
|
|
|
|
|
drawable->width == emulated_mode->width &&
|
|
|
|
|
drawable->height == emulated_mode->height) {
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-05-12 16:02:09 +02:00
|
|
|
memcpy(emulated_mode_ret, emulated_mode, sizeof(struct xwl_emulated_mode));
|
2019-12-17 15:07:07 +01:00
|
|
|
*xwl_output_ret = xwl_output;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 2. Test if the window uses override-redirect + vidmode
|
|
|
|
|
* and matches (fully covers) the entire screen.
|
|
|
|
|
* This path gets hit by: allegro4, ClanLib-1.0.
|
|
|
|
|
*/
|
|
|
|
|
xwl_output = xwl_screen_get_first_output(xwl_screen);
|
|
|
|
|
emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner);
|
2023-12-22 16:54:40 +01:00
|
|
|
if (xwl_output && xwl_window->toplevel->overrideRedirect &&
|
2019-12-17 15:07:07 +01:00
|
|
|
emulated_mode && emulated_mode->from_vidmode &&
|
2020-01-03 17:55:28 +01:00
|
|
|
drawable->x == 0 && drawable->y == 0 &&
|
2024-02-06 14:51:56 +01:00
|
|
|
drawable->width == xwl_screen_get_width(xwl_screen) &&
|
|
|
|
|
drawable->height == xwl_screen_get_height(xwl_screen)) {
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-05-12 16:02:09 +02:00
|
|
|
memcpy(emulated_mode_ret, emulated_mode, sizeof(struct xwl_emulated_mode));
|
2019-12-17 15:07:07 +01:00
|
|
|
*xwl_output_ret = xwl_output;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
static Bool
|
|
|
|
|
xwl_window_should_enable_fractional_scale_viewport(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
double scale;
|
|
|
|
|
|
|
|
|
|
if (!xwl_screen_should_use_fractional_scale(xwl_screen))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
|
|
|
|
|
return fabs(scale - 1.00) > FLT_EPSILON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_check_fractional_scale_viewport(struct xwl_window *xwl_window,
|
|
|
|
|
int width, int height)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
|
|
|
|
|
if (!xwl_screen_should_use_fractional_scale(xwl_screen))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (xwl_window_should_enable_fractional_scale_viewport(xwl_window))
|
|
|
|
|
xwl_window_enable_viewport_for_fractional_scale(xwl_window, width, height);
|
|
|
|
|
else if (xwl_window_has_viewport_enabled(xwl_window))
|
|
|
|
|
xwl_window_disable_viewport(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
void
|
|
|
|
|
xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
2022-05-12 16:02:09 +02:00
|
|
|
struct xwl_emulated_mode emulated_mode;
|
2019-12-17 15:07:07 +01:00
|
|
|
struct xwl_output *xwl_output;
|
|
|
|
|
|
|
|
|
|
if (xwl_window_should_enable_viewport(xwl_window, &xwl_output, &emulated_mode))
|
2023-11-22 11:06:59 +01:00
|
|
|
xwl_window_enable_viewport_for_output(xwl_window, xwl_output, &emulated_mode);
|
2023-11-27 14:40:25 +01:00
|
|
|
else if (xwl_window_should_enable_fractional_scale_viewport(xwl_window))
|
|
|
|
|
return;
|
2019-12-17 15:07:07 +01:00
|
|
|
else if (xwl_window_has_viewport_enabled(xwl_window))
|
|
|
|
|
xwl_window_disable_viewport(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This checks if the passed in Window is a toplevel client window, note this
|
|
|
|
|
* returns false for window-manager decoration windows and returns true for
|
|
|
|
|
* the actual client top-level window even if it has been reparented to
|
|
|
|
|
* a window-manager decoration window.
|
|
|
|
|
*/
|
|
|
|
|
Bool
|
|
|
|
|
xwl_window_is_toplevel(WindowPtr window)
|
|
|
|
|
{
|
2023-12-22 19:00:42 +01:00
|
|
|
if (!window->parent || window_is_wm_window(window))
|
2019-12-17 15:07:07 +01:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* CSD and override-redirect toplevel windows */
|
2023-12-22 19:00:42 +01:00
|
|
|
if (!window->parent->parent)
|
2019-12-17 15:07:07 +01:00
|
|
|
return TRUE;
|
|
|
|
|
|
2020-01-03 17:27:28 +01:00
|
|
|
/* Normal toplevel client windows, reparented to a window-manager window */
|
2023-12-22 19:00:42 +01:00
|
|
|
return window_is_wm_window(window->parent);
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_init_allow_commits(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
PropertyPtr prop = NULL;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2023-12-22 16:54:40 +01:00
|
|
|
ret = dixLookupProperty(&prop, xwl_window->toplevel,
|
2019-12-17 15:07:07 +01:00
|
|
|
xwl_window->xwl_screen->allow_commits_prop,
|
|
|
|
|
serverClient, DixReadAccess);
|
|
|
|
|
if (ret == Success && prop)
|
|
|
|
|
xwl_window_set_allow_commits_from_property(xwl_window, prop);
|
|
|
|
|
else
|
|
|
|
|
xwl_window_set_allow_commits(xwl_window, TRUE, "no property");
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-24 16:13:04 +00:00
|
|
|
static uint32_t
|
|
|
|
|
serial_lo(uint64_t value)
|
|
|
|
|
{
|
|
|
|
|
return value & 0xFFFFFFFFu;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
|
serial_hi(uint64_t value)
|
|
|
|
|
{
|
|
|
|
|
return value >> 32u;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
static void
|
2022-09-24 16:13:04 +00:00
|
|
|
send_window_client_message(struct xwl_window *xwl_window, Atom type_atom, uint64_t value)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
|
|
|
|
DeviceIntPtr dev;
|
|
|
|
|
xEvent e;
|
|
|
|
|
|
|
|
|
|
e.u.u.type = ClientMessage;
|
|
|
|
|
e.u.u.detail = 32;
|
2023-12-22 16:54:40 +01:00
|
|
|
e.u.clientMessage.window = xwl_window->toplevel->drawable.id;
|
2019-12-17 15:07:07 +01:00
|
|
|
e.u.clientMessage.u.l.type = type_atom;
|
2022-09-24 16:13:04 +00:00
|
|
|
e.u.clientMessage.u.l.longs0 = serial_lo(value);
|
|
|
|
|
e.u.clientMessage.u.l.longs1 = serial_hi(value);
|
2019-12-17 15:07:07 +01:00
|
|
|
e.u.clientMessage.u.l.longs2 = 0;
|
|
|
|
|
e.u.clientMessage.u.l.longs3 = 0;
|
|
|
|
|
e.u.clientMessage.u.l.longs4 = 0;
|
|
|
|
|
|
|
|
|
|
dev = PickPointer(serverClient);
|
|
|
|
|
DeliverEventsToWindow(dev, xwl_window->xwl_screen->screen->root,
|
|
|
|
|
&e, 1, SubstructureRedirectMask, NullGrab);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-24 16:13:04 +00:00
|
|
|
static void
|
|
|
|
|
send_surface_id_event_serial(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
static const char atom_name[] = "WL_SURFACE_SERIAL";
|
|
|
|
|
static Atom type_atom;
|
|
|
|
|
uint64_t serial;
|
|
|
|
|
|
|
|
|
|
if (type_atom == None)
|
|
|
|
|
type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
|
|
|
|
|
|
|
|
|
|
serial = ++xwl_window->xwl_screen->surface_association_serial;
|
|
|
|
|
|
|
|
|
|
send_window_client_message(xwl_window, type_atom, serial);
|
|
|
|
|
xwayland_surface_v1_set_serial(xwl_window->xwayland_surface,
|
|
|
|
|
serial_lo(serial), serial_hi(serial));
|
|
|
|
|
wl_surface_commit(xwl_window->surface);
|
|
|
|
|
|
|
|
|
|
/* Flush wayland display *after* commit in the new path. */
|
|
|
|
|
wl_display_flush(xwl_window->xwl_screen->display);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
send_surface_id_event_legacy(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
static const char atom_name[] = "WL_SURFACE_ID";
|
|
|
|
|
static Atom type_atom;
|
|
|
|
|
uint32_t surface_id;
|
|
|
|
|
|
|
|
|
|
if (type_atom == None)
|
|
|
|
|
type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
|
|
|
|
|
|
|
|
|
|
surface_id = wl_proxy_get_id((struct wl_proxy *) xwl_window->surface);
|
|
|
|
|
|
|
|
|
|
/* Flush wayland display *before* setting the atom in the legacy path */
|
|
|
|
|
wl_display_flush(xwl_window->xwl_screen->display);
|
|
|
|
|
|
|
|
|
|
send_window_client_message(xwl_window, type_atom, (uint64_t)surface_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
send_surface_id_event(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
return xwl_window->xwayland_surface
|
|
|
|
|
? send_surface_id_event_serial(xwl_window)
|
|
|
|
|
: send_surface_id_event_legacy(xwl_window);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 12:04:29 +02:00
|
|
|
static Bool
|
|
|
|
|
xwl_window_set_fullscreen(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_output *xwl_output;
|
|
|
|
|
struct wl_output *wl_output = NULL;
|
|
|
|
|
|
|
|
|
|
if (!xwl_window->xdg_toplevel)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
xwl_output = xwl_window_get_output(xwl_window);
|
|
|
|
|
if (xwl_output)
|
|
|
|
|
wl_output = xwl_output->output;
|
|
|
|
|
|
|
|
|
|
if (wl_output && xwl_window->wl_output_fullscreen == wl_output)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
xdg_toplevel_set_fullscreen(xwl_window->xdg_toplevel, wl_output);
|
|
|
|
|
xwl_window_check_resolution_change_emulation(xwl_window);
|
|
|
|
|
wl_surface_commit(xwl_window->surface);
|
|
|
|
|
|
|
|
|
|
xwl_window->wl_output_fullscreen = wl_output;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 09:08:57 +01:00
|
|
|
void
|
|
|
|
|
xwl_window_rootful_update_fullscreen(struct xwl_window *xwl_window,
|
|
|
|
|
struct xwl_output *xwl_output)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
|
|
|
|
|
if (!xwl_screen->fullscreen)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-12-22 16:54:40 +01:00
|
|
|
if (xwl_window->toplevel != xwl_screen->screen->root)
|
2023-11-10 09:08:57 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (xwl_window->wl_output_fullscreen != xwl_output->output)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* The size and position of the output may have changed, clear our
|
|
|
|
|
* output to make sure the next call to xwl_window_set_fullscreen()
|
|
|
|
|
* recomputes the size and updates the viewport as needed.
|
|
|
|
|
*/
|
|
|
|
|
xwl_window->wl_output_fullscreen = NULL;
|
|
|
|
|
xwl_window_set_fullscreen(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 15:51:55 +02:00
|
|
|
void
|
|
|
|
|
xwl_window_rootful_update_title(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
char title[128];
|
|
|
|
|
const char *grab_message = "";
|
|
|
|
|
|
|
|
|
|
if (xwl_screen->host_grab) {
|
|
|
|
|
if (xwl_screen->has_grab)
|
|
|
|
|
grab_message = " - ([ctrl]+[shift] releases mouse and keyboard)";
|
|
|
|
|
else
|
|
|
|
|
grab_message = " - ([ctrl]+[shift] grabs mouse and keyboard)";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(title, sizeof(title), "Xwayland on :%s%s", display, grab_message);
|
|
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
|
|
|
|
if (xwl_window->libdecor_frame)
|
|
|
|
|
libdecor_frame_set_title(xwl_window->libdecor_frame, title);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
2022-04-28 15:51:55 +02:00
|
|
|
if (xwl_window->xdg_toplevel)
|
|
|
|
|
xdg_toplevel_set_title(xwl_window->xdg_toplevel, title);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-29 10:22:15 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_rootful_set_app_id(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
const char *app_id = "org.freedesktop.Xwayland";
|
|
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
|
|
|
|
if (xwl_window->libdecor_frame)
|
|
|
|
|
libdecor_frame_set_app_id(xwl_window->libdecor_frame, app_id);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
2022-04-29 10:22:15 +02:00
|
|
|
if (xwl_window->xdg_toplevel)
|
|
|
|
|
xdg_toplevel_set_app_id(xwl_window->xdg_toplevel, app_id);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-11 17:18:08 +02:00
|
|
|
static void
|
2024-02-06 14:51:56 +01:00
|
|
|
xwl_window_maybe_resize(struct xwl_window *xwl_window, double width, double height)
|
2023-08-11 17:18:08 +02:00
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
struct xwl_output *xwl_output;
|
2023-11-02 10:25:46 +01:00
|
|
|
double scale;
|
2023-08-11 17:18:08 +02:00
|
|
|
RRModePtr mode;
|
|
|
|
|
|
|
|
|
|
/* Clamp the size */
|
|
|
|
|
width = min(max(width, MIN_ROOTFUL_WIDTH), MAX_ROOTFUL_WIDTH);
|
|
|
|
|
height = min(max(height, MIN_ROOTFUL_HEIGHT), MAX_ROOTFUL_HEIGHT);
|
|
|
|
|
|
2023-11-02 10:25:46 +01:00
|
|
|
/* Make sure the size is a multiple of the scale, it's a protocol error otherwise. */
|
|
|
|
|
scale = xwl_screen->global_surface_scale;
|
|
|
|
|
if (scale > 1.0) {
|
|
|
|
|
width = round(width / scale) * scale;
|
|
|
|
|
height = round(height / scale) * scale;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-11 17:18:08 +02:00
|
|
|
if (width == xwl_screen->width && height == xwl_screen->height)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-02-06 14:51:56 +01:00
|
|
|
xwl_screen->width = width;
|
|
|
|
|
xwl_screen->height = height;
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
/* When fractional scale is used, the global surface scale is 1, and vice
|
|
|
|
|
* versa, so we can multiply the two here, and have the resulting scale
|
|
|
|
|
* apply for both cases, the legacy wl_surface buffer scale and fractional
|
|
|
|
|
* scaling.
|
|
|
|
|
*/
|
|
|
|
|
scale *= xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
|
2023-08-11 17:18:08 +02:00
|
|
|
xwl_output = xwl_screen_get_fixed_or_first_output(xwl_screen);
|
2023-11-02 11:04:18 +01:00
|
|
|
if (!xwl_randr_add_modes_fixed(xwl_output, round(width / scale), round(height / scale)))
|
2023-08-11 17:18:08 +02:00
|
|
|
return;
|
|
|
|
|
|
2023-11-02 11:04:18 +01:00
|
|
|
mode = xwl_output_find_mode(xwl_output, round(width / scale), round(height / scale));
|
2023-08-11 17:18:08 +02:00
|
|
|
xwl_output_set_mode_fixed(xwl_output, mode);
|
|
|
|
|
|
|
|
|
|
xwl_window_attach_buffer(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
2023-07-24 17:39:51 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_libdecor_set_size_limits(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
2023-11-02 10:25:46 +01:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
|
2023-07-24 17:39:51 +02:00
|
|
|
libdecor_frame_set_min_content_size(xwl_window->libdecor_frame,
|
2023-11-02 10:25:46 +01:00
|
|
|
MIN_ROOTFUL_WIDTH /
|
|
|
|
|
xwl_screen->global_surface_scale,
|
|
|
|
|
MIN_ROOTFUL_HEIGHT /
|
|
|
|
|
xwl_screen->global_surface_scale);
|
2023-07-24 17:39:51 +02:00
|
|
|
libdecor_frame_set_max_content_size(xwl_window->libdecor_frame,
|
2023-11-02 10:25:46 +01:00
|
|
|
MAX_ROOTFUL_WIDTH /
|
|
|
|
|
xwl_screen->global_surface_scale,
|
|
|
|
|
MAX_ROOTFUL_HEIGHT /
|
|
|
|
|
xwl_screen->global_surface_scale);
|
2023-07-24 17:39:51 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
static void
|
2023-07-26 09:34:18 +02:00
|
|
|
xwl_window_update_libdecor_size(struct xwl_window *xwl_window,
|
|
|
|
|
struct libdecor_configuration *configuration /* nullable */,
|
|
|
|
|
int width, int height)
|
2022-05-04 14:42:41 +02:00
|
|
|
{
|
|
|
|
|
struct libdecor_state *state;
|
2023-11-27 14:40:25 +01:00
|
|
|
double scale;
|
2022-05-04 14:42:41 +02:00
|
|
|
|
|
|
|
|
if (xwl_window->libdecor_frame) {
|
2023-11-27 14:40:25 +01:00
|
|
|
scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
state = libdecor_state_new(round((double) width / scale),
|
|
|
|
|
round((double) height / scale));
|
2023-07-26 09:34:18 +02:00
|
|
|
libdecor_frame_commit(xwl_window->libdecor_frame, state, configuration);
|
2022-05-04 14:42:41 +02:00
|
|
|
libdecor_state_free(state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_libdecor_configure(struct libdecor_frame *frame,
|
|
|
|
|
struct libdecor_configuration *configuration,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window = data;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2023-07-13 17:07:18 +02:00
|
|
|
int width, height;
|
2024-02-06 14:51:56 +01:00
|
|
|
double new_width, new_height;
|
2023-11-27 14:40:25 +01:00
|
|
|
double scale;
|
2022-05-04 14:42:41 +02:00
|
|
|
|
2024-02-06 14:51:56 +01:00
|
|
|
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
|
|
|
|
|
new_width = (double) width;
|
|
|
|
|
new_height = (double) height;
|
2023-07-13 17:07:18 +02:00
|
|
|
}
|
2023-11-02 10:25:46 +01:00
|
|
|
else {
|
|
|
|
|
new_width = xwl_screen->width / xwl_screen->global_surface_scale;
|
|
|
|
|
new_height = xwl_screen->height / xwl_screen->global_surface_scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_width *= xwl_screen->global_surface_scale;
|
|
|
|
|
new_height *= xwl_screen->global_surface_scale;
|
2023-02-01 11:33:30 +01:00
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
new_width *= scale;
|
|
|
|
|
new_height *= scale;
|
|
|
|
|
|
2024-02-06 14:51:56 +01:00
|
|
|
xwl_window_maybe_resize(xwl_window, new_width, new_height);
|
2023-11-02 10:25:46 +01:00
|
|
|
|
|
|
|
|
new_width = xwl_screen->width / xwl_screen->global_surface_scale;
|
|
|
|
|
new_height = xwl_screen->height / xwl_screen->global_surface_scale;
|
|
|
|
|
|
2023-07-26 09:36:17 +02:00
|
|
|
xwl_window_update_libdecor_size(xwl_window, configuration,
|
2023-11-02 10:25:46 +01:00
|
|
|
round(new_width), round(new_height));
|
2023-08-10 13:31:17 +02:00
|
|
|
wl_surface_commit(xwl_window->surface);
|
2022-05-04 14:42:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_libdecor_close(struct libdecor_frame *frame,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
DebugF("Terminating on compositor request");
|
|
|
|
|
GiveUp(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_libdecor_commit(struct libdecor_frame *frame,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window = data;
|
|
|
|
|
wl_surface_commit(xwl_window->surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_libdecor_dismiss_popup(struct libdecor_frame *frame,
|
|
|
|
|
const char *seat_name,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct libdecor_frame_interface libdecor_frame_iface = {
|
|
|
|
|
handle_libdecor_configure,
|
|
|
|
|
handle_libdecor_close,
|
|
|
|
|
handle_libdecor_commit,
|
|
|
|
|
handle_libdecor_dismiss_popup,
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
static void
|
2020-02-22 17:25:15 +01:00
|
|
|
xdg_surface_handle_configure(void *data,
|
|
|
|
|
struct xdg_surface *xdg_surface,
|
|
|
|
|
uint32_t serial)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2022-05-12 12:04:29 +02:00
|
|
|
struct xwl_window *xwl_window = data;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
|
|
|
|
|
if (xwl_screen->fullscreen)
|
|
|
|
|
xwl_window_set_fullscreen(xwl_window);
|
|
|
|
|
|
2020-02-22 17:25:15 +01:00
|
|
|
xdg_surface_ack_configure(xdg_surface, serial);
|
2022-05-12 12:04:29 +02:00
|
|
|
wl_surface_commit(xwl_window->surface);
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-22 17:25:15 +01:00
|
|
|
static const struct xdg_surface_listener xdg_surface_listener = {
|
|
|
|
|
xdg_surface_handle_configure,
|
2019-12-17 15:07:07 +01:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 11:05:55 +01:00
|
|
|
static void
|
|
|
|
|
xwl_window_update_surface_scale(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
2023-11-02 11:04:18 +01:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
int previous_scale, new_scale;
|
|
|
|
|
double new_width, new_height;
|
|
|
|
|
|
|
|
|
|
previous_scale = xwl_screen->global_surface_scale;
|
|
|
|
|
assert(previous_scale != 0);
|
2023-11-02 11:05:55 +01:00
|
|
|
xwl_window->surface_scale = xwl_window_get_max_output_scale(xwl_window);
|
2023-11-02 11:04:18 +01:00
|
|
|
|
|
|
|
|
if (xwl_screen_update_global_surface_scale(xwl_screen)) {
|
|
|
|
|
new_scale = xwl_screen->global_surface_scale;
|
|
|
|
|
|
|
|
|
|
DebugF("XWAYLAND: Global scale is now %i (was %i)\n",
|
|
|
|
|
new_scale, previous_scale);
|
|
|
|
|
|
|
|
|
|
new_width = xwl_screen->width / previous_scale * new_scale;
|
|
|
|
|
new_height = xwl_screen->height / previous_scale * new_scale;
|
|
|
|
|
|
|
|
|
|
wl_surface_set_buffer_scale(xwl_window->surface, xwl_screen->global_surface_scale);
|
|
|
|
|
/* Reflect the scale factor using XRandR transform */
|
|
|
|
|
xwl_output_set_xscale(xwl_screen->fixed_output, new_scale);
|
|
|
|
|
xwl_window_maybe_resize(xwl_window, new_width, new_height);
|
|
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
|
|
|
|
if (xwl_window->libdecor_frame) {
|
|
|
|
|
xwl_window_libdecor_set_size_limits(xwl_window);
|
|
|
|
|
xwl_window_update_libdecor_size(xwl_window,
|
|
|
|
|
NULL,
|
|
|
|
|
round(new_width / new_scale),
|
|
|
|
|
round(new_height / new_scale));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
wl_surface_commit(xwl_window->surface);
|
|
|
|
|
}
|
2023-11-02 11:05:55 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-02 10:37:15 +01:00
|
|
|
static void
|
|
|
|
|
xwl_window_enter_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window_output *window_output;
|
|
|
|
|
|
2024-05-10 10:47:12 +02:00
|
|
|
window_output = XNFcallocarray(1, sizeof(struct xwl_window_output));
|
2023-11-02 10:37:15 +01:00
|
|
|
window_output->xwl_output = xwl_output;
|
|
|
|
|
xorg_list_add(&window_output->link, &xwl_window->xwl_output_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xwl_window_leave_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window_output *window_output, *tmp;
|
|
|
|
|
|
|
|
|
|
xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) {
|
|
|
|
|
if (window_output->xwl_output == xwl_output) {
|
|
|
|
|
xorg_list_del(&window_output->link);
|
|
|
|
|
free(window_output);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_free_outputs(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window_output *window_output, *tmp;
|
|
|
|
|
|
|
|
|
|
xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) {
|
|
|
|
|
xorg_list_del(&window_output->link);
|
|
|
|
|
free(window_output);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-02 11:05:55 +01:00
|
|
|
int
|
|
|
|
|
xwl_window_get_max_output_scale(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window_output *window_output;
|
|
|
|
|
struct xwl_output *xwl_output;
|
|
|
|
|
int scale = 1;
|
|
|
|
|
|
|
|
|
|
xorg_list_for_each_entry(window_output, &xwl_window->xwl_output_list, link) {
|
|
|
|
|
xwl_output = window_output->xwl_output;
|
|
|
|
|
if (xwl_output->scale > scale)
|
|
|
|
|
scale = xwl_output->scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return scale;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 15:30:38 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_surface_enter(void *data,
|
|
|
|
|
struct wl_surface *wl_surface,
|
|
|
|
|
struct wl_output *wl_output)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window = data;
|
2022-05-12 12:04:29 +02:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2023-11-02 10:37:15 +01:00
|
|
|
struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output);
|
|
|
|
|
|
2023-11-02 11:05:55 +01:00
|
|
|
if (xwl_output) {
|
2023-11-02 10:37:15 +01:00
|
|
|
xwl_window_enter_output(xwl_window, xwl_output);
|
2023-11-02 11:05:55 +01:00
|
|
|
xwl_window_update_surface_scale(xwl_window);
|
|
|
|
|
}
|
2022-05-12 15:30:38 +02:00
|
|
|
|
2022-05-12 12:04:29 +02:00
|
|
|
if (xwl_window->wl_output != wl_output) {
|
2022-05-12 15:30:38 +02:00
|
|
|
xwl_window->wl_output = wl_output;
|
2022-05-12 12:04:29 +02:00
|
|
|
|
|
|
|
|
if (xwl_screen->fullscreen)
|
|
|
|
|
xwl_window_set_fullscreen(xwl_window);
|
|
|
|
|
}
|
2022-05-12 15:30:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xwl_window_surface_leave(void *data,
|
|
|
|
|
struct wl_surface *wl_surface,
|
|
|
|
|
struct wl_output *wl_output)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window = data;
|
2023-11-02 10:37:15 +01:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output);
|
|
|
|
|
|
2023-11-02 11:05:55 +01:00
|
|
|
if (xwl_output) {
|
2023-11-02 10:37:15 +01:00
|
|
|
xwl_window_leave_output(xwl_window, xwl_output);
|
2023-11-02 11:05:55 +01:00
|
|
|
xwl_window_update_surface_scale(xwl_window);
|
|
|
|
|
}
|
2022-05-12 15:30:38 +02:00
|
|
|
|
|
|
|
|
if (xwl_window->wl_output == wl_output)
|
|
|
|
|
xwl_window->wl_output = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_surface_listener surface_listener = {
|
|
|
|
|
xwl_window_surface_enter,
|
|
|
|
|
xwl_window_surface_leave
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-29 10:45:01 +02:00
|
|
|
static void
|
|
|
|
|
xdg_toplevel_handle_configure(void *data,
|
|
|
|
|
struct xdg_toplevel *xdg_toplevel,
|
|
|
|
|
int32_t width,
|
|
|
|
|
int32_t height,
|
|
|
|
|
struct wl_array *states)
|
|
|
|
|
{
|
2023-08-11 11:16:04 +02:00
|
|
|
struct xwl_window *xwl_window = data;
|
2023-11-09 10:40:53 +01:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2023-12-14 18:26:33 +01:00
|
|
|
uint32_t *p;
|
|
|
|
|
Bool old_active = xwl_screen->active;
|
2023-11-27 14:40:25 +01:00
|
|
|
double scale, new_width, new_height;
|
2023-08-11 11:16:04 +02:00
|
|
|
|
|
|
|
|
/* Maintain our current size if no dimensions are requested */
|
|
|
|
|
if (width == 0 && height == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-11-09 10:40:53 +01:00
|
|
|
if (!xwl_screen->fullscreen) {
|
2023-11-27 14:40:25 +01:00
|
|
|
new_width = (double) (width * xwl_screen->global_surface_scale);
|
|
|
|
|
new_height = (double) (height * xwl_screen->global_surface_scale);
|
|
|
|
|
|
|
|
|
|
scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
new_width *= scale;
|
|
|
|
|
new_height *= scale;
|
|
|
|
|
|
2023-11-09 10:40:53 +01:00
|
|
|
/* This will be committed by the xdg_surface.configure handler */
|
2023-11-02 10:25:46 +01:00
|
|
|
xwl_window_maybe_resize(xwl_window, new_width, new_height);
|
2023-11-09 10:40:53 +01:00
|
|
|
}
|
2023-12-14 18:26:33 +01:00
|
|
|
|
|
|
|
|
xwl_screen->active = FALSE;
|
|
|
|
|
wl_array_for_each (p, states) {
|
|
|
|
|
uint32_t state = *p;
|
|
|
|
|
if (state == XDG_TOPLEVEL_STATE_ACTIVATED) {
|
|
|
|
|
xwl_screen->active = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (old_active != xwl_screen->active) {
|
|
|
|
|
if (!xwl_screen->active)
|
|
|
|
|
xwl_screen_lost_focus(xwl_screen);
|
|
|
|
|
}
|
2022-04-29 10:45:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xdg_toplevel_handle_close(void *data,
|
|
|
|
|
struct xdg_toplevel *xdg_toplevel)
|
|
|
|
|
{
|
|
|
|
|
DebugF("Terminating on compositor request");
|
|
|
|
|
GiveUp(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
|
|
|
|
xdg_toplevel_handle_configure,
|
|
|
|
|
xdg_toplevel_handle_close,
|
|
|
|
|
};
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
static void
|
|
|
|
|
xwl_window_update_rootful_scale(struct xwl_window *xwl_window, double previous_scale)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
double new_scale, new_width, new_height;
|
|
|
|
|
|
|
|
|
|
new_scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
new_width = xwl_screen->width / previous_scale * new_scale;
|
|
|
|
|
new_height = xwl_screen->height / previous_scale * new_scale;
|
|
|
|
|
|
|
|
|
|
DebugF("XWAYLAND: Fractional scale is now %.2f (was %.2f)\n",
|
|
|
|
|
new_scale, previous_scale);
|
|
|
|
|
|
|
|
|
|
xwl_output_set_xscale(xwl_screen->fixed_output, new_scale);
|
|
|
|
|
xwl_window_maybe_resize(xwl_window, new_width, new_height);
|
|
|
|
|
xwl_window_check_fractional_scale_viewport(xwl_window,
|
|
|
|
|
xwl_screen_get_width(xwl_screen),
|
|
|
|
|
xwl_screen_get_height(xwl_screen));
|
|
|
|
|
|
|
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
|
|
|
|
if (xwl_window->libdecor_frame) {
|
|
|
|
|
xwl_window_libdecor_set_size_limits(xwl_window);
|
|
|
|
|
xwl_window_update_libdecor_size(xwl_window,
|
|
|
|
|
NULL,
|
|
|
|
|
xwl_screen_get_width(xwl_screen),
|
|
|
|
|
xwl_screen_get_height(xwl_screen));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
wl_surface_commit(xwl_window->surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_fractional_scale_preferred_scale(void *data,
|
|
|
|
|
struct wp_fractional_scale_v1 *fractional_scale,
|
|
|
|
|
uint32_t scale_numerator)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window = data;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
|
double previous_scale = xwl_window_get_fractional_scale_factor(xwl_window);
|
|
|
|
|
|
|
|
|
|
if (xwl_window_update_fractional_scale(xwl_window, scale_numerator)) {
|
|
|
|
|
if (xwl_screen->fixed_output) { /* We're running rootful */
|
|
|
|
|
xwl_window_update_rootful_scale(xwl_window, previous_scale);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wp_fractional_scale_v1_listener fractional_scale_listener = {
|
|
|
|
|
wp_fractional_scale_preferred_scale,
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-28 15:49:51 +02:00
|
|
|
static Bool
|
|
|
|
|
xwl_create_root_surface(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2023-12-22 16:54:40 +01:00
|
|
|
WindowPtr window = xwl_window->toplevel;
|
2022-04-28 15:49:51 +02:00
|
|
|
struct wl_region *region;
|
|
|
|
|
|
|
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
|
|
|
|
if (xwl_screen->decorate) {
|
|
|
|
|
xwl_window->libdecor_frame =
|
|
|
|
|
libdecor_decorate(xwl_screen->libdecor_context,
|
|
|
|
|
xwl_window->surface,
|
|
|
|
|
&libdecor_frame_iface,
|
|
|
|
|
xwl_window);
|
2023-07-24 17:39:51 +02:00
|
|
|
xwl_window_libdecor_set_size_limits(xwl_window);
|
2022-05-04 14:42:41 +02:00
|
|
|
libdecor_frame_map(xwl_window->libdecor_frame);
|
2022-04-28 15:49:51 +02:00
|
|
|
}
|
2022-05-04 14:42:41 +02:00
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
xwl_window->xdg_surface =
|
|
|
|
|
xdg_wm_base_get_xdg_surface(xwl_screen->xdg_wm_base, xwl_window->surface);
|
|
|
|
|
if (xwl_window->xdg_surface == NULL) {
|
|
|
|
|
ErrorF("Failed creating xdg_wm_base xdg_surface\n");
|
|
|
|
|
goto err_surf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xwl_window->xdg_toplevel =
|
|
|
|
|
xdg_surface_get_toplevel(xwl_window->xdg_surface);
|
|
|
|
|
if (xwl_window->xdg_surface == NULL) {
|
|
|
|
|
ErrorF("Failed creating xdg_toplevel\n");
|
|
|
|
|
goto err_surf;
|
|
|
|
|
}
|
2022-04-28 15:49:51 +02:00
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
xdg_surface_add_listener(xwl_window->xdg_surface,
|
|
|
|
|
&xdg_surface_listener, xwl_window);
|
2022-04-28 15:49:51 +02:00
|
|
|
|
2022-05-04 14:42:41 +02:00
|
|
|
xdg_toplevel_add_listener(xwl_window->xdg_toplevel,
|
|
|
|
|
&xdg_toplevel_listener,
|
2023-08-11 11:16:04 +02:00
|
|
|
xwl_window);
|
2022-05-04 14:42:41 +02:00
|
|
|
}
|
2022-04-29 10:45:01 +02:00
|
|
|
|
2023-11-02 10:37:15 +01:00
|
|
|
wl_surface_add_listener(xwl_window->surface,
|
|
|
|
|
&surface_listener, xwl_window);
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
if (xwl_screen_should_use_fractional_scale(xwl_screen)) {
|
|
|
|
|
xwl_window->fractional_scale =
|
|
|
|
|
wp_fractional_scale_manager_v1_get_fractional_scale(xwl_screen->fractional_scale_manager,
|
|
|
|
|
xwl_window->surface);
|
|
|
|
|
wp_fractional_scale_v1_add_listener(xwl_window->fractional_scale,
|
|
|
|
|
&fractional_scale_listener, xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 15:51:55 +02:00
|
|
|
xwl_window_rootful_update_title(xwl_window);
|
2022-04-29 10:22:15 +02:00
|
|
|
xwl_window_rootful_set_app_id(xwl_window);
|
2022-04-28 15:49:51 +02:00
|
|
|
wl_surface_commit(xwl_window->surface);
|
|
|
|
|
|
|
|
|
|
region = wl_compositor_create_region(xwl_screen->compositor);
|
|
|
|
|
if (region == NULL) {
|
|
|
|
|
ErrorF("Failed creating region\n");
|
|
|
|
|
goto err_surf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_region_add(region, 0, 0,
|
|
|
|
|
window->drawable.width, window->drawable.height);
|
|
|
|
|
wl_surface_set_opaque_region(xwl_window->surface, region);
|
|
|
|
|
wl_region_destroy(region);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
err_surf:
|
|
|
|
|
if (xwl_window->xdg_toplevel)
|
|
|
|
|
xdg_toplevel_destroy(xwl_window->xdg_toplevel);
|
|
|
|
|
if (xwl_window->xdg_surface)
|
|
|
|
|
xdg_surface_destroy(xwl_window->xdg_surface);
|
|
|
|
|
wl_surface_destroy(xwl_window->surface);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-15 18:27:27 +01:00
|
|
|
void
|
2023-12-22 19:00:42 +01:00
|
|
|
xwl_window_update_surface_window(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
WindowPtr surface_window = xwl_window->toplevel;
|
|
|
|
|
ScreenPtr screen = surface_window->drawable.pScreen;
|
|
|
|
|
PixmapPtr surface_pixmap;
|
|
|
|
|
DamagePtr window_damage;
|
|
|
|
|
RegionRec damage_region;
|
|
|
|
|
WindowPtr window;
|
|
|
|
|
|
|
|
|
|
surface_pixmap = screen->GetWindowPixmap(surface_window);
|
|
|
|
|
|
|
|
|
|
for (window = surface_window->firstChild; window; window = window->firstChild) {
|
|
|
|
|
PixmapPtr window_pixmap;
|
|
|
|
|
|
|
|
|
|
if (!RegionEqual(&window->winSize, &surface_window->winSize))
|
|
|
|
|
break;
|
2024-06-04 17:26:29 +02:00
|
|
|
|
|
|
|
|
if (!window->mapped)
|
|
|
|
|
break;
|
2023-12-22 19:00:42 +01:00
|
|
|
|
|
|
|
|
/* The surface window must be top-level for its window pixmap */
|
|
|
|
|
window_pixmap = screen->GetWindowPixmap(window);
|
|
|
|
|
if (window_pixmap == surface_pixmap)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
surface_pixmap = window_pixmap;
|
|
|
|
|
|
|
|
|
|
/* A descendant with alpha channel cannot be the surface window, since
|
|
|
|
|
* any non-opaque areas need to take the contents of ancestors into
|
|
|
|
|
* account.
|
|
|
|
|
*/
|
|
|
|
|
if (window->drawable.depth == 32)
|
|
|
|
|
continue;
|
|
|
|
|
|
2024-06-17 17:35:53 +02:00
|
|
|
if (window->redirectDraw == RedirectDrawManual &&
|
|
|
|
|
!xwl_present_window_redirected(window))
|
2024-06-04 17:02:57 +02:00
|
|
|
break;
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
surface_window = window;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (xwl_window->surface_window == surface_window)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-01-10 14:55:57 +01:00
|
|
|
if (xwl_window->surface_window_damage) {
|
|
|
|
|
if (xwl_present_maybe_unredirect_window(xwl_window->surface_window) &&
|
|
|
|
|
screen->SourceValidate == xwl_source_validate) {
|
|
|
|
|
WindowPtr toplevel = xwl_window->toplevel;
|
|
|
|
|
|
|
|
|
|
xwl_source_validate(&toplevel->drawable,
|
|
|
|
|
toplevel->drawable.x, toplevel->drawable.y,
|
|
|
|
|
toplevel->drawable.width,
|
|
|
|
|
toplevel->drawable.height,
|
|
|
|
|
IncludeInferiors);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RegionNotEmpty(xwl_window->surface_window_damage))
|
|
|
|
|
need_source_validate_dec(xwl_window->xwl_screen);
|
|
|
|
|
|
|
|
|
|
RegionDestroy(xwl_window->surface_window_damage);
|
|
|
|
|
xwl_window->surface_window_damage = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
window_damage = window_get_damage(xwl_window->surface_window);
|
|
|
|
|
if (window_damage) {
|
|
|
|
|
RegionInit(&damage_region, NullBox, 1);
|
|
|
|
|
RegionCopy(&damage_region, DamageRegion(window_damage));
|
|
|
|
|
unregister_damage(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (surface_window->drawable.depth != xwl_window->surface_window->drawable.depth)
|
2024-07-02 18:51:44 +02:00
|
|
|
xwl_window_buffers_dispose(xwl_window, FALSE);
|
2023-12-22 19:00:42 +01:00
|
|
|
|
|
|
|
|
xwl_window->surface_window = surface_window;
|
|
|
|
|
register_damage(xwl_window);
|
|
|
|
|
|
|
|
|
|
if (window_damage) {
|
|
|
|
|
RegionPtr new_region = DamageRegion(window_get_damage(surface_window));
|
|
|
|
|
|
|
|
|
|
RegionUnion(new_region, new_region, &damage_region);
|
|
|
|
|
RegionUninit(&damage_region);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
static struct xwl_window *
|
2019-12-17 15:07:07 +01:00
|
|
|
ensure_surface_for_window(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen;
|
|
|
|
|
struct xwl_window *xwl_window;
|
2019-11-04 14:32:29 +01:00
|
|
|
WindowPtr toplevel;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
xwl_window = xwl_window_from_window(window);
|
|
|
|
|
if (xwl_window)
|
|
|
|
|
return xwl_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
|
|
|
|
|
if (xwl_screen->rootless) {
|
|
|
|
|
if (window->redirectDraw != RedirectDrawManual)
|
2024-02-08 18:41:25 +01:00
|
|
|
return NULL;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (window->parent)
|
2024-02-08 18:41:25 +01:00
|
|
|
return NULL;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xwl_window = calloc(1, sizeof *xwl_window);
|
|
|
|
|
if (xwl_window == NULL)
|
2024-02-08 18:41:25 +01:00
|
|
|
return NULL;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
xwl_window->xwl_screen = xwl_screen;
|
2023-12-22 16:54:40 +01:00
|
|
|
xwl_window->toplevel = window;
|
2023-12-22 19:00:42 +01:00
|
|
|
xwl_window->surface_window = window;
|
2023-11-27 14:40:25 +01:00
|
|
|
xwl_window->fractional_scale_numerator = FRACTIONAL_SCALE_DENOMINATOR;
|
2023-11-27 15:02:08 +01:00
|
|
|
xwl_window->viewport_scale_x = 1.0;
|
|
|
|
|
xwl_window->viewport_scale_y = 1.0;
|
2023-11-27 14:40:25 +01:00
|
|
|
xwl_window->surface_scale = 1;
|
2023-11-02 10:37:15 +01:00
|
|
|
xorg_list_init(&xwl_window->xwl_output_list);
|
2019-12-17 15:07:07 +01:00
|
|
|
xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor);
|
|
|
|
|
if (xwl_window->surface == NULL) {
|
|
|
|
|
ErrorF("wl_display_create_surface failed\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-24 16:13:04 +00:00
|
|
|
if (xwl_screen->xwayland_shell) {
|
|
|
|
|
xwl_window->xwayland_surface = xwayland_shell_v1_get_xwayland_surface(
|
|
|
|
|
xwl_screen->xwayland_shell, xwl_window->surface);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 15:49:51 +02:00
|
|
|
if (!xwl_screen->rootless && !xwl_create_root_surface(xwl_window))
|
|
|
|
|
goto err;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-12-20 12:15:15 +01:00
|
|
|
#ifdef XWL_HAS_GLAMOR
|
|
|
|
|
if (xwl_screen->dmabuf_protocol_version >= 4)
|
|
|
|
|
xwl_dmabuf_setup_feedback_for_window(xwl_window);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
wl_display_flush(xwl_screen->display);
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
send_surface_id_event(xwl_window);
|
|
|
|
|
|
|
|
|
|
wl_surface_set_user_data(xwl_window->surface, xwl_window);
|
2022-05-04 14:25:29 +02:00
|
|
|
xwl_window_set_xwayland_tag(xwl_window);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
compRedirectWindow(serverClient, window, CompositeRedirectManual);
|
|
|
|
|
|
|
|
|
|
dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window);
|
|
|
|
|
xorg_list_init(&xwl_window->link_damage);
|
|
|
|
|
xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list);
|
|
|
|
|
xorg_list_init(&xwl_window->frame_callback_list);
|
|
|
|
|
|
|
|
|
|
xwl_window_buffers_init(xwl_window);
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
xwl_window_update_surface_window(xwl_window);
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
xwl_window_init_allow_commits(xwl_window);
|
|
|
|
|
|
2019-11-04 14:32:29 +01:00
|
|
|
/* When a new window-manager window is realized, then the randr emulation
|
|
|
|
|
* props may have not been set on the managed client window yet.
|
|
|
|
|
*/
|
2022-05-12 12:04:29 +02:00
|
|
|
if (!xwl_screen->fullscreen && window_is_wm_window(window)) {
|
2019-11-04 14:32:29 +01:00
|
|
|
toplevel = window_get_client_toplevel(window);
|
|
|
|
|
if (toplevel)
|
|
|
|
|
xwl_output_set_window_randr_emu_props(xwl_screen, toplevel);
|
|
|
|
|
} else {
|
2019-11-04 11:46:49 +01:00
|
|
|
/* CSD or O-R toplevel window, check viewport on creation */
|
|
|
|
|
xwl_window_check_resolution_change_emulation(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 17:58:01 +02:00
|
|
|
if (xwl_screen->tearing_control_manager) {
|
|
|
|
|
xwl_window->tearing_control = wp_tearing_control_manager_v1_get_tearing_control(
|
|
|
|
|
xwl_screen->tearing_control_manager, xwl_window->surface);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-25 19:53:56 +03:00
|
|
|
xwl_window_set_input_region(xwl_window, wInputShape(window));
|
|
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
return xwl_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
free(xwl_window);
|
2024-02-08 18:41:25 +01:00
|
|
|
return NULL;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bool
|
|
|
|
|
xwl_realize_window(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
2022-02-21 10:20:09 +01:00
|
|
|
CompScreenPtr comp_screen = GetCompScreen(screen);
|
2019-12-17 15:07:07 +01:00
|
|
|
struct xwl_screen *xwl_screen;
|
2024-02-08 18:41:25 +01:00
|
|
|
struct xwl_window *xwl_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
Bool ret;
|
|
|
|
|
|
|
|
|
|
xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
|
|
|
|
|
screen->RealizeWindow = xwl_screen->RealizeWindow;
|
|
|
|
|
ret = (*screen->RealizeWindow) (window);
|
|
|
|
|
xwl_screen->RealizeWindow = screen->RealizeWindow;
|
|
|
|
|
screen->RealizeWindow = xwl_realize_window;
|
|
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2022-02-21 10:20:09 +01:00
|
|
|
if (xwl_screen->rootless) {
|
|
|
|
|
/* We do not want the COW to be mapped when rootless in Xwayland */
|
|
|
|
|
if (window == comp_screen->pOverlayWin) {
|
|
|
|
|
window->mapped = FALSE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-02-21 10:20:09 +01:00
|
|
|
if (!window->parent) {
|
2024-02-06 14:51:56 +01:00
|
|
|
BoxRec box = {
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
xwl_screen_get_width(xwl_screen),
|
|
|
|
|
xwl_screen_get_height(xwl_screen)
|
|
|
|
|
};
|
2022-02-21 10:20:09 +01:00
|
|
|
|
|
|
|
|
RegionReset(&window->winSize, &box);
|
|
|
|
|
RegionNull(&window->clipList);
|
|
|
|
|
RegionNull(&window->borderClip);
|
|
|
|
|
}
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
xwl_window = ensure_surface_for_window(window);
|
|
|
|
|
if (!xwl_window)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
if (window == xwl_window->surface_window &&
|
2024-02-08 18:41:25 +01:00
|
|
|
!window_get_damage(window))
|
2024-02-08 18:18:06 +01:00
|
|
|
return register_damage(xwl_window);
|
2024-02-08 18:41:25 +01:00
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
return TRUE;
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-23 09:23:02 +02:00
|
|
|
static void
|
|
|
|
|
xwl_surface_destroy_free_timer(struct xwl_wl_surface *xwl_wl_surface)
|
|
|
|
|
{
|
|
|
|
|
if (xwl_wl_surface->wl_surface_destroy_timer) {
|
|
|
|
|
TimerFree(xwl_wl_surface->wl_surface_destroy_timer);
|
|
|
|
|
xwl_wl_surface->wl_surface_destroy_timer = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xwl_window_surface_do_destroy(struct xwl_wl_surface *xwl_wl_surface)
|
|
|
|
|
{
|
|
|
|
|
wl_surface_destroy(xwl_wl_surface->wl_surface);
|
|
|
|
|
xorg_list_del(&xwl_wl_surface->link);
|
|
|
|
|
xwl_surface_destroy_free_timer(xwl_wl_surface);
|
|
|
|
|
free(xwl_wl_surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CARD32
|
|
|
|
|
xwl_surface_destroy_callback(OsTimerPtr timer, CARD32 now, void *arg)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_wl_surface *xwl_wl_surface = arg;
|
|
|
|
|
|
|
|
|
|
xwl_window_surface_do_destroy(xwl_wl_surface);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2022-09-24 16:13:04 +00:00
|
|
|
release_wl_surface_for_window_legacy_delay(struct xwl_window *xwl_window)
|
2022-09-23 09:23:02 +02:00
|
|
|
{
|
|
|
|
|
struct xwl_wl_surface *xwl_wl_surface;
|
|
|
|
|
|
|
|
|
|
/* If the Xserver is terminating, destroy the surface immediately */
|
|
|
|
|
if ((dispatchException & DE_TERMINATE) == DE_TERMINATE) {
|
|
|
|
|
wl_surface_destroy(xwl_window->surface);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 16:39:30 +02:00
|
|
|
/* Break the wl_surface / xwl_window relationship */
|
|
|
|
|
wl_surface_set_user_data(xwl_window->surface, NULL);
|
|
|
|
|
xwl_window_clear_xwayland_tag(xwl_window);
|
|
|
|
|
|
|
|
|
|
/* Schedule the destruction later, to mitigate the race between X11
|
|
|
|
|
* and Wayland processing so that the compositor has the time to
|
|
|
|
|
* establish the association before the wl_surface is destroyed.
|
2022-09-23 09:23:02 +02:00
|
|
|
*/
|
2024-05-10 10:47:12 +02:00
|
|
|
xwl_wl_surface = XNFcallocarray(1, sizeof *xwl_wl_surface);
|
2022-09-23 09:23:02 +02:00
|
|
|
xwl_wl_surface->wl_surface = xwl_window->surface;
|
|
|
|
|
xorg_list_add(&xwl_wl_surface->link,
|
|
|
|
|
&xwl_window->xwl_screen->pending_wl_surface_destroy);
|
|
|
|
|
xwl_wl_surface->wl_surface_destroy_timer =
|
|
|
|
|
TimerSet(NULL, 0, DELAYED_WL_SURFACE_DESTROY,
|
|
|
|
|
xwl_surface_destroy_callback, xwl_wl_surface);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-24 16:13:04 +00:00
|
|
|
static void
|
|
|
|
|
release_wl_surface_for_window_shell(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
xwayland_surface_v1_destroy(xwl_window->xwayland_surface);
|
|
|
|
|
wl_surface_destroy(xwl_window->surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
release_wl_surface_for_window(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
if (xwl_window->xwayland_surface)
|
|
|
|
|
release_wl_surface_for_window_shell(xwl_window);
|
|
|
|
|
else
|
|
|
|
|
release_wl_surface_for_window_legacy_delay(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-03 09:52:28 +02:00
|
|
|
static void
|
|
|
|
|
xwl_window_dispose(struct xwl_window *xwl_window)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
2024-07-03 09:52:28 +02:00
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2019-12-17 15:07:07 +01:00
|
|
|
struct xwl_seat *xwl_seat;
|
2024-07-03 09:52:28 +02:00
|
|
|
WindowPtr window = xwl_window->toplevel;
|
2024-07-02 18:54:10 +02:00
|
|
|
ScreenPtr screen = xwl_screen->screen;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-07-03 09:52:28 +02:00
|
|
|
compUnredirectWindow(serverClient, window, CompositeRedirectManual);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-03-12 10:51:25 +01:00
|
|
|
xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) {
|
|
|
|
|
if (xwl_seat->focus_window == xwl_window)
|
|
|
|
|
xwl_seat->focus_window = NULL;
|
|
|
|
|
if (xwl_seat->tablet_focus_window == xwl_window)
|
|
|
|
|
xwl_seat->tablet_focus_window = NULL;
|
|
|
|
|
if (xwl_seat->last_focus_window == xwl_window)
|
|
|
|
|
xwl_seat->last_focus_window = NULL;
|
|
|
|
|
if (xwl_seat->cursor_confinement_window == xwl_window)
|
|
|
|
|
xwl_seat_unconfine_pointer(xwl_seat);
|
|
|
|
|
if (xwl_seat->pointer_warp_emulator &&
|
|
|
|
|
xwl_seat->pointer_warp_emulator->locked_window == xwl_window)
|
|
|
|
|
xwl_seat_destroy_pointer_warp_emulator(xwl_seat);
|
|
|
|
|
xwl_seat_clear_touch(xwl_seat, xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
if (xwl_window_has_viewport_enabled(xwl_window))
|
|
|
|
|
xwl_window_disable_viewport(xwl_window);
|
2023-04-06 11:34:51 +02:00
|
|
|
#ifdef XWL_HAS_GLAMOR
|
2022-12-20 12:15:15 +01:00
|
|
|
xwl_dmabuf_feedback_destroy(&xwl_window->feedback);
|
|
|
|
|
|
2023-04-06 11:34:51 +02:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
2023-03-09 18:44:25 +01:00
|
|
|
if (xwl_window->xwl_screen->present)
|
|
|
|
|
xwl_present_for_each_frame_callback(xwl_window, xwl_present_unrealize_window);
|
2023-04-06 11:34:51 +02:00
|
|
|
#endif /* GLAMOR_HAS_GBM */
|
|
|
|
|
#endif /* XWL_HAS_GLAMOR */
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2022-10-17 17:58:01 +02:00
|
|
|
if (xwl_window->tearing_control)
|
|
|
|
|
wp_tearing_control_v1_destroy(xwl_window->tearing_control);
|
|
|
|
|
|
2023-11-27 14:40:25 +01:00
|
|
|
if (xwl_window->fractional_scale)
|
|
|
|
|
wp_fractional_scale_v1_destroy(xwl_window->fractional_scale);
|
|
|
|
|
|
2023-08-15 15:32:47 -07:00
|
|
|
if (xwl_window->surface_sync)
|
|
|
|
|
wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync);
|
|
|
|
|
|
2022-09-23 09:23:02 +02:00
|
|
|
release_wl_surface_for_window(xwl_window);
|
2022-03-11 12:03:06 +01:00
|
|
|
xorg_list_del(&xwl_window->link_damage);
|
|
|
|
|
xorg_list_del(&xwl_window->link_window);
|
|
|
|
|
|
2024-07-02 18:54:10 +02:00
|
|
|
/* Special case for the root window in rootful mode */
|
|
|
|
|
xwl_window_buffers_dispose(xwl_window,
|
|
|
|
|
(!xwl_screen->rootless && window == screen->root));
|
2022-03-11 12:03:06 +01:00
|
|
|
|
2023-12-21 12:25:28 +01:00
|
|
|
if (xwl_window->window_buffers_timer)
|
|
|
|
|
TimerFree(xwl_window->window_buffers_timer);
|
|
|
|
|
|
2022-03-11 12:03:06 +01:00
|
|
|
if (xwl_window->frame_callback)
|
|
|
|
|
wl_callback_destroy(xwl_window->frame_callback);
|
|
|
|
|
|
2023-11-02 10:37:15 +01:00
|
|
|
xwl_window_free_outputs(xwl_window);
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
free(xwl_window);
|
|
|
|
|
dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL);
|
2024-07-03 09:52:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bool
|
|
|
|
|
xwl_unrealize_window(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
struct xwl_window *xwl_window = xwl_window_get(window);
|
|
|
|
|
Bool ret;
|
|
|
|
|
|
|
|
|
|
if (xwl_window) {
|
|
|
|
|
unregister_damage(xwl_window);
|
|
|
|
|
xwl_window_dispose(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
screen->UnrealizeWindow = xwl_screen->UnrealizeWindow;
|
|
|
|
|
ret = (*screen->UnrealizeWindow) (window);
|
|
|
|
|
xwl_screen->UnrealizeWindow = screen->UnrealizeWindow;
|
|
|
|
|
screen->UnrealizeWindow = xwl_unrealize_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xwl_window_set_window_pixmap(WindowPtr window,
|
|
|
|
|
PixmapPtr pixmap)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen;
|
|
|
|
|
struct xwl_window *xwl_window;
|
|
|
|
|
PixmapPtr old_pixmap;
|
|
|
|
|
|
|
|
|
|
old_pixmap = (*screen->GetWindowPixmap) (window);
|
|
|
|
|
xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
|
|
|
|
|
screen->SetWindowPixmap = xwl_screen->SetWindowPixmap;
|
|
|
|
|
(*screen->SetWindowPixmap) (window, pixmap);
|
|
|
|
|
xwl_screen->SetWindowPixmap = screen->SetWindowPixmap;
|
|
|
|
|
screen->SetWindowPixmap = xwl_window_set_window_pixmap;
|
|
|
|
|
|
|
|
|
|
if (!RegionNotEmpty(&window->winSize))
|
|
|
|
|
return;
|
|
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
xwl_window = ensure_surface_for_window(window);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-02-08 18:41:25 +01:00
|
|
|
if (!xwl_window ||
|
|
|
|
|
(old_pixmap->drawable.width == pixmap->drawable.width &&
|
|
|
|
|
old_pixmap->drawable.height == pixmap->drawable.height))
|
2019-12-17 15:07:07 +01:00
|
|
|
return;
|
|
|
|
|
|
2024-07-02 18:51:44 +02:00
|
|
|
xwl_window_buffers_dispose(xwl_window, FALSE);
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-27 11:08:00 +01:00
|
|
|
Bool
|
|
|
|
|
xwl_change_window_attributes(WindowPtr window, unsigned long mask)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
OtherClients *others;
|
|
|
|
|
Bool ret;
|
|
|
|
|
|
|
|
|
|
screen->ChangeWindowAttributes = xwl_screen->ChangeWindowAttributes;
|
|
|
|
|
ret = (*screen->ChangeWindowAttributes) (window, mask);
|
|
|
|
|
xwl_screen->ChangeWindowAttributes = screen->ChangeWindowAttributes;
|
|
|
|
|
screen->ChangeWindowAttributes = xwl_change_window_attributes;
|
|
|
|
|
|
|
|
|
|
if (window != screen->root || !(mask & CWEventMask))
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
for (others = wOtherClients(window); others; others = others->next) {
|
|
|
|
|
if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask))
|
|
|
|
|
xwl_screen->wm_client_id = CLIENT_ID(others->resource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-22 19:00:42 +01:00
|
|
|
void
|
|
|
|
|
xwl_clip_notify(WindowPtr window, int dx, int dy)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
struct xwl_window *xwl_window = xwl_window_from_window(window);
|
|
|
|
|
|
|
|
|
|
screen->ClipNotify = xwl_screen->ClipNotify;
|
|
|
|
|
(*screen->ClipNotify) (window, dx, dy);
|
|
|
|
|
xwl_screen->ClipNotify = screen->ClipNotify;
|
|
|
|
|
screen->ClipNotify = xwl_clip_notify;
|
|
|
|
|
|
|
|
|
|
if (xwl_window)
|
|
|
|
|
xwl_window_update_surface_window(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-15 18:08:16 +01:00
|
|
|
int
|
|
|
|
|
xwl_config_notify(WindowPtr window,
|
2019-12-17 15:07:07 +01:00
|
|
|
int x, int y,
|
2024-02-15 18:08:16 +01:00
|
|
|
int width, int height, int bw,
|
2019-12-17 15:07:07 +01:00
|
|
|
WindowPtr sib)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen;
|
|
|
|
|
struct xwl_window *xwl_window;
|
2024-02-15 18:08:16 +01:00
|
|
|
Bool size_changed;
|
|
|
|
|
int ret;
|
2019-12-17 15:07:07 +01:00
|
|
|
|
|
|
|
|
xwl_screen = xwl_screen_get(screen);
|
2020-01-03 17:55:28 +01:00
|
|
|
xwl_window = xwl_window_from_window(window);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-02-15 18:08:16 +01:00
|
|
|
size_changed = width != window->drawable.width || height != window->drawable.height;
|
2024-01-10 14:55:57 +01:00
|
|
|
if (size_changed && xwl_window && xwl_window->toplevel == window &&
|
|
|
|
|
screen->SourceValidate == xwl_source_validate) {
|
|
|
|
|
xwl_source_validate(&window->drawable, window->drawable.x, window->drawable.y,
|
|
|
|
|
window->drawable.width, window->drawable.height,
|
|
|
|
|
IncludeInferiors);
|
|
|
|
|
}
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2024-02-15 18:08:16 +01:00
|
|
|
screen->ConfigNotify = xwl_screen->ConfigNotify;
|
|
|
|
|
ret = screen->ConfigNotify(window, x, y, width, height, bw, sib);
|
|
|
|
|
xwl_screen->ConfigNotify = screen->ConfigNotify;
|
|
|
|
|
screen->ConfigNotify = xwl_config_notify;
|
|
|
|
|
|
|
|
|
|
return ret;
|
2020-01-09 11:00:36 +01:00
|
|
|
}
|
|
|
|
|
|
2024-05-06 11:37:36 +02:00
|
|
|
void
|
|
|
|
|
xwl_resize_window(WindowPtr window,
|
|
|
|
|
int x, int y,
|
|
|
|
|
unsigned int width, unsigned int height,
|
|
|
|
|
WindowPtr sib)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen;
|
2024-05-06 11:39:32 +02:00
|
|
|
struct xwl_window *xwl_window;
|
2024-05-06 11:37:36 +02:00
|
|
|
|
|
|
|
|
xwl_screen = xwl_screen_get(screen);
|
2024-05-06 11:39:32 +02:00
|
|
|
xwl_window = xwl_window_from_window(window);
|
2024-05-06 11:37:36 +02:00
|
|
|
|
|
|
|
|
screen->ResizeWindow = xwl_screen->ResizeWindow;
|
|
|
|
|
screen->ResizeWindow(window, x, y, width, height, sib);
|
|
|
|
|
xwl_screen->ResizeWindow = screen->ResizeWindow;
|
|
|
|
|
screen->ResizeWindow = xwl_resize_window;
|
2024-05-06 11:39:32 +02:00
|
|
|
|
|
|
|
|
if (xwl_window) {
|
2024-05-06 13:57:28 +02:00
|
|
|
if (xwl_window_get(window) || xwl_window_is_toplevel(window))
|
|
|
|
|
xwl_window_check_resolution_change_emulation(xwl_window);
|
2024-05-06 11:39:32 +02:00
|
|
|
if (window == screen->root) {
|
|
|
|
|
#ifdef XWL_HAS_LIBDECOR
|
|
|
|
|
unsigned int decor_width, decor_height;
|
|
|
|
|
|
|
|
|
|
decor_width = width / xwl_screen->global_surface_scale;
|
|
|
|
|
decor_height = height / xwl_screen->global_surface_scale;
|
|
|
|
|
xwl_window_update_libdecor_size(xwl_window, NULL,
|
|
|
|
|
decor_width, decor_height);
|
|
|
|
|
#endif
|
|
|
|
|
xwl_window_check_fractional_scale_viewport(xwl_window, width, height);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-06 11:37:36 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-09 11:00:36 +01:00
|
|
|
void
|
|
|
|
|
xwl_move_window(WindowPtr window,
|
|
|
|
|
int x, int y,
|
|
|
|
|
WindowPtr next_sib,
|
|
|
|
|
VTKind kind)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen;
|
|
|
|
|
struct xwl_window *xwl_window;
|
|
|
|
|
|
|
|
|
|
xwl_screen = xwl_screen_get(screen);
|
|
|
|
|
xwl_window = xwl_window_from_window(window);
|
|
|
|
|
|
|
|
|
|
screen->MoveWindow = xwl_screen->MoveWindow;
|
|
|
|
|
(*screen->MoveWindow) (window, x, y, next_sib, kind);
|
|
|
|
|
xwl_screen->MoveWindow = screen->MoveWindow;
|
|
|
|
|
screen->MoveWindow = xwl_move_window;
|
|
|
|
|
|
2020-01-15 14:36:45 +01:00
|
|
|
if (xwl_window && (xwl_window_get(window) || xwl_window_is_toplevel(window)))
|
2019-12-17 15:07:07 +01:00
|
|
|
xwl_window_check_resolution_change_emulation(xwl_window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
frame_callback(void *data,
|
|
|
|
|
struct wl_callback *callback,
|
|
|
|
|
uint32_t time)
|
|
|
|
|
{
|
|
|
|
|
struct xwl_window *xwl_window = data;
|
|
|
|
|
|
|
|
|
|
wl_callback_destroy (xwl_window->frame_callback);
|
|
|
|
|
xwl_window->frame_callback = NULL;
|
|
|
|
|
|
2023-03-10 12:39:30 +01:00
|
|
|
if (xwl_window->xwl_screen->present) {
|
2023-03-09 18:44:25 +01:00
|
|
|
xwl_present_for_each_frame_callback(xwl_window, xwl_present_frame_callback);
|
2023-03-10 12:39:30 +01:00
|
|
|
|
|
|
|
|
/* If xwl_window_create_frame_callback was called from
|
|
|
|
|
* xwl_present_frame_callback, need to make sure all fallback timers
|
|
|
|
|
* are adjusted correspondingly.
|
|
|
|
|
*/
|
|
|
|
|
if (xwl_window->frame_callback)
|
|
|
|
|
xwl_present_for_each_frame_callback(xwl_window, xwl_present_reset_timer);
|
|
|
|
|
}
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_callback_listener frame_listener = {
|
|
|
|
|
frame_callback
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xwl_window_create_frame_callback(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
|
|
|
|
|
wl_callback_add_listener(xwl_window->frame_callback, &frame_listener,
|
|
|
|
|
xwl_window);
|
2022-03-15 17:47:56 +01:00
|
|
|
|
2023-03-10 12:39:30 +01:00
|
|
|
/* If we get called from frame_callback, it will take care of calling
|
|
|
|
|
* xwl_present_reset_timer.
|
|
|
|
|
*/
|
|
|
|
|
if (xwl_window->xwl_screen->present &&
|
|
|
|
|
!xwl_present_entered_for_each_frame_callback())
|
2023-03-09 18:44:25 +01:00
|
|
|
xwl_present_for_each_frame_callback(xwl_window, xwl_present_reset_timer);
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bool
|
|
|
|
|
xwl_destroy_window(WindowPtr window)
|
|
|
|
|
{
|
|
|
|
|
ScreenPtr screen = window->drawable.pScreen;
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
xwayland: Make sure we do not leak xwl_window on destroy
Right now, we would dispose the xwl_window and all the data associated
with it on unrealize.
But not all window destruction go through the unrealize code path, for
example when the root window (running rootful) is destroyed from the
resource manager on server reset, we do not get to the unrealize window
step, but straight to destroy window.
As a result, we are leaking the xwl_window and all the data associated
with it, for example:
| 65,536 bytes in 1 blocks are possibly lost in loss record 12,462 of 12,488
| at 0x484A0FC: calloc (vg_replace_malloc.c:1675)
| by 0x48B661C: UnknownInlinedFun (pixman-bits-image.c:1273)
| by 0x48B661C: _pixman_bits_image_init (pixman-bits-image.c:1296)
| by 0x48B6754: create_bits_image_internal (pixman-bits-image.c:1349)
| by 0x64180DE: UnknownInlinedFun (cairo-image-surface.c:380)
| by 0x64180DE: UnknownInlinedFun (cairo-image-surface.c:366)
| by 0x64180DE: cairo_image_surface_create (cairo-image-surface.c:432)
| by 0x6346B44: UnknownInlinedFun (libdecor-gtk.c:467)
| by 0x6346B44: libdecor_plugin_gtk_frame_new (libdecor-gtk.c:546)
| by 0x4B7F297: libdecor_decorate (libdecor.c:559)
| by 0x42C6F3: xwl_create_root_surface (xwayland-window.c:1266)
| by 0x42CD97: ensure_surface_for_window (xwayland-window.c:1466)
| by 0x42D0D1: xwl_realize_window (xwayland-window.c:1560)
| by 0x50858F: compRealizeWindow (compwindow.c:279)
| by 0x4FF2A2: MapWindow (window.c:2706)
| by 0x4F9E7F: InitRootWindow (window.c:697)
To avoid that issue, check whether there is still an xwl_window
associated with the X11 window on destroy, and if that's the case,
dispose the xwl_window.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1589>
2024-07-03 09:55:43 +02:00
|
|
|
struct xwl_window *xwl_window = xwl_window_get(window);
|
2019-12-17 15:07:07 +01:00
|
|
|
Bool ret;
|
|
|
|
|
|
|
|
|
|
if (xwl_screen->present)
|
|
|
|
|
xwl_present_cleanup(window);
|
|
|
|
|
|
xwayland: Make sure we do not leak xwl_window on destroy
Right now, we would dispose the xwl_window and all the data associated
with it on unrealize.
But not all window destruction go through the unrealize code path, for
example when the root window (running rootful) is destroyed from the
resource manager on server reset, we do not get to the unrealize window
step, but straight to destroy window.
As a result, we are leaking the xwl_window and all the data associated
with it, for example:
| 65,536 bytes in 1 blocks are possibly lost in loss record 12,462 of 12,488
| at 0x484A0FC: calloc (vg_replace_malloc.c:1675)
| by 0x48B661C: UnknownInlinedFun (pixman-bits-image.c:1273)
| by 0x48B661C: _pixman_bits_image_init (pixman-bits-image.c:1296)
| by 0x48B6754: create_bits_image_internal (pixman-bits-image.c:1349)
| by 0x64180DE: UnknownInlinedFun (cairo-image-surface.c:380)
| by 0x64180DE: UnknownInlinedFun (cairo-image-surface.c:366)
| by 0x64180DE: cairo_image_surface_create (cairo-image-surface.c:432)
| by 0x6346B44: UnknownInlinedFun (libdecor-gtk.c:467)
| by 0x6346B44: libdecor_plugin_gtk_frame_new (libdecor-gtk.c:546)
| by 0x4B7F297: libdecor_decorate (libdecor.c:559)
| by 0x42C6F3: xwl_create_root_surface (xwayland-window.c:1266)
| by 0x42CD97: ensure_surface_for_window (xwayland-window.c:1466)
| by 0x42D0D1: xwl_realize_window (xwayland-window.c:1560)
| by 0x50858F: compRealizeWindow (compwindow.c:279)
| by 0x4FF2A2: MapWindow (window.c:2706)
| by 0x4F9E7F: InitRootWindow (window.c:697)
To avoid that issue, check whether there is still an xwl_window
associated with the X11 window on destroy, and if that's the case,
dispose the xwl_window.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1589>
2024-07-03 09:55:43 +02:00
|
|
|
if (xwl_window)
|
|
|
|
|
xwl_window_dispose(xwl_window);
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
screen->DestroyWindow = xwl_screen->DestroyWindow;
|
|
|
|
|
|
|
|
|
|
if (screen->DestroyWindow)
|
|
|
|
|
ret = screen->DestroyWindow (window);
|
|
|
|
|
else
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
|
|
xwl_screen->DestroyWindow = screen->DestroyWindow;
|
|
|
|
|
screen->DestroyWindow = xwl_destroy_window;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 16:39:03 +02:00
|
|
|
static Bool
|
|
|
|
|
xwl_window_attach_buffer(struct xwl_window *xwl_window)
|
2019-12-17 15:07:07 +01:00
|
|
|
{
|
|
|
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
2023-12-22 19:00:42 +01:00
|
|
|
WindowPtr surface_window = xwl_window->surface_window;
|
2019-12-17 15:07:07 +01:00
|
|
|
RegionPtr region;
|
|
|
|
|
BoxPtr box;
|
|
|
|
|
struct wl_buffer *buffer;
|
|
|
|
|
PixmapPtr pixmap;
|
|
|
|
|
int i;
|
|
|
|
|
|
2024-07-02 12:36:01 +02:00
|
|
|
pixmap = xwl_window_swap_pixmap(xwl_window, TRUE);
|
2024-01-18 17:10:57 +01:00
|
|
|
buffer = xwl_pixmap_get_wl_buffer(pixmap);
|
2019-12-17 15:07:07 +01:00
|
|
|
|
2021-03-29 15:01:15 +02:00
|
|
|
if (!buffer) {
|
|
|
|
|
ErrorF("Error getting buffer\n");
|
2023-07-24 16:39:03 +02:00
|
|
|
return FALSE;
|
2021-03-29 15:01:15 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Arbitrary limit to try to avoid flooding the Wayland
|
|
|
|
|
* connection. If we flood it too much anyway, this could
|
|
|
|
|
* abort in libwayland-client.
|
|
|
|
|
*/
|
2024-02-19 16:39:13 +01:00
|
|
|
region = xwl_window_get_damage_region(xwl_window);
|
2019-12-17 15:07:07 +01:00
|
|
|
if (RegionNumRects(region) > 256) {
|
|
|
|
|
box = RegionExtents(region);
|
|
|
|
|
xwl_surface_damage(xwl_screen, xwl_window->surface,
|
2023-12-22 19:00:42 +01:00
|
|
|
box->x1 + surface_window->borderWidth,
|
|
|
|
|
box->y1 + surface_window->borderWidth,
|
2019-12-17 15:07:07 +01:00
|
|
|
box->x2 - box->x1, box->y2 - box->y1);
|
|
|
|
|
} else {
|
|
|
|
|
box = RegionRects(region);
|
|
|
|
|
for (i = 0; i < RegionNumRects(region); i++, box++) {
|
|
|
|
|
xwl_surface_damage(xwl_screen, xwl_window->surface,
|
2023-12-22 19:00:42 +01:00
|
|
|
box->x1 + surface_window->borderWidth,
|
|
|
|
|
box->y1 + surface_window->borderWidth,
|
2019-12-17 15:07:07 +01:00
|
|
|
box->x2 - box->x1, box->y2 - box->y1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 16:39:03 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xwl_window_post_damage(struct xwl_window *xwl_window)
|
|
|
|
|
{
|
|
|
|
|
assert(!xwl_window->frame_callback);
|
|
|
|
|
|
|
|
|
|
if (!xwl_window_attach_buffer(xwl_window))
|
|
|
|
|
return;
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
xwl_window_create_frame_callback(xwl_window);
|
2023-12-22 19:00:42 +01:00
|
|
|
DamageEmpty(window_get_damage(xwl_window->surface_window));
|
2019-12-17 15:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
2024-04-25 19:53:56 +03:00
|
|
|
void
|
|
|
|
|
xwl_window_set_input_region(struct xwl_window *xwl_window,
|
|
|
|
|
RegionPtr input_shape)
|
|
|
|
|
{
|
|
|
|
|
struct wl_region *region;
|
|
|
|
|
BoxPtr box;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!input_shape) {
|
|
|
|
|
wl_surface_set_input_region(xwl_window->surface, NULL);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region = wl_compositor_create_region(xwl_window->xwl_screen->compositor);
|
|
|
|
|
box = RegionRects(input_shape);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < RegionNumRects(input_shape); ++i, ++box) {
|
|
|
|
|
wl_region_add(region,
|
|
|
|
|
box->x1,
|
|
|
|
|
box->y1,
|
|
|
|
|
box->x2 - box->x1,
|
|
|
|
|
box->y2 - box->y1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_surface_set_input_region(xwl_window->surface, region);
|
|
|
|
|
wl_region_destroy(region);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 15:07:07 +01:00
|
|
|
Bool
|
|
|
|
|
xwl_window_init(void)
|
|
|
|
|
{
|
|
|
|
|
if (!dixRegisterPrivateKey(&xwl_window_private_key, PRIVATE_WINDOW, 0))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|