diff --git a/gdk/gdk.h b/gdk/gdk.h index 3f10581bb2..f63867c555 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/gdk/gdkcolorstate.c b/gdk/gdkcolorstate.c new file mode 100644 index 0000000000..1970707d97 --- /dev/null +++ b/gdk/gdkcolorstate.c @@ -0,0 +1,183 @@ +/* gdkcolorstate.c + * + * Copyright 2024 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkcolorstateprivate.h" + +#include + +/** + * GdkColorState: + * + * A `GdkColorState` object provides the information to interpret + * colors and pixels in a variety of ways. + * + * They are also known as + * [*color spaces*](https://en.wikipedia.org/wiki/Color_space). + * + * Crucially, GTK knows how to convert colors from one color + * state to another. + * + * `GdkColorState objects are immutable and therefore threadsafe. + * + * Since 4.16 + */ + +G_DEFINE_BOXED_TYPE (GdkColorState, gdk_color_state, + gdk_color_state_ref, gdk_color_state_unref); + +/* {{{ Public API */ + +/** + * gdk_color_state_ref: + * @self: a `GdkColorState` + * + * Increase the reference count of @self. + * + * Returns: the object that was passed in + * + * Since: 4.16 + */ +GdkColorState * +(gdk_color_state_ref) (GdkColorState *self) +{ + return _gdk_color_state_ref (self); +} + +/** + * gdk_color_state_unref: + * @self:a `GdkColorState` + * + * Decrease the reference count of @self. + * + * Unless @self is static, it will be freed + * when the reference count reaches zero. + * + * Since: 4.16 + */ +void +(gdk_color_state_unref) (GdkColorState *self) +{ + _gdk_color_state_unref (self); +} + +/** + * gdk_color_state_get_srgb: + * + * Returns the color state object representing the sRGB color space. + * + * Since: 4.16 + */ +GdkColorState * +gdk_color_state_get_srgb (void) +{ + return GDK_COLOR_STATE_SRGB; +} + +/** + * gdk_color_state_get_srgb_linear: + * + * Returns the color state object representing the linearized sRGB color space. + * + * Since: 4.16 + */ +GdkColorState * +gdk_color_state_get_srgb_linear (void) +{ + return GDK_COLOR_STATE_SRGB_LINEAR; +} + +/** + * gdk_color_state_equal: + * @self: a `GdkColorState` + * @other: another `GdkColorStatee` + * + * Compares two `GdkColorStates` for equality. + * + * Note that this function is not guaranteed to be perfect and two objects + * describing the same color state may compare not equal. However, different + * color states will never compare equal. + * + * Returns: %TRUE if the two color states compare equal + * + * Since: 4.16 + */ +gboolean +(gdk_color_state_equal) (GdkColorState *self, + GdkColorState *other) +{ + return _gdk_color_state_equal (self, other); +} + +/* }}} */ +/* {{{ Default implementation */ + +static gboolean +gdk_default_color_state_equal (GdkColorState *self, + GdkColorState *other) +{ + return self == other; +} + +static const char * +gdk_default_color_state_get_name (GdkColorState *color_state) +{ + GdkDefaultColorState *self = (GdkDefaultColorState *) color_state; + + return self->name; +} + +static const +GdkColorStateClass GDK_DEFAULT_COLOR_STATE_CLASS = { + .free = NULL, /* crash here if this ever happens */ + .equal = gdk_default_color_state_equal, + .get_name = gdk_default_color_state_get_name, +}; + +GdkDefaultColorState gdk_default_color_states[] = { + [GDK_COLOR_STATE_ID_SRGB] = { + .parent = { + .klass = &GDK_DEFAULT_COLOR_STATE_CLASS, + .ref_count = 0, + .depth = GDK_MEMORY_U8, + }, + .name = "srgb", + }, + [GDK_COLOR_STATE_ID_SRGB_LINEAR] = { + .parent = { + .klass = &GDK_DEFAULT_COLOR_STATE_CLASS, + .ref_count = 0, + .depth = GDK_MEMORY_U8, + }, + .name = "srgb-linear", + }, +}; + +/* }}} */ +/* {{{ Private API */ + +const char * +gdk_color_state_get_name (GdkColorState *self) +{ + return self->klass->get_name (self); +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ diff --git a/gdk/gdkcolorstate.h b/gdk/gdkcolorstate.h new file mode 100644 index 0000000000..cfd51210ea --- /dev/null +++ b/gdk/gdkcolorstate.h @@ -0,0 +1,50 @@ +/* gdkcolorstate.h + * + * Copyright 2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define GDK_TYPE_COLOR_STATE (gdk_color_state_get_type ()) + +GDK_AVAILABLE_IN_4_16 +GType gdk_color_state_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_color_state_ref (GdkColorState *self); + +GDK_AVAILABLE_IN_4_16 +void gdk_color_state_unref (GdkColorState *self); + +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_color_state_get_srgb (void); + +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_color_state_get_srgb_linear (void); + +GDK_AVAILABLE_IN_4_16 +gboolean gdk_color_state_equal (GdkColorState *self, + GdkColorState *other); + +G_END_DECLS diff --git a/gdk/gdkcolorstateprivate.h b/gdk/gdkcolorstateprivate.h new file mode 100644 index 0000000000..ab0c502645 --- /dev/null +++ b/gdk/gdkcolorstateprivate.h @@ -0,0 +1,94 @@ +#pragma once + +#include "gdkcolorstate.h" +#include "gdkmemoryformatprivate.h" + +typedef enum +{ + GDK_COLOR_STATE_ID_SRGB, + GDK_COLOR_STATE_ID_SRGB_LINEAR, + + GDK_COLOR_STATE_N_IDS +} GdkColorStateId; + +typedef struct _GdkColorStateClass GdkColorStateClass; + +struct _GdkColorState +{ + const GdkColorStateClass *klass; + gatomicrefcount ref_count; + + GdkMemoryDepth depth; +}; + +struct _GdkColorStateClass +{ + void (* free) (GdkColorState *self); + gboolean (* equal) (GdkColorState *self, + GdkColorState *other); + const char * (* get_name) (GdkColorState *self); +}; + +typedef struct _GdkDefaultColorState GdkDefaultColorState; + +struct _GdkDefaultColorState +{ + GdkColorState parent; + + const char *name; +}; + +extern GdkDefaultColorState gdk_default_color_states[GDK_COLOR_STATE_N_IDS]; + +#define GDK_COLOR_STATE_SRGB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB]) +#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR]) + +#define GDK_IS_DEFAULT_COLOR_STATE(c) ((GdkDefaultColorState *) (c) >= &gdk_default_color_states[0] && \ + (GdkDefaultColorState *) (c) < &gdk_default_color_states[GDK_COLOR_STATE_N_IDS]) +#define GDK_DEFAULT_COLOR_STATE_ID(c) ((GdkColorStateId) (((GdkDefaultColorState *) c) - gdk_default_color_states)) + +const char * gdk_color_state_get_name (GdkColorState *color_state); + +static inline GdkMemoryDepth +gdk_color_state_get_depth (GdkColorState *self) +{ + return self->depth; +} + +#define gdk_color_state_ref(self) _gdk_color_state_ref (self) +static inline GdkColorState * +_gdk_color_state_ref (GdkColorState *self) +{ + if (GDK_IS_DEFAULT_COLOR_STATE (self)) + return self; + + g_atomic_ref_count_inc (&self->ref_count); + + return self; +} + +#define gdk_color_state_unref(self) _gdk_color_state_unref (self) +static inline void +_gdk_color_state_unref (GdkColorState *self) +{ + if (GDK_IS_DEFAULT_COLOR_STATE (self)) + return; + + if (g_atomic_ref_count_dec (&self->ref_count)) + self->klass->free (self); +} + +#define gdk_color_state_equal(a,b) _gdk_color_state_equal ((a), (b)) +static inline gboolean +_gdk_color_state_equal (GdkColorState *self, + GdkColorState *other) +{ + if (self == other) + return TRUE; + + if (self->klass != other->klass) + return FALSE; + + return self->klass->equal (self, other); +} + diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h index 1d77f92b86..af1e7e494b 100644 --- a/gdk/gdktypes.h +++ b/gdk/gdktypes.h @@ -74,6 +74,7 @@ typedef cairo_rectangle_int_t GdkRectangle; /* Forward declarations of commonly used types */ typedef struct _GdkRGBA GdkRGBA; +typedef struct _GdkColorState GdkColorState; typedef struct _GdkContentFormats GdkContentFormats; typedef struct _GdkContentProvider GdkContentProvider; typedef struct _GdkCursor GdkCursor; diff --git a/gdk/meson.build b/gdk/meson.build index 290e4f71d6..67cd1a0546 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -6,6 +6,7 @@ gdk_public_sources = files([ 'gdkcairo.c', 'gdkcairocontext.c', 'gdkclipboard.c', + 'gdkcolorstate.c', 'gdkcontentdeserializer.c', 'gdkcontentformats.c', 'gdkcontentprovider.c', @@ -76,6 +77,7 @@ gdk_public_headers = files([ 'gdkcairo.h', 'gdkcairocontext.h', 'gdkclipboard.h', + 'gdkcolorstate.h', 'gdkcontentdeserializer.h', 'gdkcontentformats.h', 'gdkcontentprovider.h', diff --git a/testsuite/gdk/colorstate.c b/testsuite/gdk/colorstate.c new file mode 100644 index 0000000000..0f402e653a --- /dev/null +++ b/testsuite/gdk/colorstate.c @@ -0,0 +1,25 @@ +#include + +static void +test_srgb (void) +{ + GdkColorState *srgb; + GdkColorState *srgb_linear; + + srgb = gdk_color_state_get_srgb (); + srgb_linear = gdk_color_state_get_srgb_linear (); + + g_assert_true (gdk_color_state_equal (srgb, srgb)); + g_assert_true (gdk_color_state_equal (srgb_linear, srgb_linear)); + g_assert_false (gdk_color_state_equal (srgb, srgb_linear)); +} + +int +main (int argc, char *argv[]) +{ + (g_test_init) (&argc, &argv, NULL); + + g_test_add_func ("/colorstate/srgb", test_srgb); + + return g_test_run (); +} diff --git a/testsuite/gdk/meson.build b/testsuite/gdk/meson.build index b6a9abd332..19259e30b0 100644 --- a/testsuite/gdk/meson.build +++ b/testsuite/gdk/meson.build @@ -57,6 +57,7 @@ foreach t : tests endforeach internal_tests = [ + { 'name': 'colorstate' }, { 'name': 'dihedral' }, { 'name': 'image' }, { 'name': 'texture' },