4cbf1fb1f9
At shutdown, the Xserver will free all its resources which includes the RRCrtc and RROutput created. Xwayland would do the same in its xwl_output_destroy() called from xwl_close_screen(), leading to a double free of existing RRCrtc RROutput: Invalid read of size 4 at 0x4CDA10: RRCrtcDestroy (rrcrtc.c:689) by 0x426E75: xwl_output_destroy (xwayland-output.c:301) by 0x424144: xwl_close_screen (xwayland.c:117) by 0x460E17: CursorCloseScreen (cursor.c:187) by 0x4EB5A3: AnimCurCloseScreen (animcur.c:106) by 0x4EF431: present_close_screen (present_screen.c:64) by 0x556D40: dix_main (main.c:354) by 0x6F0D290: (below main) (in /usr/lib/libc-2.24.so) Address 0xbb1fc30 is 0 bytes inside a block of size 728 free'd at 0x4C2BDB0: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x4CCE5F: RRCrtcDestroyResource (rrcrtc.c:719) by 0x577541: doFreeResource (resource.c:895) by 0x5787B5: FreeClientResources (resource.c:1161) by 0x578862: FreeAllResources (resource.c:1176) by 0x556C54: dix_main (main.c:323) by 0x6F0D290: (below main) (in /usr/lib/libc-2.24.so) Block was alloc'd at at 0x4C2CA6A: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x4CC6DB: RRCrtcCreate (rrcrtc.c:76) by 0x426D1C: xwl_output_create (xwayland-output.c:264) by 0x4232EC: registry_global (xwayland.c:431) by 0x76CB1C7: ffi_call_unix64 (in /usr/lib/libffi.so.6.0.4) by 0x76CAC29: ffi_call (in /usr/lib/libffi.so.6.0.4) by 0x556CEFD: wl_closure_invoke (connection.c:935) by 0x5569CBF: dispatch_event.isra.4 (wayland-client.c:1310) by 0x556AF13: dispatch_queue (wayland-client.c:1456) by 0x556AF13: wl_display_dispatch_queue_pending (wayland-client.c:1698) by 0x556B33A: wl_display_roundtrip_queue (wayland-client.c:1121) by 0x42371C: xwl_screen_init (xwayland.c:631) by 0x552F60: AddScreen (dispatch.c:3864) And: Invalid read of size 4 at 0x522890: RROutputDestroy (rroutput.c:348) by 0x42684E: xwl_output_destroy (xwayland-output.c:302) by 0x423CF4: xwl_close_screen (xwayland.c:118) by 0x4B6377: CursorCloseScreen (cursor.c:187) by 0x539503: AnimCurCloseScreen (animcur.c:106) by 0x53D081: present_close_screen (present_screen.c:64) by 0x43DBF0: dix_main (main.c:354) by 0x7068730: (below main) (libc-start.c:289) Address 0xc403190 is 0 bytes inside a block of size 154 free'd at 0x4C2CD5A: free (vg_replace_malloc.c:530) by 0x521DF3: RROutputDestroyResource (rroutput.c:389) by 0x45DA61: doFreeResource (resource.c:895) by 0x45ECFD: FreeClientResources (resource.c:1161) by 0x45EDC2: FreeAllResources (resource.c:1176) by 0x43DB04: dix_main (main.c:323) by 0x7068730: (below main) (libc-start.c:289) Block was alloc'd at at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) by 0x52206B: RROutputCreate (rroutput.c:84) by 0x426763: xwl_output_create (xwayland-output.c:270) by 0x422EDC: registry_global (xwayland.c:432) by 0x740FC57: ffi_call_unix64 (unix64.S:76) by 0x740F6B9: ffi_call (ffi64.c:525) by 0x5495A9D: wl_closure_invoke (connection.c:949) by 0x549283F: dispatch_event.isra.4 (wayland-client.c:1274) by 0x5493A13: dispatch_queue (wayland-client.c:1420) by 0x5493A13: wl_display_dispatch_queue_pending (wayland-client.c:1662) by 0x5493D2E: wl_display_roundtrip_queue (wayland-client.c:1085) by 0x4232EC: xwl_screen_init (xwayland.c:632) by 0x439F50: AddScreen (dispatch.c:3864) Split xwl_output_destroy() into xwl_output_destroy() which frees the wl_output and the xwl_output structure, and xwl_output_remove() which does the RRCrtcDestroy() and RROutputDestroy() and call the latter only when an output is effectively removed. An additional benefit, on top of avoiding a double free, is to avoid updating the screen size at shutdown. Signed-off-by: Olivier Fourdan <ofourdan@redhat.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
348 lines
10 KiB
C
348 lines
10 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include "xwayland.h"
|
|
#include <randrstr.h>
|
|
|
|
#define DEFAULT_DPI 96
|
|
|
|
static Rotation
|
|
wl_transform_to_xrandr(enum wl_output_transform transform)
|
|
{
|
|
switch (transform) {
|
|
default:
|
|
case WL_OUTPUT_TRANSFORM_NORMAL:
|
|
return RR_Rotate_0;
|
|
case WL_OUTPUT_TRANSFORM_90:
|
|
return RR_Rotate_90;
|
|
case WL_OUTPUT_TRANSFORM_180:
|
|
return RR_Rotate_180;
|
|
case WL_OUTPUT_TRANSFORM_270:
|
|
return RR_Rotate_270;
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
|
return RR_Reflect_X | RR_Rotate_0;
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
|
return RR_Reflect_X | RR_Rotate_90;
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
|
return RR_Reflect_X | RR_Rotate_180;
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
|
return RR_Reflect_X | RR_Rotate_270;
|
|
}
|
|
}
|
|
|
|
static int
|
|
wl_subpixel_to_xrandr(int subpixel)
|
|
{
|
|
switch (subpixel) {
|
|
default:
|
|
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
|
|
return SubPixelUnknown;
|
|
case WL_OUTPUT_SUBPIXEL_NONE:
|
|
return SubPixelNone;
|
|
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
|
|
return SubPixelHorizontalRGB;
|
|
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
|
|
return SubPixelHorizontalBGR;
|
|
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
|
|
return SubPixelVerticalRGB;
|
|
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
|
|
return SubPixelVerticalBGR;
|
|
}
|
|
}
|
|
|
|
static void
|
|
output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
|
|
int physical_width, int physical_height, int subpixel,
|
|
const char *make, const char *model, int transform)
|
|
{
|
|
struct xwl_output *xwl_output = data;
|
|
|
|
RROutputSetPhysicalSize(xwl_output->randr_output,
|
|
physical_width, physical_height);
|
|
RROutputSetSubpixelOrder(xwl_output->randr_output,
|
|
wl_subpixel_to_xrandr(subpixel));
|
|
xwl_output->x = x;
|
|
xwl_output->y = y;
|
|
|
|
xwl_output->rotation = wl_transform_to_xrandr(transform);
|
|
}
|
|
|
|
static void
|
|
output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
|
|
int width, int height, int refresh)
|
|
{
|
|
struct xwl_output *xwl_output = data;
|
|
|
|
if (!(flags & WL_OUTPUT_MODE_CURRENT))
|
|
return;
|
|
|
|
if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) {
|
|
xwl_output->width = width;
|
|
xwl_output->height = height;
|
|
} else {
|
|
xwl_output->width = height;
|
|
xwl_output->height = width;
|
|
}
|
|
|
|
xwl_output->refresh = refresh;
|
|
}
|
|
|
|
static inline void
|
|
output_get_new_size(struct xwl_output *xwl_output,
|
|
int *height, int *width)
|
|
{
|
|
if (*width < xwl_output->x + xwl_output->width)
|
|
*width = xwl_output->x + xwl_output->width;
|
|
|
|
if (*height < xwl_output->y + xwl_output->height)
|
|
*height = xwl_output->y + xwl_output->height;
|
|
}
|
|
|
|
/* Approximate some kind of mmpd (m.m. per dot) of the screen given the outputs
|
|
* associated with it.
|
|
*
|
|
* It will either calculate the mean mmpd of all the outputs, or default to
|
|
* 96 DPI if no reasonable value could be calculated.
|
|
*/
|
|
static double
|
|
approximate_mmpd(struct xwl_screen *xwl_screen)
|
|
{
|
|
struct xwl_output *it;
|
|
int total_width_mm = 0;
|
|
int total_width = 0;
|
|
|
|
xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
|
|
if (it->randr_output->mmWidth == 0)
|
|
continue;
|
|
|
|
total_width_mm += it->randr_output->mmWidth;
|
|
total_width += it->width;
|
|
}
|
|
|
|
if (total_width_mm != 0)
|
|
return (double)total_width_mm / total_width;
|
|
else
|
|
return 25.4 / DEFAULT_DPI;
|
|
}
|
|
|
|
static void
|
|
update_screen_size(struct xwl_output *xwl_output, int width, int height)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
|
double mmpd;
|
|
|
|
if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
|
|
SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
|
|
|
|
xwl_screen->width = width;
|
|
xwl_screen->height = height;
|
|
xwl_screen->screen->width = width;
|
|
xwl_screen->screen->height = height;
|
|
|
|
if (xwl_output->width == width && xwl_output->height == height) {
|
|
xwl_screen->screen->mmWidth = xwl_output->randr_output->mmWidth;
|
|
xwl_screen->screen->mmHeight = xwl_output->randr_output->mmHeight;
|
|
} else {
|
|
mmpd = approximate_mmpd(xwl_screen);
|
|
xwl_screen->screen->mmWidth = width * mmpd;
|
|
xwl_screen->screen->mmHeight = height * mmpd;
|
|
}
|
|
|
|
SetRootClip(xwl_screen->screen, xwl_screen->root_clip_mode);
|
|
|
|
if (xwl_screen->screen->root) {
|
|
xwl_screen->screen->root->drawable.width = width;
|
|
xwl_screen->screen->root->drawable.height = height;
|
|
RRScreenSizeNotify(xwl_screen->screen);
|
|
}
|
|
|
|
update_desktop_dimensions();
|
|
}
|
|
|
|
static void
|
|
output_handle_done(void *data, struct wl_output *wl_output)
|
|
{
|
|
struct xwl_output *it, *xwl_output = data;
|
|
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
|
int width = 0, height = 0, has_this_output = 0;
|
|
RRModePtr randr_mode;
|
|
|
|
randr_mode = xwayland_cvt(xwl_output->width, xwl_output->height,
|
|
xwl_output->refresh / 1000.0, 0, 0);
|
|
RROutputSetModes(xwl_output->randr_output, &randr_mode, 1, 1);
|
|
RRCrtcNotify(xwl_output->randr_crtc, randr_mode,
|
|
xwl_output->x, xwl_output->y,
|
|
xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
|
|
|
|
xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
|
|
/* output done event is sent even when some property
|
|
* of output is changed. That means that we may already
|
|
* have this output. If it is true, we must not add it
|
|
* into the output_list otherwise we'll corrupt it */
|
|
if (it == xwl_output)
|
|
has_this_output = 1;
|
|
|
|
output_get_new_size(it, &height, &width);
|
|
}
|
|
|
|
if (!has_this_output) {
|
|
xorg_list_append(&xwl_output->link, &xwl_screen->output_list);
|
|
|
|
/* we did not check this output for new screen size, do it now */
|
|
output_get_new_size(xwl_output, &height, &width);
|
|
|
|
--xwl_screen->expecting_event;
|
|
}
|
|
|
|
update_screen_size(xwl_output, width, height);
|
|
}
|
|
|
|
static void
|
|
output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
|
|
{
|
|
}
|
|
|
|
static const struct wl_output_listener output_listener = {
|
|
output_handle_geometry,
|
|
output_handle_mode,
|
|
output_handle_done,
|
|
output_handle_scale
|
|
};
|
|
|
|
struct xwl_output *
|
|
xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
|
|
{
|
|
struct xwl_output *xwl_output;
|
|
static int serial;
|
|
char name[256];
|
|
|
|
xwl_output = calloc(sizeof *xwl_output, 1);
|
|
if (xwl_output == NULL) {
|
|
ErrorF("create_output ENOMEM\n");
|
|
return NULL;
|
|
}
|
|
|
|
xwl_output->output = wl_registry_bind(xwl_screen->registry, id,
|
|
&wl_output_interface, 2);
|
|
if (!xwl_output->output) {
|
|
ErrorF("Failed binding wl_output\n");
|
|
goto err;
|
|
}
|
|
|
|
xwl_output->server_output_id = id;
|
|
wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
|
|
|
|
snprintf(name, sizeof name, "XWAYLAND%d", serial++);
|
|
|
|
xwl_output->xwl_screen = xwl_screen;
|
|
xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output);
|
|
if (!xwl_output->randr_crtc) {
|
|
ErrorF("Failed creating RandR CRTC\n");
|
|
goto err;
|
|
}
|
|
|
|
xwl_output->randr_output = RROutputCreate(xwl_screen->screen, name,
|
|
strlen(name), xwl_output);
|
|
if (!xwl_output->randr_output) {
|
|
ErrorF("Failed creating RandR Output\n");
|
|
goto err;
|
|
}
|
|
|
|
RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
|
|
RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
|
|
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
|
|
|
|
return xwl_output;
|
|
|
|
err:
|
|
if (xwl_output->randr_crtc)
|
|
RRCrtcDestroy(xwl_output->randr_crtc);
|
|
if (xwl_output->output)
|
|
wl_output_destroy(xwl_output->output);
|
|
free(xwl_output);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
xwl_output_destroy(struct xwl_output *xwl_output)
|
|
{
|
|
wl_output_destroy(xwl_output->output);
|
|
free(xwl_output);
|
|
}
|
|
|
|
void
|
|
xwl_output_remove(struct xwl_output *xwl_output)
|
|
{
|
|
struct xwl_output *it;
|
|
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
|
int width = 0, height = 0;
|
|
|
|
RRCrtcDestroy(xwl_output->randr_crtc);
|
|
RROutputDestroy(xwl_output->randr_output);
|
|
xorg_list_del(&xwl_output->link);
|
|
|
|
xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
|
|
output_get_new_size(it, &height, &width);
|
|
update_screen_size(xwl_output, width, height);
|
|
|
|
xwl_output_destroy(xwl_output);
|
|
}
|
|
|
|
static Bool
|
|
xwl_randr_get_info(ScreenPtr pScreen, Rotation * rotations)
|
|
{
|
|
*rotations = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
xwl_randr_set_config(ScreenPtr pScreen,
|
|
Rotation rotation, int rate, RRScreenSizePtr pSize)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Bool
|
|
xwl_screen_init_output(struct xwl_screen *xwl_screen)
|
|
{
|
|
rrScrPrivPtr rp;
|
|
|
|
if (!RRScreenInit(xwl_screen->screen))
|
|
return FALSE;
|
|
|
|
RRScreenSetSizeRange(xwl_screen->screen, 320, 200, 8192, 8192);
|
|
|
|
rp = rrGetScrPriv(xwl_screen->screen);
|
|
rp->rrGetInfo = xwl_randr_get_info;
|
|
rp->rrSetConfig = xwl_randr_set_config;
|
|
|
|
return TRUE;
|
|
}
|