mutter/src/wayland/meta-wayland-color-management.c

1629 lines
55 KiB
C

/*
* Copyright (C) 2024 SUSE Software Solutions Germany GmbH
* Copyright (C) 2024 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Written by:
* Joan Torres <joan.torres@suse.com>
* Sebastian Wick <sebastian.wick@redhat.com>
*/
#include "config.h"
#include "meta-wayland-color-management.h"
#include "backends/meta-color-device.h"
#include "backends/meta-color-manager.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "core/meta-debug-control-private.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-versions.h"
#include "wayland/meta-wayland-outputs.h"
#include "color-management-v1-server-protocol.h"
struct _MetaWaylandColorManager
{
GObject parent;
MetaWaylandCompositor *compositor;
struct wl_global *global;
gulong color_state_changed_handler_id;
/* struct wl_resource */
GList *resources;
/* Key: MetaMonitor
* Value: MetaWaylandColorManagementOutput
*/
GHashTable *outputs;
/* Key: MetaWaylandSurface
* Value: MetaWaylandColorManagementSurface
*/
GHashTable *surfaces;
};
#define META_TYPE_WAYLAND_COLOR_MANAGER (meta_wayland_color_manager_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandColorManager,
meta_wayland_color_manager,
META, WAYLAND_COLOR_MANAGER,
GObject)
G_DEFINE_TYPE (MetaWaylandColorManager,
meta_wayland_color_manager,
G_TYPE_OBJECT)
typedef struct _MetaWaylandColorManagementOutput
{
MetaWaylandColorManager *color_manager;
/* struct wl_resource */
GList *resources;
MetaWaylandOutput *output;
gulong output_destroyed_handler_id;
} MetaWaylandColorManagementOutput;
typedef struct _MetaWaylandColorManagementSurface
{
MetaWaylandColorManager *color_manager;
struct wl_resource *resource;
/* struct wl_resource */
GList *feedback_resources;
MetaWaylandSurface *surface;
gulong surface_destroyed_handler_id;
gulong surface_main_monitor_handler_id;
ClutterColorState *preferred_color_state;
} MetaWaylandColorManagementSurface;
typedef enum _MetaWaylandImageDescriptionState
{
META_WAYLAND_IMAGE_DESCRIPTION_STATE_PENDING,
META_WAYLAND_IMAGE_DESCRIPTION_STATE_READY,
META_WAYLAND_IMAGE_DESCRIPTION_STATE_FAILED,
} MetaWaylandImageDescriptionState;
typedef enum _MetaWaylandImageDescriptionFlags
{
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_DEFAULT = 0,
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_ALLOW_INFO = (1 << 0),
} MetaWaylandImageDescriptionFlags;
typedef struct _MetaWaylandImageDescription
{
MetaWaylandColorManager *color_manager;
struct wl_resource *resource;
MetaWaylandImageDescriptionState state;
gboolean has_info;
ClutterColorState *color_state;
} MetaWaylandImageDescription;
typedef struct _MetaWaylandCreatorParams
{
MetaWaylandColorManager *color_manager;
struct wl_resource *resource;
ClutterColorimetry colorimetry;
ClutterEOTF eotf;
ClutterLuminance lum;
gboolean is_colorimetry_set;
gboolean is_eotf_set;
gboolean is_luminance_set;
} MetaWaylandCreatorParams;
static void meta_wayland_color_management_surface_free (MetaWaylandColorManagementSurface *cm_surface);
static void meta_wayland_color_management_output_free (MetaWaylandColorManagementOutput *cm_output);
static MetaMonitorManager *
get_monitor_manager (MetaWaylandColorManager *color_manager)
{
MetaWaylandCompositor *compositor = color_manager->compositor;
MetaBackend *backend = meta_context_get_backend (compositor->context);
return meta_backend_get_monitor_manager (backend);
}
static ClutterContext *
get_clutter_context (MetaWaylandColorManager *color_manager)
{
MetaWaylandCompositor *compositor = color_manager->compositor;
MetaBackend *backend = meta_context_get_backend (compositor->context);
return meta_backend_get_clutter_context (backend);
}
static MetaColorManager *
get_meta_color_manager (MetaWaylandColorManager *color_manager)
{
MetaWaylandCompositor *compositor = color_manager->compositor;
MetaBackend *backend = meta_context_get_backend (compositor->context);
return meta_backend_get_color_manager (backend);
}
static ClutterColorManager *
get_clutter_color_manager (MetaWaylandColorManager *color_manager)
{
ClutterContext *clutter_context = get_clutter_context (color_manager);
return clutter_context_get_color_manager (clutter_context);
}
static float
scaled_uint32_to_float (uint32_t value)
{
return value * 0.0001f;
}
static uint32_t
float_to_scaled_uint32 (float value)
{
return (uint32_t) (value * 10000);
}
static gboolean
wayland_tf_to_clutter (enum xx_color_manager_v4_transfer_function tf,
ClutterEOTF *eotf)
{
switch (tf)
{
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22:
eotf->type = CLUTTER_EOTF_TYPE_GAMMA;
eotf->gamma_exp = 2.2f;
return TRUE;
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28:
eotf->type = CLUTTER_EOTF_TYPE_GAMMA;
eotf->gamma_exp = 2.8f;
return TRUE;
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB:
eotf->type = CLUTTER_EOTF_TYPE_NAMED;
eotf->tf_name = CLUTTER_TRANSFER_FUNCTION_SRGB;
return TRUE;
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ:
eotf->type = CLUTTER_EOTF_TYPE_NAMED;
eotf->tf_name = CLUTTER_TRANSFER_FUNCTION_PQ;
return TRUE;
default:
return FALSE;
}
}
static enum xx_color_manager_v4_transfer_function
clutter_tf_to_wayland (ClutterTransferFunction tf)
{
switch (tf)
{
case CLUTTER_TRANSFER_FUNCTION_SRGB:
return XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB;
case CLUTTER_TRANSFER_FUNCTION_PQ:
return XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ;
case CLUTTER_TRANSFER_FUNCTION_LINEAR:
return XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR;
}
g_assert_not_reached ();
}
static gboolean
wayland_primaries_to_clutter (enum xx_color_manager_v4_primaries primaries,
ClutterColorimetry *colorimetry)
{
switch (primaries)
{
case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB:
colorimetry->type = CLUTTER_COLORIMETRY_TYPE_COLORSPACE;
colorimetry->colorspace = CLUTTER_COLORSPACE_SRGB;
return TRUE;
case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020:
colorimetry->type = CLUTTER_COLORIMETRY_TYPE_COLORSPACE;
colorimetry->colorspace = CLUTTER_COLORSPACE_BT2020;
return TRUE;
case XX_COLOR_MANAGER_V4_PRIMARIES_NTSC:
colorimetry->type = CLUTTER_COLORIMETRY_TYPE_COLORSPACE;
colorimetry->colorspace = CLUTTER_COLORSPACE_NTSC;
return TRUE;
default:
return FALSE;
}
}
static enum xx_color_manager_v4_primaries
clutter_colorspace_to_wayland (ClutterColorspace colorspace)
{
switch (colorspace)
{
case CLUTTER_COLORSPACE_SRGB:
return XX_COLOR_MANAGER_V4_PRIMARIES_SRGB;
case CLUTTER_COLORSPACE_BT2020:
return XX_COLOR_MANAGER_V4_PRIMARIES_BT2020;
case CLUTTER_COLORSPACE_NTSC:
return XX_COLOR_MANAGER_V4_PRIMARIES_NTSC;
}
g_assert_not_reached ();
}
static ClutterColorState *
get_default_color_state (MetaWaylandColorManager *color_manager)
{
ClutterColorManager *clutter_color_manager =
get_clutter_color_manager (color_manager);
return clutter_color_manager_get_default_color_state (clutter_color_manager);
}
static ClutterColorState *
get_output_color_state (MetaWaylandColorManager *color_manager,
MetaMonitor *monitor)
{
MetaColorManager *meta_color_manager = get_meta_color_manager (color_manager);
MetaColorDevice *color_device =
meta_color_manager_get_color_device (meta_color_manager, monitor);
ClutterColorState *color_state = NULL;
if (color_device)
color_state = meta_color_device_get_color_state (color_device);
if (!color_state)
color_state = get_default_color_state (color_manager);
return color_state;
}
static MetaWaylandImageDescription *
meta_wayland_image_description_new (MetaWaylandColorManager *color_manager,
struct wl_resource *resource)
{
MetaWaylandImageDescription *image_desc;
image_desc = g_new0 (MetaWaylandImageDescription, 1);
image_desc->color_manager = color_manager;
image_desc->resource = resource;
return image_desc;
}
static MetaWaylandImageDescription *
meta_wayland_image_description_new_failed (MetaWaylandColorManager *color_manager,
struct wl_resource *resource,
enum xx_image_description_v4_cause cause,
const char *message)
{
MetaWaylandImageDescription *image_desc;
image_desc = meta_wayland_image_description_new (color_manager, resource);
image_desc->state = META_WAYLAND_IMAGE_DESCRIPTION_STATE_FAILED;
image_desc->has_info = FALSE;
xx_image_description_v4_send_failed (resource, cause, message);
return image_desc;
}
static MetaWaylandImageDescription *
meta_wayland_image_description_new_color_state (MetaWaylandColorManager *color_manager,
struct wl_resource *resource,
ClutterColorState *color_state,
MetaWaylandImageDescriptionFlags flags)
{
MetaWaylandImageDescription *image_desc;
image_desc = meta_wayland_image_description_new (color_manager, resource);
image_desc->state = META_WAYLAND_IMAGE_DESCRIPTION_STATE_READY;
image_desc->has_info = !!(flags & META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_ALLOW_INFO);
image_desc->color_state = g_object_ref (color_state);
xx_image_description_v4_send_ready (resource,
clutter_color_state_get_id (color_state));
return image_desc;
}
static void
meta_wayland_image_description_free (MetaWaylandImageDescription *image_desc)
{
g_clear_object (&image_desc->color_state);
free (image_desc);
}
static void
image_description_destructor (struct wl_resource *resource)
{
MetaWaylandImageDescription *image_desc = wl_resource_get_user_data (resource);
meta_wayland_image_description_free (image_desc);
}
static void
image_description_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
send_information (struct wl_resource *info_resource,
ClutterColorState *color_state)
{
enum xx_color_manager_v4_primaries primaries_named;
enum xx_color_manager_v4_transfer_function tf;
const ClutterColorimetry *colorimetry;
const ClutterPrimaries *primaries;
const ClutterEOTF *eotf;
const ClutterLuminance *lum;
colorimetry = clutter_color_state_get_colorimetry (color_state);
switch (colorimetry->type)
{
case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
primaries_named = clutter_colorspace_to_wayland (colorimetry->colorspace);
xx_image_description_info_v4_send_primaries_named (info_resource,
primaries_named);
primaries = clutter_colorspace_to_primaries (colorimetry->colorspace);
xx_image_description_info_v4_send_primaries (
info_resource,
float_to_scaled_uint32 (primaries->r_x),
float_to_scaled_uint32 (primaries->r_y),
float_to_scaled_uint32 (primaries->g_x),
float_to_scaled_uint32 (primaries->g_y),
float_to_scaled_uint32 (primaries->b_x),
float_to_scaled_uint32 (primaries->b_y),
float_to_scaled_uint32 (primaries->w_x),
float_to_scaled_uint32 (primaries->w_y));
break;
case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
xx_image_description_info_v4_send_primaries (
info_resource,
float_to_scaled_uint32 (colorimetry->primaries->r_x),
float_to_scaled_uint32 (colorimetry->primaries->r_y),
float_to_scaled_uint32 (colorimetry->primaries->g_x),
float_to_scaled_uint32 (colorimetry->primaries->g_y),
float_to_scaled_uint32 (colorimetry->primaries->b_x),
float_to_scaled_uint32 (colorimetry->primaries->b_y),
float_to_scaled_uint32 (colorimetry->primaries->w_x),
float_to_scaled_uint32 (colorimetry->primaries->w_y));
break;
}
eotf = clutter_color_state_get_eotf (color_state);
switch (eotf->type)
{
case CLUTTER_EOTF_TYPE_NAMED:
tf = clutter_tf_to_wayland (eotf->tf_name);
xx_image_description_info_v4_send_tf_named (info_resource, tf);
break;
case CLUTTER_EOTF_TYPE_GAMMA:
if (G_APPROX_VALUE (eotf->gamma_exp, 2.2f, 0.0001f))
xx_image_description_info_v4_send_tf_named (info_resource,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22);
else if (G_APPROX_VALUE (eotf->gamma_exp, 2.8f, 0.0001f))
xx_image_description_info_v4_send_tf_named (info_resource,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28);
else
xx_image_description_info_v4_send_tf_power (info_resource,
float_to_scaled_uint32 (eotf->gamma_exp));
break;
}
lum = clutter_color_state_get_luminance (color_state);
xx_image_description_info_v4_send_luminances (info_resource,
float_to_scaled_uint32 (lum->min),
(uint32_t) lum->max,
(uint32_t) lum->ref);
}
static void
image_description_get_information (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
{
MetaWaylandImageDescription *image_desc = wl_resource_get_user_data (resource);
struct wl_resource *info_resource;
if (image_desc->state != META_WAYLAND_IMAGE_DESCRIPTION_STATE_READY)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_V4_ERROR_NOT_READY,
"The image description is not ready");
return;
}
if (!image_desc->has_info)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_V4_ERROR_NO_INFORMATION,
"The image description has no information");
return;
}
g_return_if_fail (image_desc->color_state);
info_resource =
wl_resource_create (client,
&xx_image_description_info_v4_interface,
wl_resource_get_version (resource),
id);
send_information (info_resource, image_desc->color_state);
xx_image_description_info_v4_send_done (info_resource);
wl_resource_destroy (info_resource);
}
static const struct xx_image_description_v4_interface
meta_wayland_image_description_interface =
{
image_description_destroy,
image_description_get_information,
};
static void
update_preferred_color_state (MetaWaylandColorManagementSurface *cm_surface)
{
MetaWaylandColorManager *color_manager = cm_surface->color_manager;
MetaMonitorManager *monitor_manager = get_monitor_manager (color_manager);
MetaWaylandSurface *surface = cm_surface->surface;
MetaLogicalMonitor *logical_monitor;
ClutterColorState *color_state = NULL;
GList *l;
gboolean initial = !cm_surface->preferred_color_state;
g_return_if_fail (surface != NULL);
logical_monitor = meta_wayland_surface_get_main_monitor (surface);
if (!logical_monitor)
{
logical_monitor =
meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
}
if (logical_monitor)
{
GList *monitors = meta_logical_monitor_get_monitors (logical_monitor);
g_return_if_fail (monitors != NULL);
color_state = get_output_color_state (color_manager, monitors->data);
}
if (!color_state)
color_state = get_default_color_state (color_manager);
if (cm_surface->preferred_color_state &&
clutter_color_state_equals (color_state,
cm_surface->preferred_color_state))
return;
g_set_object (&cm_surface->preferred_color_state, color_state);
if (initial)
return;
for (l = cm_surface->feedback_resources; l; l = l->next)
{
struct wl_resource *resource = l->data;
xx_color_management_feedback_surface_v4_send_preferred_changed (resource);
}
}
static void
on_surface_destroy (MetaWaylandSurface *surface,
gpointer user_data)
{
MetaWaylandColorManagementSurface *cm_surface = user_data;
meta_wayland_color_management_surface_free (cm_surface);
}
static void
on_main_monitor_changed (MetaWaylandSurface *surface,
GParamSpec *pspec,
gpointer user_data)
{
MetaWaylandColorManagementSurface *cm_surface = user_data;
update_preferred_color_state (cm_surface);
}
static MetaWaylandColorManagementSurface *
meta_wayland_color_management_surface_new (MetaWaylandColorManager *color_manager,
MetaWaylandSurface *surface)
{
MetaWaylandColorManagementSurface *cm_surface;
cm_surface = g_new0 (MetaWaylandColorManagementSurface, 1);
cm_surface->color_manager = color_manager;
cm_surface->surface = surface;
cm_surface->surface_destroyed_handler_id =
g_signal_connect (surface, "destroy",
G_CALLBACK (on_surface_destroy),
cm_surface);
cm_surface->surface_main_monitor_handler_id =
g_signal_connect (surface, "notify::main-monitor",
G_CALLBACK (on_main_monitor_changed),
cm_surface);
g_hash_table_insert (color_manager->surfaces, surface, cm_surface);
return cm_surface;
}
static void
meta_wayland_color_management_surface_free (MetaWaylandColorManagementSurface *cm_surface)
{
GList *l;
for (l = cm_surface->feedback_resources; l; l = l->next)
{
struct wl_resource *resource = l->data;
wl_resource_set_user_data (resource, NULL);
}
g_clear_list (&cm_surface->feedback_resources, NULL);
if (cm_surface->resource)
wl_resource_set_user_data (cm_surface->resource, NULL);
g_clear_signal_handler (&cm_surface->surface_destroyed_handler_id,
cm_surface->surface);
g_clear_signal_handler (&cm_surface->surface_main_monitor_handler_id,
cm_surface->surface);
g_hash_table_remove (cm_surface->color_manager->surfaces,
cm_surface->surface);
free (cm_surface);
}
static MetaWaylandColorManagementSurface *
ensure_color_management_surface (MetaWaylandColorManager *color_manager,
MetaWaylandSurface *surface)
{
MetaWaylandColorManagementSurface *cm_surface;
cm_surface = g_hash_table_lookup (color_manager->surfaces, surface);
if (cm_surface)
return cm_surface;
return meta_wayland_color_management_surface_new (color_manager, surface);
}
static void
set_image_description (MetaWaylandColorManagementSurface *cm_surface,
ClutterColorState *color_state)
{
MetaWaylandColorManager *color_manager = cm_surface->color_manager;
MetaWaylandSurface *surface = cm_surface->surface;
MetaWaylandSurfaceState *pending =
meta_wayland_surface_get_pending_state (surface);
ClutterColorState *new_color_state;
if (color_state)
new_color_state = color_state;
else
new_color_state = get_default_color_state (color_manager);
g_assert (new_color_state);
pending->has_new_color_state = TRUE;
g_set_object (&pending->color_state, new_color_state);
}
static void
color_management_surface_destructor (struct wl_resource *resource)
{
MetaWaylandColorManagementSurface *cm_surface =
wl_resource_get_user_data (resource);
if (!cm_surface)
return;
set_image_description (cm_surface, NULL);
cm_surface->resource = NULL;
}
static void
color_management_surface_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
color_management_surface_set_image_description (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *image_desc_resource,
uint32_t render_intent)
{
MetaWaylandColorManagementSurface *cm_surface =
wl_resource_get_user_data (resource);
MetaWaylandImageDescription *image_desc =
wl_resource_get_user_data (image_desc_resource);
if (!cm_surface)
{
/* FIXME: the next version will have an ERROR_INERT */
wl_resource_post_error (resource,
XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION,
"Underlying surface object has been destroyed");
return;
}
if (!image_desc->color_state ||
image_desc->state != META_WAYLAND_IMAGE_DESCRIPTION_STATE_READY)
{
wl_resource_post_error (resource,
XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION,
"Trying to set an image description which is not ready");
return;
}
switch (render_intent)
{
case XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL:
break;
default:
wl_resource_post_error (resource,
XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_RENDER_INTENT,
"Trying to use an unsupported rendering intent");
return;
}
set_image_description (cm_surface, image_desc->color_state);
}
static void
color_management_surface_unset_image_description (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandColorManagementSurface *cm_surface =
wl_resource_get_user_data (resource);
if (!cm_surface)
{
/* FIXME: the next version will have an ERROR_INERT */
wl_resource_post_error (resource,
XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION,
"Underlying surface object has been destroyed");
return;
}
set_image_description (cm_surface, NULL);
}
static const struct xx_color_management_surface_v4_interface
meta_wayland_color_management_surface_interface =
{
color_management_surface_destroy,
color_management_surface_set_image_description,
color_management_surface_unset_image_description,
};
static void
on_output_destroyed (MetaWaylandOutput *wayland_output,
gpointer user_data)
{
MetaWaylandColorManagementOutput *cm_output = user_data;
meta_wayland_color_management_output_free (cm_output);
}
static MetaWaylandColorManagementOutput *
meta_wayland_color_management_output_new (MetaWaylandColorManager *color_manager,
MetaWaylandOutput *output)
{
MetaWaylandColorManagementOutput *cm_output;
cm_output = g_new0 (MetaWaylandColorManagementOutput, 1);
cm_output->color_manager = color_manager;
cm_output->output = output;
cm_output->output_destroyed_handler_id =
g_signal_connect (output, "output-destroyed",
G_CALLBACK (on_output_destroyed),
cm_output);
g_hash_table_insert (color_manager->outputs,
meta_wayland_output_get_monitor (output),
cm_output);
return cm_output;
}
static void
meta_wayland_color_management_output_free (MetaWaylandColorManagementOutput *cm_output)
{
GList *l;
for (l = cm_output->resources; l; l = l->next)
{
struct wl_resource *resource = l->data;
wl_resource_set_user_data (resource, NULL);
}
g_clear_list (&cm_output->resources, NULL);
g_clear_signal_handler (&cm_output->output_destroyed_handler_id,
cm_output->output);
g_hash_table_remove (cm_output->color_manager->outputs,
meta_wayland_output_get_monitor (cm_output->output));
free (cm_output);
}
static MetaWaylandColorManagementOutput *
ensure_color_management_output (MetaWaylandColorManager *color_manager,
MetaWaylandOutput *output)
{
MetaWaylandColorManagementOutput *cm_output;
cm_output = g_hash_table_lookup (color_manager->outputs,
meta_wayland_output_get_monitor (output));
if (cm_output)
return cm_output;
return meta_wayland_color_management_output_new (color_manager, output);
}
static void
color_management_output_destructor (struct wl_resource *resource)
{
MetaWaylandColorManagementOutput *cm_output =
wl_resource_get_user_data (resource);
if (!cm_output)
return;
cm_output->resources = g_list_remove (cm_output->resources, resource);
}
static void
color_management_output_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
color_management_output_get_image_description (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
{
MetaWaylandColorManagementOutput *cm_output =
wl_resource_get_user_data (resource);
MetaWaylandCompositor *compositor = wl_client_get_user_data (client);
MetaWaylandColorManager *color_manager =
g_object_get_data (G_OBJECT (compositor), "-meta-wayland-color-manager");
struct wl_resource *image_desc_resource;
MetaWaylandImageDescription *image_desc;
image_desc_resource =
wl_resource_create (client,
&xx_image_description_v4_interface,
wl_resource_get_version (resource),
id);
if (cm_output)
{
MetaMonitor *monitor = meta_wayland_output_get_monitor (cm_output->output);
ClutterColorState *color_state =
get_output_color_state (color_manager, monitor);
image_desc =
meta_wayland_image_description_new_color_state (color_manager,
image_desc_resource,
color_state,
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_DEFAULT |
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_ALLOW_INFO);
}
else
{
image_desc =
meta_wayland_image_description_new_failed (color_manager,
image_desc_resource,
XX_IMAGE_DESCRIPTION_V4_CAUSE_NO_OUTPUT,
"Underlying output object has been destroyed");
}
wl_resource_set_implementation (image_desc_resource,
&meta_wayland_image_description_interface,
image_desc,
image_description_destructor);
}
static const struct xx_color_management_output_v4_interface
meta_wayland_color_management_output_interface =
{
color_management_output_destroy,
color_management_output_get_image_description,
};
static MetaWaylandCreatorParams *
meta_wayland_creator_params_new (MetaWaylandColorManager *color_manager,
struct wl_resource *resource)
{
MetaWaylandCreatorParams *creator_params;
creator_params = g_new0 (MetaWaylandCreatorParams, 1);
creator_params->color_manager = color_manager;
creator_params->resource = resource;
return creator_params;
}
static void
meta_wayland_creator_params_free (MetaWaylandCreatorParams *creator_params)
{
if (creator_params->is_colorimetry_set &&
creator_params->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_PRIMARIES)
g_clear_pointer (&creator_params->colorimetry.primaries, g_free);
g_free (creator_params);
}
static void
creator_params_destructor (struct wl_resource *resource)
{
MetaWaylandCreatorParams *creator_params = wl_resource_get_user_data (resource);
meta_wayland_creator_params_free (creator_params);
}
static void
creator_params_create (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
{
MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource);
MetaWaylandColorManager *color_manager = creator_params->color_manager;
ClutterContext *clutter_context = get_clutter_context (color_manager);
struct wl_resource *image_desc_resource;
g_autoptr (ClutterColorState) color_state = NULL;
MetaWaylandImageDescription *image_desc;
ClutterColorspace colorspace;
ClutterPrimaries *primaries;
ClutterTransferFunction tf_name;
float gamma_exp;
if (!creator_params->is_colorimetry_set || !creator_params->is_eotf_set)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET,
"Not all required parameters were set");
return;
}
image_desc_resource =
wl_resource_create (client,
&xx_image_description_v4_interface,
wl_resource_get_version (resource),
id);
switch (creator_params->colorimetry.type)
{
case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
colorspace = creator_params->colorimetry.colorspace;
primaries = NULL;
break;
case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
colorspace = CLUTTER_COLORSPACE_SRGB;
primaries = creator_params->colorimetry.primaries;
break;
}
switch (creator_params->eotf.type)
{
case CLUTTER_EOTF_TYPE_NAMED:
tf_name = creator_params->eotf.tf_name;
gamma_exp = -1.0f;
break;
case CLUTTER_EOTF_TYPE_GAMMA:
tf_name = CLUTTER_TRANSFER_FUNCTION_SRGB;
gamma_exp = creator_params->eotf.gamma_exp;
break;
}
color_state = clutter_color_state_new_full (clutter_context,
colorspace,
tf_name,
primaries,
gamma_exp,
creator_params->lum.min,
creator_params->lum.max,
creator_params->lum.ref);
image_desc =
meta_wayland_image_description_new_color_state (color_manager,
image_desc_resource,
color_state,
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_DEFAULT);
wl_resource_set_implementation (image_desc_resource,
&meta_wayland_image_description_interface,
image_desc,
image_description_destructor);
wl_resource_destroy (resource);
}
static void
creator_params_set_tf_named (struct wl_client *client,
struct wl_resource *resource,
uint32_t tf)
{
MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource);
ClutterEOTF eotf;
if (creator_params->is_eotf_set)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
"The transfer characteristics were already set");
return;
}
if (!wayland_tf_to_clutter (tf, &eotf))
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF,
"The named transfer function is not supported");
return;
}
creator_params->eotf = eotf;
creator_params->is_eotf_set = TRUE;
}
static void
creator_params_set_tf_power (struct wl_client *client,
struct wl_resource *resource,
uint32_t eexp)
{
MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource);
if (creator_params->is_eotf_set)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
"The transfer characteristics were already set");
return;
}
if (eexp < 10000 || eexp > 100000)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF,
"The exponent must be between 1.0 and 10.0");
return;
}
creator_params->eotf.type = CLUTTER_EOTF_TYPE_GAMMA;
creator_params->eotf.gamma_exp = scaled_uint32_to_float (eexp);
creator_params->is_eotf_set = TRUE;
}
static void
creator_params_set_primaries_named (struct wl_client *client,
struct wl_resource *resource,
uint32_t primaries)
{
MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource);
ClutterColorimetry colorimetry;
if (creator_params->is_colorimetry_set)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
"The primaries were already set");
return;
}
if (!wayland_primaries_to_clutter (primaries, &colorimetry))
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES,
"The named primaries are not supported");
return;
}
creator_params->colorimetry = colorimetry;
creator_params->is_colorimetry_set = TRUE;
}
static void
creator_params_set_primaries (struct wl_client *client,
struct wl_resource *resource,
int32_t r_x,
int32_t r_y,
int32_t g_x,
int32_t g_y,
int32_t b_x,
int32_t b_y,
int32_t w_x,
int32_t w_y)
{
MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource);
ClutterPrimaries *primaries;
if (creator_params->is_colorimetry_set)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
"The primaries were already set");
return;
}
primaries = g_new0 (ClutterPrimaries, 1);
primaries->r_x = scaled_uint32_to_float (r_x);
primaries->r_y = scaled_uint32_to_float (r_y);
primaries->g_x = scaled_uint32_to_float (g_x);
primaries->g_y = scaled_uint32_to_float (g_y);
primaries->b_x = scaled_uint32_to_float (b_x);
primaries->b_y = scaled_uint32_to_float (b_y);
primaries->w_x = scaled_uint32_to_float (w_x);
primaries->w_y = scaled_uint32_to_float (w_y);
if (primaries->r_x < 0.0f || primaries->r_x > 1.0f ||
primaries->r_y < 0.0f || primaries->r_y > 1.0f ||
primaries->g_x < 0.0f || primaries->g_x > 1.0f ||
primaries->g_y < 0.0f || primaries->g_y > 1.0f ||
primaries->b_x < 0.0f || primaries->b_x > 1.0f ||
primaries->b_y < 0.0f || primaries->b_y > 1.0f ||
primaries->w_x < 0.0f || primaries->w_x > 1.0f ||
primaries->w_y < 0.0f || primaries->w_y > 1.0f)
{
g_warning ("Primaries out of expected normalized range");
clutter_primaries_ensure_normalized_range (primaries);
}
creator_params->colorimetry.type = CLUTTER_COLORIMETRY_TYPE_PRIMARIES;
creator_params->colorimetry.primaries = primaries;
creator_params->is_colorimetry_set = TRUE;
}
static void
creator_params_set_luminance (struct wl_client *client,
struct wl_resource *resource,
uint32_t min_lum,
uint32_t max_lum,
uint32_t reference_lum)
{
MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource);
float min, max, ref;
if (creator_params->is_luminance_set)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
"The luminance was already set");
return;
}
min = scaled_uint32_to_float (min_lum);
max = (float) max_lum;
ref = (float) reference_lum;
if (max < ref)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE,
"The maximum luminance is smaller than the reference luminance");
return;
}
if (ref <= min)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE,
"The reference luminance is less or equal to the minimum luminance");
return;
}
creator_params->lum.min = min;
creator_params->lum.max = max;
creator_params->lum.ref = ref;
creator_params->is_luminance_set = TRUE;
}
static void
creator_params_set_mastering_display_primaries (struct wl_client *client,
struct wl_resource *resource,
int32_t r_x,
int32_t r_y,
int32_t g_x,
int32_t g_y,
int32_t b_x,
int32_t b_y,
int32_t w_x,
int32_t w_y)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_MASTERING,
"Setting mastering display primaries is not supported");
}
static void
creator_params_set_mastering_luminance (struct wl_client *client,
struct wl_resource *resource,
uint32_t min_lum,
uint32_t max_lum)
{
wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_MASTERING,
"Setting mastering display luminances is not supported");
}
static void
creator_params_set_max_cll (struct wl_client *client,
struct wl_resource *resource,
uint32_t max_cll)
{
/* ignoring for now */
/* FIXME: technically we must send errors in some cases */
}
static void
creator_params_set_max_fall (struct wl_client *client,
struct wl_resource *resource,
uint32_t max_fall)
{
/* ignoring for now */
/* FIXME: technically we must send errors in some cases */
}
static const struct xx_image_description_creator_params_v4_interface
meta_wayland_image_description_creator_params_interface =
{
creator_params_create,
creator_params_set_tf_named,
creator_params_set_tf_power,
creator_params_set_primaries_named,
creator_params_set_primaries,
creator_params_set_luminance,
creator_params_set_mastering_display_primaries,
creator_params_set_mastering_luminance,
creator_params_set_max_cll,
creator_params_set_max_fall,
};
static void
color_manager_destructor (struct wl_resource *resource)
{
MetaWaylandColorManager *color_manager = wl_resource_get_user_data (resource);
color_manager->resources = g_list_remove (color_manager->resources, resource);
}
static void
color_manager_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
color_manager_get_output (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *output_resource)
{
MetaWaylandColorManager *color_manager = wl_resource_get_user_data (resource);
MetaWaylandOutput *output = wl_resource_get_user_data (output_resource);
MetaWaylandColorManagementOutput *cm_output = NULL;
struct wl_resource *cm_output_resource;
cm_output_resource =
wl_resource_create (client,
&xx_color_management_output_v4_interface,
wl_resource_get_version (resource),
id);
if (output)
{
cm_output = ensure_color_management_output (color_manager, output);
cm_output->resources = g_list_prepend (cm_output->resources,
cm_output_resource);
}
wl_resource_set_implementation (cm_output_resource,
&meta_wayland_color_management_output_interface,
cm_output,
color_management_output_destructor);
}
static void
color_manager_get_surface (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource)
{
MetaWaylandColorManager *color_manager = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandColorManagementSurface *cm_surface;
cm_surface = ensure_color_management_surface (color_manager, surface);
if (cm_surface->resource)
{
wl_resource_post_error (resource,
XX_COLOR_MANAGER_V4_ERROR_SURFACE_EXISTS,
"surface already requested");
return;
}
cm_surface->resource =
wl_resource_create (client,
&xx_color_management_surface_v4_interface,
wl_resource_get_version (resource),
id);
wl_resource_set_implementation (cm_surface->resource,
&meta_wayland_color_management_surface_interface,
cm_surface,
color_management_surface_destructor);
}
static void
color_management_feedback_surface_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
color_management_feedback_surface_get_preferred (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
{
MetaWaylandColorManagementSurface *cm_surface =
wl_resource_get_user_data (resource);
MetaWaylandColorManager *color_manager = cm_surface->color_manager;
MetaWaylandSurface *surface = cm_surface->surface;
struct wl_resource *image_desc_resource;
MetaWaylandImageDescription *image_desc;
if (!surface)
{
wl_resource_post_error (resource,
XX_COLOR_MANAGEMENT_FEEDBACK_SURFACE_V4_ERROR_INERT,
"Underlying surface object has been destroyed");
return;
}
image_desc_resource =
wl_resource_create (client,
&xx_image_description_v4_interface,
wl_resource_get_version (resource),
id);
image_desc =
meta_wayland_image_description_new_color_state (color_manager,
image_desc_resource,
cm_surface->preferred_color_state,
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_DEFAULT |
META_WAYLAND_IMAGE_DESCRIPTION_FLAGS_ALLOW_INFO);
wl_resource_set_implementation (image_desc_resource,
&meta_wayland_image_description_interface,
image_desc,
image_description_destructor);
}
static const struct xx_color_management_feedback_surface_v4_interface
meta_wayland_color_management_feedback_surface_interface =
{
color_management_feedback_surface_destroy,
color_management_feedback_surface_get_preferred,
};
static void
color_management_feedback_surface_destructor (struct wl_resource *resource)
{
MetaWaylandColorManagementSurface *cm_surface =
wl_resource_get_user_data (resource);
if (!cm_surface)
return;
cm_surface->feedback_resources =
g_list_remove (cm_surface->feedback_resources, resource);
}
static void
color_manager_get_feedback_surface (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource)
{
MetaWaylandColorManager *color_manager = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandColorManagementSurface *cm_surface;
struct wl_resource *cm_feedback_surface_resource;
cm_surface = ensure_color_management_surface (color_manager, surface);
cm_feedback_surface_resource =
wl_resource_create (client,
&xx_color_management_feedback_surface_v4_interface,
wl_resource_get_version (resource),
id);
wl_resource_set_implementation (cm_feedback_surface_resource,
&meta_wayland_color_management_feedback_surface_interface,
cm_surface,
color_management_feedback_surface_destructor);
cm_surface->feedback_resources =
g_list_prepend (cm_surface->feedback_resources,
cm_feedback_surface_resource);
update_preferred_color_state (cm_surface);
}
static void
color_manager_new_icc_creator (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
{
wl_resource_post_error (resource,
XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE,
"ICC-based image description creator is unsupported");
}
static void
color_manager_new_parametric_creator (struct wl_client *client,
struct wl_resource *resource,
uint32_t id)
{
MetaWaylandColorManager *color_manager = wl_resource_get_user_data (resource);
MetaWaylandCreatorParams *creator_params;
struct wl_resource *creator_resource;
creator_resource =
wl_resource_create (client,
&xx_image_description_creator_params_v4_interface,
wl_resource_get_version (resource),
id);
creator_params = meta_wayland_creator_params_new (color_manager,
creator_resource);
wl_resource_set_implementation (creator_resource,
&meta_wayland_image_description_creator_params_interface,
creator_params,
creator_params_destructor);
}
static void
color_manager_send_supported_events (struct wl_resource *resource)
{
xx_color_manager_v4_send_supported_intent (resource,
XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
xx_color_manager_v4_send_supported_feature (resource,
XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC);
xx_color_manager_v4_send_supported_feature (resource,
XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES);
xx_color_manager_v4_send_supported_feature (resource,
XX_COLOR_MANAGER_V4_FEATURE_SET_TF_POWER);
xx_color_manager_v4_send_supported_feature (resource,
XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES);
xx_color_manager_v4_send_supported_tf_named (resource,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22);
xx_color_manager_v4_send_supported_tf_named (resource,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28);
xx_color_manager_v4_send_supported_tf_named (resource,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB);
xx_color_manager_v4_send_supported_tf_named (resource,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ);
xx_color_manager_v4_send_supported_primaries_named (resource,
XX_COLOR_MANAGER_V4_PRIMARIES_SRGB);
xx_color_manager_v4_send_supported_primaries_named (resource,
XX_COLOR_MANAGER_V4_PRIMARIES_BT2020);
xx_color_manager_v4_send_supported_primaries_named (resource,
XX_COLOR_MANAGER_V4_PRIMARIES_NTSC);
}
static const struct xx_color_manager_v4_interface
meta_wayland_color_manager_interface =
{
color_manager_destroy,
color_manager_get_output,
color_manager_get_surface,
color_manager_get_feedback_surface,
color_manager_new_icc_creator,
color_manager_new_parametric_creator,
};
static void
color_management_bind (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
MetaWaylandColorManager *color_manager = data;
struct wl_resource *resource;
resource = wl_resource_create (client,
&xx_color_manager_v4_interface,
version,
id);
wl_resource_set_implementation (resource,
&meta_wayland_color_manager_interface,
color_manager,
color_manager_destructor);
color_manager->resources = g_list_prepend (color_manager->resources,
resource);
color_manager_send_supported_events (resource);
}
static void
update_output_color_state (MetaWaylandColorManager *color_manager,
MetaMonitor *monitor)
{
MetaWaylandColorManagementOutput *cm_output;
GHashTableIter iter_surfaces;
MetaWaylandColorManagementSurface *cm_surface;
MetaWaylandOutput *wayland_output;
cm_output = g_hash_table_lookup (color_manager->outputs, monitor);
if (cm_output)
{
GList *l;
for (l = cm_output->resources; l; l = l->next)
{
struct wl_resource *resource = l->data;
xx_color_management_output_v4_send_image_description_changed (resource);
}
}
wayland_output = g_hash_table_lookup (color_manager->compositor->outputs,
meta_monitor_get_spec (monitor));
g_hash_table_iter_init (&iter_surfaces, color_manager->surfaces);
while (g_hash_table_iter_next (&iter_surfaces, NULL, (gpointer *)&cm_surface))
{
MetaWaylandSurface *surface = cm_surface->surface;
if (g_hash_table_contains (surface->outputs, wayland_output))
update_preferred_color_state (cm_surface);
}
}
static void
on_device_color_state_changed (MetaColorManager *meta_color_manager,
MetaColorDevice *color_device,
MetaWaylandColorManager *color_manager)
{
MetaMonitor *monitor = meta_color_device_get_monitor (color_device);
update_output_color_state (color_manager, monitor);
}
static void
meta_wayland_color_manager_dispose (GObject *object)
{
MetaWaylandColorManager *color_manager = META_WAYLAND_COLOR_MANAGER (object);
MetaColorManager *meta_color_manager = get_meta_color_manager (color_manager);
g_clear_signal_handler (&color_manager->color_state_changed_handler_id,
meta_color_manager);
g_clear_pointer (&color_manager->outputs, g_hash_table_destroy);
g_clear_pointer (&color_manager->surfaces, g_hash_table_destroy);
}
static void
meta_wayland_color_manager_init (MetaWaylandColorManager *color_manager)
{
color_manager->outputs = g_hash_table_new (NULL, NULL);
color_manager->surfaces = g_hash_table_new (NULL, NULL);
}
static void
meta_wayland_color_manager_class_init (MetaWaylandColorManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_wayland_color_manager_dispose;
}
static MetaWaylandColorManager *
meta_wayland_color_manager_new (MetaWaylandCompositor *compositor)
{
MetaWaylandColorManager *color_manager;
MetaColorManager *meta_color_manager;
color_manager = g_object_new (META_TYPE_WAYLAND_COLOR_MANAGER, NULL);
color_manager->compositor = compositor;
meta_color_manager = get_meta_color_manager (color_manager);
color_manager->color_state_changed_handler_id =
g_signal_connect_object (meta_color_manager, "device-color-state-changed",
G_CALLBACK (on_device_color_state_changed),
color_manager, 0);
return color_manager;
}
static void
update_enabled (MetaWaylandColorManager *color_manager)
{
MetaWaylandCompositor *compositor = color_manager->compositor;
MetaDebugControl *debug_control =
meta_context_get_debug_control (compositor->context);
gboolean is_enabled =
meta_debug_control_is_color_management_protocol_enabled (debug_control);
if (is_enabled && color_manager->global == NULL)
{
color_manager->global =
wl_global_create (compositor->wayland_display,
&xx_color_manager_v4_interface,
META_XX_COLOR_MANAGEMENT_VERSION,
color_manager,
color_management_bind);
if (color_manager->global == NULL)
g_error ("Failed to register a global wp_color_management object");
}
else if (!is_enabled)
{
g_clear_pointer (&color_manager->global, wl_global_destroy);
}
}
void
meta_wayland_init_color_management (MetaWaylandCompositor *compositor)
{
MetaDebugControl *debug_control =
meta_context_get_debug_control (compositor->context);
g_autoptr (MetaWaylandColorManager) color_manager = NULL;
color_manager = meta_wayland_color_manager_new (compositor);
g_signal_connect_data (debug_control, "notify::color-management-protocol",
G_CALLBACK (update_enabled),
color_manager, NULL,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
update_enabled (color_manager);
g_object_set_data_full (G_OBJECT (compositor), "-meta-wayland-color-manager",
g_steal_pointer (&color_manager),
g_object_unref);
}