static void
cdisplay_lcms_changed (GimpColorDisplay *display)
{
  CdisplayLcms     *lcms   = CDISPLAY_LCMS (display);
  GtkWidget        *widget = NULL;
  GimpColorConfig  *config;
  GimpColorManaged *managed;
  GimpColorProfile *src_profile;

  if (lcms->transform)
    {
      g_object_unref (lcms->transform);
      lcms->transform = NULL;
    }

  config  = gimp_color_display_get_config (display);
  managed = gimp_color_display_get_managed (display);

  if (! config || ! managed)
    return;

  if (GTK_IS_WIDGET (managed))
    widget = gtk_widget_get_toplevel (GTK_WIDGET (managed));

  src_profile = gimp_color_managed_get_color_profile (managed);

  lcms->transform =
    gimp_widget_get_color_transform (widget,
                                     config, src_profile,
                                     babl_format ("R'G'B'A float"),
                                     babl_format ("R'G'B'A float"));
}
static cmsHPROFILE
cdisplay_lcms_get_rgb_profile (CdisplayLcms *lcms)
{
  GimpColorConfig  *config;
  GimpColorManaged *managed;
  cmsHPROFILE       profile = NULL;

  managed = gimp_color_display_get_managed (GIMP_COLOR_DISPLAY (lcms));

  if (managed)
    {
      gsize         len;
      const guint8 *data = gimp_color_managed_get_icc_profile (managed, &len);

      if (data)
        profile = cmsOpenProfileFromMem ((gpointer) data, len);

      if (profile &&
          ! cdisplay_lcms_profile_is_rgb (profile))
        {
          cmsCloseProfile (profile);
          profile = NULL;
        }
    }

  if (! profile)
    {
      config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));

      if (config->rgb_profile)
        profile = cmsOpenProfileFromFile (config->rgb_profile, "r");
    }

  return profile;
}
static void
cdisplay_lcms_update_profile_label (CdisplayLcms *lcms,
                                    const gchar  *name)
{
  GimpColorConfig  *config;
  GimpColorManaged *managed;
  GtkWidget        *label;
  GimpColorProfile *profile = NULL;
  const gchar      *text;
  const gchar      *tooltip;

  config  = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));
  managed = gimp_color_display_get_managed (GIMP_COLOR_DISPLAY (lcms));

  label = g_object_get_data (G_OBJECT (lcms), name);

  if (! label)
    return;

  if (strcmp (name, "rgb-profile") == 0)
    {
      profile = gimp_color_managed_get_color_profile (managed);

      if (profile)
        g_object_ref (profile);
    }
  else if (g_str_has_prefix (name, "display-profile"))
    {
      profile = cdisplay_lcms_get_display_profile (lcms);
    }
  else if (strcmp (name, "printer-profile") == 0)
    {
      profile = gimp_color_config_get_simulation_color_profile (config, NULL);
    }
  else
    {
      g_return_if_reached ();
    }

  if (profile)
    {
      text    = gimp_color_profile_get_label (profile);
      tooltip = gimp_color_profile_get_summary (profile);
    }
  else
    {
      text    = _("None");
      tooltip = NULL;
    }

  gtk_label_set_text (GTK_LABEL (label), text);
  gimp_help_set_help_data (label, tooltip, NULL);

  if (profile)
    g_object_unref (profile);
}
static cmsHPROFILE
cdisplay_lcms_get_printer_profile (CdisplayLcms *lcms)
{
  GimpColorConfig *config;

  config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));

  if (config->printer_profile)
    return cmsOpenProfileFromFile (config->printer_profile, "r");

  return NULL;
}
static GimpColorProfile *
cdisplay_lcms_get_display_profile (CdisplayLcms *lcms)
{
  GimpColorConfig  *config;
  GimpColorManaged *managed;
  GtkWidget        *widget  = NULL;
  GimpColorProfile *profile = NULL;

  config  = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));
  managed = gimp_color_display_get_managed (GIMP_COLOR_DISPLAY (lcms));

  if (GTK_IS_WIDGET (managed))
    widget = gtk_widget_get_toplevel (GTK_WIDGET (managed));

  if (gimp_color_config_get_display_profile_from_gdk (config))
    profile = gimp_widget_get_color_profile (widget);

  if (! profile)
    profile = gimp_color_config_get_display_color_profile (config, NULL);

  return profile;
}
static cmsHPROFILE
cdisplay_lcms_get_display_profile (CdisplayLcms *lcms)
{
  GimpColorConfig *config;
  cmsHPROFILE      profile = NULL;

  config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));

#if defined GDK_WINDOWING_X11
  if (config->display_profile_from_gdk)
    {
      GdkScreen *screen;
      GdkAtom    type    = GDK_NONE;
      gint       format  = 0;
      gint       nitems  = 0;
      gint       monitor = 0;
      gchar     *atom_name;
      guchar    *data    = NULL;

      screen = cdisplay_lcms_get_screen (lcms, &monitor);

      if (monitor > 0)
        atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor);
      else
        atom_name = g_strdup ("_ICC_PROFILE");

      if (gdk_property_get (gdk_screen_get_root_window (screen),
                            gdk_atom_intern (atom_name, FALSE),
                            GDK_NONE,
                            0, 64 * 1024 * 1024, FALSE,
                            &type, &format, &nitems, &data) && nitems > 0)
        {
          profile = cmsOpenProfileFromMem (data, nitems);
          g_free (data);
        }

      g_free (atom_name);
    }

#elif defined GDK_WINDOWING_QUARTZ
  if (config->display_profile_from_gdk)
    {
      CMProfileRef  prof    = NULL;
      gint          monitor = 0;

      cdisplay_lcms_get_screen (lcms, &monitor);

      CMGetProfileByAVID (monitor, &prof);

      if (prof)
        {
          CFDataRef data;

          data = CMProfileCopyICCData (NULL, prof);
          CMCloseProfile (prof);

          if (data)
            {
              UInt8 *buffer = g_malloc (CFDataGetLength (data));

              /* We cannot use CFDataGetBytesPtr(), because that returns
               * a const pointer where cmsOpenProfileFromMem wants a
               * non-const pointer.
               */
              CFDataGetBytes (data, CFRangeMake (0, CFDataGetLength (data)),
                              buffer);

              profile = cmsOpenProfileFromMem (buffer, CFDataGetLength (data));

              g_free (buffer);
              CFRelease (data);
            }
        }
    }

#elif defined G_OS_WIN32
  if (config->display_profile_from_gdk)
    {
      HDC hdc = GetDC (NULL);

      if (hdc)
        {
          gchar *path;
          gint32 len = 0;

          GetICMProfile (hdc, &len, NULL);
          path = g_new (gchar, len);

          if (GetICMProfile (hdc, &len, path))
            profile = cmsOpenProfileFromFile (path, "r");

          g_free (path);
          ReleaseDC (NULL, hdc);
        }
    }
#endif

  if (! profile && config->display_profile)
    profile = cmsOpenProfileFromFile (config->display_profile, "r");

  return profile;
}
static void
cdisplay_lcms_changed (GimpColorDisplay *display)
{
  CdisplayLcms    *lcms   = CDISPLAY_LCMS (display);
  GimpColorConfig *config = gimp_color_display_get_config (display);

  cmsHPROFILE      src_profile   = NULL;
  cmsHPROFILE      dest_profile  = NULL;
  cmsHPROFILE      proof_profile = NULL;
  cmsUInt16Number  alarmCodes[cmsMAXCHANNELS] = { 0, };

  if (lcms->transform)
    {
      cmsDeleteTransform (lcms->transform);
      lcms->transform = NULL;
    }

  if (! config)
    return;

  switch (config->mode)
    {
    case GIMP_COLOR_MANAGEMENT_OFF:
      return;

    case GIMP_COLOR_MANAGEMENT_SOFTPROOF:
      proof_profile = cdisplay_lcms_get_printer_profile (lcms);
      /*  fallthru  */

    case GIMP_COLOR_MANAGEMENT_DISPLAY:
      src_profile = cdisplay_lcms_get_rgb_profile (lcms);
      dest_profile = cdisplay_lcms_get_display_profile (lcms);
      break;
    }

  if (proof_profile)
    {
      cmsUInt32Number softproof_flags = 0;

      if (! src_profile)
        src_profile = gimp_lcms_create_srgb_profile ();

      if (! dest_profile)
        dest_profile = gimp_lcms_create_srgb_profile ();

      softproof_flags |= cmsFLAGS_SOFTPROOFING;

      if (config->simulation_use_black_point_compensation)
        {
          softproof_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
        }

      if (config->simulation_gamut_check)
        {
          guchar r, g, b;

          softproof_flags |= cmsFLAGS_GAMUTCHECK;

          gimp_rgb_get_uchar (&config->out_of_gamut_color, &r, &g, &b);

          alarmCodes[0] = (cmsUInt16Number) r * 256;
          alarmCodes[1] = (cmsUInt16Number) g * 256;
          alarmCodes[2] = (cmsUInt16Number) b * 256;

          cmsSetAlarmCodes (alarmCodes);
        }

      lcms->transform = cmsCreateProofingTransform (src_profile,  TYPE_RGBA_FLT,
                                                    dest_profile, TYPE_RGBA_FLT,
                                                    proof_profile,
                                                    config->simulation_intent,
                                                    config->display_intent,
                                                    softproof_flags);
      cmsCloseProfile (proof_profile);
    }
  else if (src_profile || dest_profile)
    {
      cmsUInt32Number display_flags = 0;

      if (! src_profile)
        src_profile = gimp_lcms_create_srgb_profile ();

      if (! dest_profile)
        dest_profile = gimp_lcms_create_srgb_profile ();

      if (config->display_use_black_point_compensation)
        {
          display_flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
        }

      lcms->transform = cmsCreateTransform (src_profile,  TYPE_RGBA_FLT,
                                            dest_profile, TYPE_RGBA_FLT,
                                            config->display_intent,
                                            display_flags);
    }

  if (dest_profile)
    cmsCloseProfile (dest_profile);

  if (src_profile)
    cmsCloseProfile (src_profile);
}
static GtkWidget *
cdisplay_lcms_configure (GimpColorDisplay *display)
{
  CdisplayLcms *lcms   = CDISPLAY_LCMS (display);
  GObject      *config = G_OBJECT (gimp_color_display_get_config (display));
  GtkWidget    *vbox;
  GtkWidget    *hint;
  GtkWidget    *table;
  GtkWidget    *label;
  gint          row = 0;

  if (! config)
    return NULL;

  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);

  hint = gimp_hint_box_new (_("This filter takes its configuration "
                              "from the Color Management section "
                              "in the Preferences dialog."));
  gtk_box_pack_start (GTK_BOX (vbox), hint, FALSE, FALSE, 0);
  gtk_widget_show (hint);

  table = gtk_table_new (5, 2, FALSE);
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 12);
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  gtk_widget_show (table);

  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Mode of operation:"),
                                 gimp_prop_enum_label_new (config, "mode"));

  label = gtk_label_new (NULL);
  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
  g_object_set_data (G_OBJECT (lcms), "rgb-profile", label);
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Image profile:"),
                                 label);
  cdisplay_lcms_update_profile_label (lcms, "rgb-profile");

  label = gtk_label_new (NULL);
  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
  g_object_set_data (G_OBJECT (lcms), "display-profile", label);
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Monitor profile:"),
                                 label);
  cdisplay_lcms_update_profile_label (lcms, "display-profile");

  label = gtk_label_new (NULL);
  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
  g_object_set_data (G_OBJECT (lcms), "printer-profile", label);
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Print simulation profile:"),
                                 label);
  cdisplay_lcms_update_profile_label (lcms, "printer-profile");

  g_signal_connect_object (config, "notify",
                           G_CALLBACK (cdisplay_lcms_notify_profile),
                           lcms, 0);

  return vbox;
}