mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-01 00:11:29 +00:00
f24be8476e
If an image description query is running while the surface gets destroyed, we were not properly cleaning up, causing the callbacks to be emitted on freed variables.
825 lines
25 KiB
C
825 lines
25 KiB
C
|
|
#include "gdkwaylandcolor-private.h"
|
|
#include "gdksurface-wayland-private.h"
|
|
#include <gdk/wayland/xx-color-management-v4-client-protocol.h>
|
|
|
|
typedef struct _ImageDescription ImageDescription;
|
|
|
|
static uint primaries_map[] = {
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_SRGB] = 1,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M] = 4,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_PAL] = 5,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_NTSC] = 6,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM] = 8,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_BT2020] = 9,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ] = 10,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3] = 11,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3] = 12,
|
|
[XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB] = 0,
|
|
};
|
|
|
|
static uint
|
|
wl_to_cicp_primaries (enum xx_color_manager_v4_primaries cp)
|
|
{
|
|
return primaries_map[cp];
|
|
}
|
|
|
|
static enum xx_color_manager_v4_primaries
|
|
cicp_to_wl_primaries (uint cp)
|
|
{
|
|
for (guint i = 0; i < G_N_ELEMENTS (primaries_map); i++)
|
|
if (primaries_map[i] == cp)
|
|
return (enum xx_color_manager_v4_primaries)i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uint transfer_map[] = {
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_BT709] = 1,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22] = 4,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28] = 5,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST240] = 7,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR] = 8,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LOG_100] = 9,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LOG_316] = 10,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_XVYCC] = 11,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_BT1361] = 12,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB] = 13,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_EXT_SRGB] = 13,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ] = 16,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST428] = 17,
|
|
[XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_HLG] = 18,
|
|
};
|
|
|
|
static uint
|
|
wl_to_cicp_transfer (enum xx_color_manager_v4_transfer_function tf)
|
|
{
|
|
return transfer_map[tf];
|
|
}
|
|
|
|
static enum xx_color_manager_v4_transfer_function
|
|
cicp_to_wl_transfer (uint tf)
|
|
{
|
|
for (guint i = 0; i < G_N_ELEMENTS (transfer_map); i++)
|
|
if (transfer_map[i] == tf)
|
|
return (enum xx_color_manager_v4_transfer_function)i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct _GdkWaylandColor
|
|
{
|
|
GdkWaylandDisplay *display;
|
|
|
|
struct xx_color_manager_v4 *color_manager;
|
|
struct {
|
|
unsigned int intents;
|
|
unsigned int features;
|
|
unsigned int transfers;
|
|
unsigned int primaries;
|
|
} color_manager_supported;
|
|
|
|
GHashTable *cs_to_desc; /* GdkColorState => xx_image_description_v4 or NULL */
|
|
GHashTable *id_to_cs; /* uint32 identifier => GdkColorState */
|
|
};
|
|
|
|
static guint
|
|
color_state_hash (gconstpointer data)
|
|
{
|
|
GdkColorState *cs = (GdkColorState *) data;
|
|
const GdkCicp *cicp;
|
|
|
|
cicp = gdk_color_state_get_cicp (cs);
|
|
if (cicp)
|
|
{
|
|
GdkCicp norm;
|
|
gdk_cicp_normalize (cicp, &norm);
|
|
return norm.color_primaries << 24 | norm.transfer_function;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gboolean
|
|
color_state_equal (gconstpointer a,
|
|
gconstpointer b)
|
|
{
|
|
GdkColorState *csa = (GdkColorState *) a;
|
|
GdkColorState *csb = (GdkColorState *) b;
|
|
const GdkCicp *cicpa, *cicpb;
|
|
GdkCicp norma, normb;
|
|
|
|
cicpa = gdk_color_state_get_cicp (csa);
|
|
cicpb = gdk_color_state_get_cicp (csb);
|
|
if (cicpa == NULL || cicpb == NULL)
|
|
return FALSE;
|
|
|
|
gdk_cicp_normalize (cicpa, &norma);
|
|
gdk_cicp_normalize (cicpb, &normb);
|
|
|
|
return norma.color_primaries == normb.color_primaries &&
|
|
norma.transfer_function == normb.transfer_function;
|
|
}
|
|
|
|
static void
|
|
xx_color_manager_v4_supported_intent (void *data,
|
|
struct xx_color_manager_v4 *xx_color_manager_v4,
|
|
uint32_t render_intent)
|
|
{
|
|
GdkWaylandColor *color = data;
|
|
|
|
color->color_manager_supported.intents |= (1 << render_intent);
|
|
}
|
|
|
|
static void
|
|
xx_color_manager_v4_supported_feature (void *data,
|
|
struct xx_color_manager_v4 *xx_color_manager_v4,
|
|
uint32_t feature)
|
|
{
|
|
GdkWaylandColor *color = data;
|
|
|
|
color->color_manager_supported.features |= (1 << feature);
|
|
}
|
|
|
|
static void
|
|
xx_color_manager_v4_supported_tf_named (void *data,
|
|
struct xx_color_manager_v4 *xx_color_manager_v4,
|
|
uint32_t tf)
|
|
{
|
|
GdkWaylandColor *color = data;
|
|
|
|
color->color_manager_supported.transfers |= (1 << tf);
|
|
}
|
|
|
|
static void
|
|
xx_color_manager_v4_supported_primaries_named (void *data,
|
|
struct xx_color_manager_v4 *xx_color_manager_v4,
|
|
uint32_t primaries)
|
|
{
|
|
GdkWaylandColor *color = data;
|
|
|
|
color->color_manager_supported.primaries |= (1 << primaries);
|
|
}
|
|
|
|
static struct xx_color_manager_v4_listener color_manager_listener = {
|
|
xx_color_manager_v4_supported_intent,
|
|
xx_color_manager_v4_supported_feature,
|
|
xx_color_manager_v4_supported_tf_named,
|
|
xx_color_manager_v4_supported_primaries_named,
|
|
};
|
|
|
|
GdkWaylandColor *
|
|
gdk_wayland_color_new (GdkWaylandDisplay *display,
|
|
struct wl_registry *registry,
|
|
uint32_t id,
|
|
uint32_t version)
|
|
{
|
|
GdkWaylandColor *color;
|
|
|
|
color = g_new0 (GdkWaylandColor, 1);
|
|
|
|
color->display = display;
|
|
color->cs_to_desc = g_hash_table_new_full (color_state_hash,
|
|
color_state_equal,
|
|
(GDestroyNotify) gdk_color_state_unref,
|
|
(GDestroyNotify) xx_image_description_v4_destroy);
|
|
color->id_to_cs = g_hash_table_new_full (g_direct_hash,
|
|
g_direct_equal,
|
|
NULL,
|
|
(GDestroyNotify) gdk_color_state_unref);
|
|
|
|
color->color_manager = wl_registry_bind (registry,
|
|
id,
|
|
&xx_color_manager_v4_interface,
|
|
MIN (version, 2));
|
|
|
|
xx_color_manager_v4_add_listener (color->color_manager,
|
|
&color_manager_listener,
|
|
color);
|
|
|
|
return color;
|
|
}
|
|
|
|
void
|
|
gdk_wayland_color_free (GdkWaylandColor *color)
|
|
{
|
|
g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
|
|
|
|
g_hash_table_unref (color->cs_to_desc);
|
|
g_hash_table_unref (color->id_to_cs);
|
|
|
|
g_free (color);
|
|
}
|
|
|
|
struct wl_proxy *
|
|
gdk_wayland_color_get_color_manager (GdkWaylandColor *color)
|
|
{
|
|
return (struct wl_proxy *) color->color_manager;
|
|
}
|
|
|
|
typedef struct _CsImageDescListenerData {
|
|
GdkWaylandColor *color;
|
|
GdkColorState *color_state;
|
|
gboolean sync;
|
|
gboolean done;
|
|
} CsImageDescListenerData;
|
|
|
|
static void
|
|
cs_image_listener_data_free (CsImageDescListenerData *csi)
|
|
{
|
|
csi->done = TRUE;
|
|
|
|
if (csi->sync)
|
|
return;
|
|
|
|
g_free (csi);
|
|
}
|
|
|
|
static void
|
|
cs_image_desc_failed (void *data,
|
|
struct xx_image_description_v4 *desc,
|
|
uint32_t cause,
|
|
const char *msg)
|
|
{
|
|
CsImageDescListenerData *csi = data;
|
|
|
|
g_warning ("Failed to get one of the standard image descriptions: %s", msg);
|
|
xx_image_description_v4_destroy (desc);
|
|
|
|
g_hash_table_insert (csi->color->cs_to_desc,
|
|
gdk_color_state_ref (csi->color_state),
|
|
NULL);
|
|
|
|
cs_image_listener_data_free (csi);
|
|
}
|
|
|
|
static void
|
|
cs_image_desc_ready (void *data,
|
|
struct xx_image_description_v4 *desc,
|
|
uint32_t identity)
|
|
{
|
|
CsImageDescListenerData *csi = data;
|
|
|
|
g_hash_table_insert (csi->color->cs_to_desc,
|
|
gdk_color_state_ref (csi->color_state),
|
|
desc);
|
|
g_hash_table_insert (csi->color->id_to_cs,
|
|
GUINT_TO_POINTER (identity),
|
|
gdk_color_state_ref (csi->color_state));
|
|
|
|
cs_image_listener_data_free (csi);
|
|
}
|
|
|
|
static struct xx_image_description_v4_listener cs_image_desc_listener = {
|
|
cs_image_desc_failed,
|
|
cs_image_desc_ready,
|
|
};
|
|
|
|
static void
|
|
create_image_desc (GdkWaylandColor *color,
|
|
GdkColorState *cs,
|
|
gboolean sync)
|
|
{
|
|
CsImageDescListenerData data;
|
|
struct xx_image_description_creator_params_v4 *creator;
|
|
struct xx_image_description_v4 *desc;
|
|
const GdkCicp *cicp;
|
|
GdkCicp norm;
|
|
uint32_t primaries, tf;
|
|
|
|
cicp = gdk_color_state_get_cicp (cs);
|
|
if (!cicp)
|
|
{
|
|
GDK_DEBUG (MISC, "Unsupported color state %s: Not a CICP colorstate",
|
|
gdk_color_state_get_name (cs));
|
|
g_hash_table_insert (color->cs_to_desc, gdk_color_state_ref (cs), NULL);
|
|
return;
|
|
}
|
|
|
|
gdk_cicp_normalize (cicp, &norm);
|
|
primaries = cicp_to_wl_primaries (norm.color_primaries);
|
|
tf = cicp_to_wl_transfer (norm.transfer_function);
|
|
|
|
if ((color->color_manager_supported.primaries & (1 << primaries)) == 0 ||
|
|
(color->color_manager_supported.transfers & (1 << tf)) == 0)
|
|
{
|
|
GDK_DEBUG (MISC, "Unsupported color state %s: Primaries or transfer function unsupported",
|
|
gdk_color_state_get_name (cs));
|
|
g_hash_table_insert (color->cs_to_desc, gdk_color_state_ref (cs), NULL);
|
|
return;
|
|
}
|
|
|
|
data.color = color;
|
|
data.color_state = cs;
|
|
data.sync = sync;
|
|
data.done = FALSE;
|
|
|
|
creator = xx_color_manager_v4_new_parametric_creator (color->color_manager);
|
|
|
|
xx_image_description_creator_params_v4_set_primaries_named (creator, primaries);
|
|
xx_image_description_creator_params_v4_set_tf_named (creator, tf);
|
|
|
|
desc = xx_image_description_creator_params_v4_create (creator);
|
|
|
|
if (sync)
|
|
{
|
|
struct wl_event_queue *event_queue;
|
|
|
|
event_queue = wl_display_create_queue (color->display->wl_display);
|
|
wl_proxy_set_queue ((struct wl_proxy *) desc, event_queue);
|
|
xx_image_description_v4_add_listener (desc, &cs_image_desc_listener, &data);
|
|
while (!data.done)
|
|
gdk_wayland_display_dispatch_queue (GDK_DISPLAY (color->display), event_queue);
|
|
|
|
wl_event_queue_destroy (event_queue);
|
|
}
|
|
else
|
|
{
|
|
xx_image_description_v4_add_listener (desc, &cs_image_desc_listener, g_memdup (&data, sizeof data));
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
gdk_wayland_color_prepare (GdkWaylandColor *color)
|
|
{
|
|
if (color->color_manager)
|
|
{
|
|
const char *intents[] = {
|
|
"perceptual", "relative", "saturation", "absolute", "relative-bpc"
|
|
};
|
|
const char *features[] = {
|
|
"icc-v4-v4", "parametric", "set-primaries", "set-tf-power",
|
|
"set-mastering-display-primaries", "extended-target-volume"
|
|
};
|
|
const char *tf[] = {
|
|
"bt709", "gamma22", "gamma28", "st240", "linear", "log100",
|
|
"log316", "xvycc", "bt1361", "srgb", "ext-srgb", "pq", "st428", "hlg"
|
|
};
|
|
const char *primaries[] = {
|
|
"srgb", "pal-m", "pal", "ntsc", "generic-film", "bt2020", "xyz",
|
|
"dci-p3", "display-p3", "adobe-rgb",
|
|
};
|
|
|
|
for (int i = 0; i < G_N_ELEMENTS (intents); i++)
|
|
{
|
|
GDK_DEBUG (MISC, "Rendering intent %d (%s): %s",
|
|
i, intents[i], color->color_manager_supported.intents & (1 << i) ? "✓" : "✗");
|
|
}
|
|
|
|
for (int i = 0; i < G_N_ELEMENTS (features); i++)
|
|
{
|
|
GDK_DEBUG (MISC, "Feature %d (%s): %s",
|
|
i, features[i], color->color_manager_supported.features & (1 << i) ? "✓" : "✗");
|
|
}
|
|
|
|
for (int i = 0; i < G_N_ELEMENTS (tf); i++)
|
|
{
|
|
GDK_DEBUG (MISC, "Transfer function %d (%s): %s",
|
|
i, tf[i], color->color_manager_supported.transfers & (1 << i) ? "✓" : "✗");
|
|
}
|
|
|
|
for (int i = 0; i < G_N_ELEMENTS (primaries); i++)
|
|
{
|
|
GDK_DEBUG (MISC, "Primaries %d (%s): %s",
|
|
i, primaries[i], color->color_manager_supported.primaries& (1 << i) ? "✓" : "✗");
|
|
}
|
|
}
|
|
|
|
if (color->color_manager &&
|
|
!(color->color_manager_supported.intents & (1 << XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL)))
|
|
{
|
|
GDK_DEBUG (MISC, "Not using color management: Missing perceptual render intent");
|
|
g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
|
|
}
|
|
|
|
if (color->color_manager &&
|
|
(!(color->color_manager_supported.features & (1 << XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC)) ||
|
|
!(color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB)) ||
|
|
!(color->color_manager_supported.primaries & (1 << XX_COLOR_MANAGER_V4_PRIMARIES_SRGB))))
|
|
|
|
{
|
|
GDK_DEBUG (MISC, "Not using color management: Can't create srgb image description");
|
|
g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
|
|
}
|
|
|
|
if (color->color_manager)
|
|
{
|
|
create_image_desc (color, GDK_COLOR_STATE_SRGB, FALSE);
|
|
|
|
if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR))
|
|
create_image_desc (color, GDK_COLOR_STATE_SRGB_LINEAR, FALSE);
|
|
|
|
if (color->color_manager_supported.primaries & (1 << XX_COLOR_MANAGER_V4_PRIMARIES_BT2020))
|
|
{
|
|
if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ))
|
|
create_image_desc (color, GDK_COLOR_STATE_REC2100_PQ, FALSE);
|
|
|
|
if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR))
|
|
create_image_desc (color, GDK_COLOR_STATE_REC2100_LINEAR, FALSE);
|
|
}
|
|
}
|
|
|
|
return color->color_manager != NULL;
|
|
}
|
|
|
|
struct _GdkWaylandColorSurface
|
|
{
|
|
GdkWaylandColor *color;
|
|
struct xx_color_management_surface_v4 *surface;
|
|
struct xx_color_management_feedback_surface_v4 *feedback;
|
|
ImageDescription *current_desc;
|
|
GdkColorStateChanged callback;
|
|
gpointer data;
|
|
};
|
|
|
|
struct _ImageDescription
|
|
{
|
|
GdkWaylandColorSurface *surface;
|
|
|
|
struct xx_image_description_v4 *image_desc;
|
|
struct xx_image_description_info_v4 *info;
|
|
|
|
uint32_t identity;
|
|
|
|
int32_t icc;
|
|
uint32_t icc_size;
|
|
int32_t r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y;
|
|
uint32_t primaries;
|
|
uint32_t tf_power;
|
|
uint32_t tf_named;
|
|
uint32_t min_lum, max_lum, ref_lum;
|
|
int32_t target_r_x, target_r_y, target_g_x, target_g_y, target_b_x, target_b_y, target_w_x, target_w_y;
|
|
uint32_t target_min_lum, target_max_lum;
|
|
uint32_t target_max_cll, target_max_fall;
|
|
|
|
unsigned int has_icc : 1;
|
|
unsigned int has_primaries : 1;
|
|
unsigned int has_primaries_named : 1;
|
|
unsigned int has_tf_power : 1;
|
|
unsigned int has_tf_named : 1;
|
|
unsigned int has_luminances : 1;
|
|
unsigned int has_target_primaries : 1;
|
|
unsigned int has_target_luminance : 1;
|
|
unsigned int has_target_max_cll : 1;
|
|
unsigned int has_target_max_fall : 1;
|
|
};
|
|
|
|
static GdkColorState *
|
|
gdk_color_state_from_image_description_bits (ImageDescription *desc)
|
|
{
|
|
if (desc->has_primaries_named && desc->has_tf_named)
|
|
{
|
|
GdkCicp cicp;
|
|
|
|
cicp.color_primaries = wl_to_cicp_primaries (desc->primaries);
|
|
cicp.transfer_function = wl_to_cicp_transfer (desc->tf_named);
|
|
cicp.matrix_coefficients = 0;
|
|
cicp.range = GDK_CICP_RANGE_FULL;
|
|
|
|
return gdk_color_state_new_for_cicp (&cicp, NULL);
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
gdk_wayland_color_surface_clear_image_desc (GdkWaylandColorSurface *self)
|
|
{
|
|
ImageDescription *desc = self->current_desc;
|
|
|
|
if (desc == NULL)
|
|
return;
|
|
|
|
g_clear_pointer (&desc->image_desc, xx_image_description_v4_destroy);
|
|
g_clear_pointer (&desc->info, xx_image_description_info_v4_destroy);
|
|
g_free (desc);
|
|
|
|
self->current_desc = NULL;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_done (void *data,
|
|
struct xx_image_description_info_v4 *info)
|
|
{
|
|
ImageDescription *desc = data;
|
|
GdkWaylandColorSurface *self = desc->surface;
|
|
GdkColorState *cs;
|
|
|
|
g_assert (self->current_desc == desc);
|
|
|
|
cs = gdk_color_state_from_image_description_bits (desc);
|
|
if (cs)
|
|
{
|
|
g_hash_table_insert (self->color->id_to_cs,
|
|
GUINT_TO_POINTER (desc->identity),
|
|
gdk_color_state_ref (cs));
|
|
}
|
|
else
|
|
{
|
|
cs = GDK_COLOR_STATE_SRGB;
|
|
g_clear_pointer (&desc->image_desc, xx_image_description_v4_destroy);
|
|
}
|
|
|
|
if (self->callback)
|
|
self->callback (desc->surface, cs, self->data);
|
|
|
|
gdk_color_state_unref (cs);
|
|
|
|
gdk_wayland_color_surface_clear_image_desc (self);
|
|
}
|
|
|
|
static void
|
|
image_desc_info_icc_file (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
int32_t icc,
|
|
uint32_t icc_size)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->icc = icc;
|
|
desc->icc_size = icc_size;
|
|
desc->has_icc = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_primaries (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
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)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->r_x = r_x; desc->r_y = r_y;
|
|
desc->g_x = g_x; desc->r_y = g_y;
|
|
desc->b_x = b_x; desc->r_y = b_y;
|
|
desc->w_x = w_x; desc->r_y = w_y;
|
|
desc->has_primaries = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_primaries_named (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t primaries)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->primaries = primaries;
|
|
desc->has_primaries_named = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_tf_power (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t tf_power)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->tf_power = tf_power;
|
|
desc->has_tf_power = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_tf_named (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t tf)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->tf_named = tf;
|
|
desc->has_tf_named = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_luminances (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t min_lum,
|
|
uint32_t max_lum,
|
|
uint32_t ref_lum)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->min_lum = min_lum;
|
|
desc->max_lum = max_lum;
|
|
desc->ref_lum = ref_lum;
|
|
desc->has_luminances = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_target_primaries (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
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)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->target_r_x = r_x; desc->target_r_y = r_y;
|
|
desc->target_g_x = g_x; desc->target_r_y = g_y;
|
|
desc->target_b_x = b_x; desc->target_r_y = b_y;
|
|
desc->target_w_x = w_x; desc->target_r_y = w_y;
|
|
desc->has_target_primaries = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_target_luminance (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t min_lum,
|
|
uint32_t max_lum)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->target_min_lum = min_lum;
|
|
desc->target_max_lum = max_lum;
|
|
desc->has_target_luminance = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_target_max_cll (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t max_cll)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->target_max_cll = max_cll;
|
|
desc->has_target_max_cll = 1;
|
|
}
|
|
|
|
static void
|
|
image_desc_info_target_max_fall (void *data,
|
|
struct xx_image_description_info_v4 *info,
|
|
uint32_t max_fall)
|
|
{
|
|
ImageDescription *desc = data;
|
|
|
|
desc->target_max_fall = max_fall;
|
|
desc->has_target_max_fall = 1;
|
|
}
|
|
|
|
static struct xx_image_description_info_v4_listener info_listener = {
|
|
image_desc_info_done,
|
|
image_desc_info_icc_file,
|
|
image_desc_info_primaries,
|
|
image_desc_info_primaries_named,
|
|
image_desc_info_tf_power,
|
|
image_desc_info_tf_named,
|
|
image_desc_info_luminances,
|
|
image_desc_info_target_primaries,
|
|
image_desc_info_target_luminance,
|
|
image_desc_info_target_max_cll,
|
|
image_desc_info_target_max_fall,
|
|
};
|
|
|
|
static void
|
|
image_desc_failed (void *data,
|
|
struct xx_image_description_v4 *image_desc,
|
|
uint32_t cause,
|
|
const char *msg)
|
|
{
|
|
ImageDescription *desc = data;
|
|
GdkWaylandColorSurface *self = desc->surface;
|
|
|
|
g_assert (self->current_desc == desc);
|
|
|
|
self->callback (self, GDK_COLOR_STATE_SRGB, self->data);
|
|
|
|
gdk_wayland_color_surface_clear_image_desc (self);
|
|
}
|
|
|
|
static void
|
|
image_desc_ready (void *data,
|
|
struct xx_image_description_v4 *image_desc,
|
|
uint32_t identity)
|
|
{
|
|
ImageDescription *desc = data;
|
|
GdkWaylandColorSurface *self = desc->surface;
|
|
GdkColorState *cs;
|
|
|
|
g_assert (self->current_desc == desc);
|
|
|
|
cs = g_hash_table_lookup (self->color->id_to_cs, GUINT_TO_POINTER (identity));
|
|
if (cs)
|
|
{
|
|
self->callback (self, cs, self->data);
|
|
|
|
gdk_wayland_color_surface_clear_image_desc (self);
|
|
return;
|
|
}
|
|
|
|
desc->info = xx_image_description_v4_get_information (image_desc);
|
|
desc->identity = identity;
|
|
|
|
xx_image_description_info_v4_add_listener (desc->info, &info_listener, desc);
|
|
}
|
|
|
|
static const struct xx_image_description_v4_listener image_desc_listener = {
|
|
image_desc_failed,
|
|
image_desc_ready
|
|
};
|
|
|
|
static void
|
|
preferred_changed (void *data,
|
|
struct xx_color_management_feedback_surface_v4 *feedback)
|
|
{
|
|
GdkWaylandColorSurface *self = data;
|
|
ImageDescription *desc;
|
|
|
|
if (!self->callback)
|
|
return;
|
|
|
|
/* If there's still an ongoing query, cancel it. It's outdated. */
|
|
gdk_wayland_color_surface_clear_image_desc (self);
|
|
|
|
desc = g_new0 (ImageDescription, 1);
|
|
|
|
desc->surface = self;
|
|
self->current_desc = desc;
|
|
|
|
desc->image_desc = xx_color_management_feedback_surface_v4_get_preferred (self->feedback);
|
|
|
|
xx_image_description_v4_add_listener (desc->image_desc, &image_desc_listener, desc);
|
|
}
|
|
|
|
static const struct xx_color_management_feedback_surface_v4_listener color_listener = {
|
|
preferred_changed,
|
|
};
|
|
|
|
GdkWaylandColorSurface *
|
|
gdk_wayland_color_surface_new (GdkWaylandColor *color,
|
|
struct wl_surface *wl_surface,
|
|
GdkColorStateChanged callback,
|
|
gpointer data)
|
|
{
|
|
GdkWaylandColorSurface *self;
|
|
|
|
self = g_new0 (GdkWaylandColorSurface, 1);
|
|
|
|
self->color = color;
|
|
|
|
self->surface = xx_color_manager_v4_get_surface (color->color_manager, wl_surface);
|
|
self->feedback = xx_color_manager_v4_get_feedback_surface (color->color_manager, wl_surface);
|
|
|
|
self->callback = callback;
|
|
self->data = data;
|
|
|
|
xx_color_management_feedback_surface_v4_add_listener (self->feedback, &color_listener, self);
|
|
preferred_changed (self, self->feedback);
|
|
|
|
return self;
|
|
}
|
|
|
|
void
|
|
gdk_wayland_color_surface_free (GdkWaylandColorSurface *self)
|
|
{
|
|
gdk_wayland_color_surface_clear_image_desc (self);
|
|
|
|
xx_color_management_surface_v4_destroy (self->surface);
|
|
xx_color_management_feedback_surface_v4_destroy (self->feedback);
|
|
|
|
g_free (self);
|
|
}
|
|
|
|
static struct xx_image_description_v4 *
|
|
gdk_wayland_color_get_image_description (GdkWaylandColor *color,
|
|
GdkColorState *cs)
|
|
{
|
|
gpointer result;
|
|
|
|
if (g_hash_table_lookup_extended (color->cs_to_desc, cs, NULL, &result))
|
|
return result;
|
|
|
|
create_image_desc (color, cs, TRUE);
|
|
|
|
if (!g_hash_table_lookup_extended (color->cs_to_desc, cs, NULL, &result))
|
|
{
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
gdk_wayland_color_surface_set_color_state (GdkWaylandColorSurface *self,
|
|
GdkColorState *cs)
|
|
{
|
|
struct xx_image_description_v4 *desc;
|
|
|
|
desc = gdk_wayland_color_get_image_description (self->color, cs);
|
|
|
|
if (desc)
|
|
xx_color_management_surface_v4_set_image_description (self->surface,
|
|
desc,
|
|
XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
|
|
else
|
|
xx_color_management_surface_v4_unset_image_description (self->surface);
|
|
}
|
|
|
|
gboolean
|
|
gdk_wayland_color_surface_can_set_color_state (GdkWaylandColorSurface *self,
|
|
GdkColorState *cs)
|
|
{
|
|
return gdk_wayland_color_get_image_description (self->color, cs) != NULL;
|
|
}
|