Bug 1751217 Part 3: Make HDR-capable macOS screens report 30 pixelDepth. r=mstange
[gecko.git] / widget / gtk / nsColorPicker.cpp
bloba2e461d8cf9bc47402a0f933885d8cdb3b1a30c5
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <gtk/gtk.h>
8 #include "nsColor.h"
9 #include "nsColorPicker.h"
10 #include "nsGtkUtils.h"
11 #include "nsIWidget.h"
12 #include "WidgetUtils.h"
13 #include "nsPIDOMWindow.h"
15 NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
17 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
18 int nsColorPicker::convertGdkRgbaComponent(gdouble color_component) {
19 // GdkRGBA value is in range [0.0..1.0]. We need something in range [0..255]
20 return color_component * 255 + 0.5;
23 gdouble nsColorPicker::convertToGdkRgbaComponent(int color_component) {
24 return color_component / 255.0;
27 GdkRGBA nsColorPicker::convertToRgbaColor(nscolor color) {
28 GdkRGBA result = {convertToGdkRgbaComponent(NS_GET_R(color)),
29 convertToGdkRgbaComponent(NS_GET_G(color)),
30 convertToGdkRgbaComponent(NS_GET_B(color)),
31 convertToGdkRgbaComponent(NS_GET_A(color))};
33 return result;
35 #else
36 int nsColorPicker::convertGdkColorComponent(guint16 color_component) {
37 // GdkColor value is in range [0..65535]. We need something in range [0..255]
38 return (color_component * 255 + 127) / 65535;
41 guint16 nsColorPicker::convertToGdkColorComponent(int color_component) {
42 return color_component * 65535 / 255;
45 GdkColor nsColorPicker::convertToGdkColor(nscolor color) {
46 GdkColor result = {0 /* obsolete, unused 'pixel' value */,
47 convertToGdkColorComponent(NS_GET_R(color)),
48 convertToGdkColorComponent(NS_GET_G(color)),
49 convertToGdkColorComponent(NS_GET_B(color))};
51 return result;
54 GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget) {
55 return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
56 GTK_COLOR_SELECTION_DIALOG(widget)));
58 #endif
60 NS_IMETHODIMP nsColorPicker::Init(mozIDOMWindowProxy* aParent,
61 const nsAString& title,
62 const nsAString& initialColor) {
63 auto* parent = nsPIDOMWindowOuter::From(aParent);
64 mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
65 mTitle = title;
66 mInitialColor = initialColor;
68 return NS_OK;
71 NS_IMETHODIMP nsColorPicker::Open(
72 nsIColorPickerShownCallback* aColorPickerShownCallback) {
73 // Input color string should be 7 length (i.e. a string representing a valid
74 // simple color)
75 if (mInitialColor.Length() != 7) {
76 return NS_ERROR_FAILURE;
79 const nsAString& withoutHash = StringTail(mInitialColor, 6);
80 nscolor color;
81 if (!NS_HexToRGBA(withoutHash, nsHexColorType::NoAlpha, &color)) {
82 return NS_ERROR_FAILURE;
85 if (mCallback) {
86 // It means Open has already been called: this is not allowed
87 NS_WARNING("mCallback is already set. Open called twice?");
88 return NS_ERROR_FAILURE;
90 mCallback = aColorPickerShownCallback;
92 NS_ConvertUTF16toUTF8 title(mTitle);
93 GtkWindow* parent_window =
94 GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
96 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
97 GtkWidget* color_chooser =
98 gtk_color_chooser_dialog_new(title.get(), parent_window);
100 if (parent_window) {
101 GtkWindow* window = GTK_WINDOW(color_chooser);
102 gtk_window_set_destroy_with_parent(window, TRUE);
103 if (gtk_window_get_modal(parent_window)) {
104 gtk_window_set_modal(window, TRUE);
108 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_chooser), FALSE);
109 GdkRGBA color_rgba = convertToRgbaColor(color);
110 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser), &color_rgba);
112 g_signal_connect(GTK_COLOR_CHOOSER(color_chooser), "color-activated",
113 G_CALLBACK(OnColorChanged), this);
114 #else
115 GtkWidget* color_chooser = gtk_color_selection_dialog_new(title.get());
117 if (parent_window) {
118 GtkWindow* window = GTK_WINDOW(color_chooser);
119 gtk_window_set_transient_for(window, parent_window);
120 gtk_window_set_destroy_with_parent(window, TRUE);
121 if (gtk_window_get_modal(parent_window)) {
122 gtk_window_set_modal(window, TRUE);
126 GdkColor color_gdk = convertToGdkColor(color);
127 gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser),
128 &color_gdk);
130 g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed",
131 G_CALLBACK(OnColorChanged), this);
132 #endif
134 NS_ADDREF_THIS();
136 g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this);
137 g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this);
138 gtk_widget_show(color_chooser);
140 return NS_OK;
143 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
144 /* static */
145 void nsColorPicker::OnColorChanged(GtkColorChooser* color_chooser,
146 GdkRGBA* color, gpointer user_data) {
147 static_cast<nsColorPicker*>(user_data)->Update(color);
150 void nsColorPicker::Update(GdkRGBA* color) {
151 SetColor(color);
152 if (mCallback) {
153 mCallback->Update(mColor);
157 void nsColorPicker::SetColor(const GdkRGBA* color) {
158 mColor.Assign('#');
159 mColor += ToHexString(convertGdkRgbaComponent(color->red));
160 mColor += ToHexString(convertGdkRgbaComponent(color->green));
161 mColor += ToHexString(convertGdkRgbaComponent(color->blue));
163 #else
164 /* static */
165 void nsColorPicker::OnColorChanged(GtkColorSelection* colorselection,
166 gpointer user_data) {
167 static_cast<nsColorPicker*>(user_data)->Update(colorselection);
170 void nsColorPicker::Update(GtkColorSelection* colorselection) {
171 ReadValueFromColorSelection(colorselection);
172 if (mCallback) {
173 mCallback->Update(mColor);
177 void nsColorPicker::ReadValueFromColorSelection(
178 GtkColorSelection* colorselection) {
179 GdkColor rgba;
180 gtk_color_selection_get_current_color(colorselection, &rgba);
182 mColor.Assign('#');
183 mColor += ToHexString(convertGdkColorComponent(rgba.red));
184 mColor += ToHexString(convertGdkColorComponent(rgba.green));
185 mColor += ToHexString(convertGdkColorComponent(rgba.blue));
187 #endif
189 /* static */
190 void nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id,
191 gpointer user_data) {
192 static_cast<nsColorPicker*>(user_data)->Done(color_chooser, response_id);
195 /* static */
196 void nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) {
197 static_cast<nsColorPicker*>(user_data)->Done(color_chooser,
198 GTK_RESPONSE_CANCEL);
201 void nsColorPicker::Done(GtkWidget* color_chooser, gint response) {
202 switch (response) {
203 case GTK_RESPONSE_OK:
204 case GTK_RESPONSE_ACCEPT:
205 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
206 GdkRGBA color;
207 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser), &color);
208 SetColor(&color);
209 #else
210 ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser));
211 #endif
212 break;
213 case GTK_RESPONSE_CANCEL:
214 case GTK_RESPONSE_CLOSE:
215 case GTK_RESPONSE_DELETE_EVENT:
216 mColor = mInitialColor;
217 break;
218 default:
219 NS_WARNING("Unexpected response");
220 break;
223 // A "response" signal won't be sent again but "destroy" will be.
224 g_signal_handlers_disconnect_by_func(color_chooser, FuncToGpointer(OnDestroy),
225 this);
227 gtk_widget_destroy(color_chooser);
228 if (mCallback) {
229 mCallback->Done(mColor);
230 mCallback = nullptr;
233 NS_RELEASE_THIS();
236 nsString nsColorPicker::ToHexString(int n) {
237 nsString result;
238 if (n <= 0x0F) {
239 result.Append('0');
241 result.AppendInt(n, 16);
242 return result;