Bug 1869647 - Mark hasStorageAccess.sub.https.window.html as intermittent after wpt...
[gecko.git] / widget / gtk / nsColorPicker.cpp
blob4719710d9ebbca02380249e1e9594c4aa4ddc292
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 "mozilla/Maybe.h"
9 #include "mozilla/dom/HTMLInputElement.h"
10 #include "nsColor.h"
11 #include "nsColorPicker.h"
12 #include "nsGtkUtils.h"
13 #include "nsIWidget.h"
14 #include "WidgetUtils.h"
15 #include "nsPIDOMWindow.h"
17 using mozilla::dom::HTMLInputElement;
19 NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
21 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
22 int nsColorPicker::convertGdkRgbaComponent(gdouble color_component) {
23 // GdkRGBA value is in range [0.0..1.0]. We need something in range [0..255]
24 return color_component * 255 + 0.5;
27 gdouble nsColorPicker::convertToGdkRgbaComponent(int color_component) {
28 return color_component / 255.0;
31 GdkRGBA nsColorPicker::convertToRgbaColor(nscolor color) {
32 GdkRGBA result = {convertToGdkRgbaComponent(NS_GET_R(color)),
33 convertToGdkRgbaComponent(NS_GET_G(color)),
34 convertToGdkRgbaComponent(NS_GET_B(color)),
35 convertToGdkRgbaComponent(NS_GET_A(color))};
37 return result;
39 #else
40 int nsColorPicker::convertGdkColorComponent(guint16 color_component) {
41 // GdkColor value is in range [0..65535]. We need something in range [0..255]
42 return (color_component * 255 + 127) / 65535;
45 guint16 nsColorPicker::convertToGdkColorComponent(int color_component) {
46 return color_component * 65535 / 255;
49 GdkColor nsColorPicker::convertToGdkColor(nscolor color) {
50 GdkColor result = {0 /* obsolete, unused 'pixel' value */,
51 convertToGdkColorComponent(NS_GET_R(color)),
52 convertToGdkColorComponent(NS_GET_G(color)),
53 convertToGdkColorComponent(NS_GET_B(color))};
55 return result;
58 GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget) {
59 return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
60 GTK_COLOR_SELECTION_DIALOG(widget)));
62 #endif
64 NS_IMETHODIMP nsColorPicker::Init(mozIDOMWindowProxy* aParent,
65 const nsAString& title,
66 const nsAString& initialColor,
67 const nsTArray<nsString>& aDefaultColors) {
68 auto* parent = nsPIDOMWindowOuter::From(aParent);
69 mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
70 mTitle = title;
71 mInitialColor = initialColor;
72 mDefaultColors.Assign(aDefaultColors);
74 return NS_OK;
77 NS_IMETHODIMP nsColorPicker::Open(
78 nsIColorPickerShownCallback* aColorPickerShownCallback) {
79 auto maybeColor = HTMLInputElement::ParseSimpleColor(mInitialColor);
80 if (maybeColor.isNothing()) {
81 return NS_ERROR_FAILURE;
83 nscolor color = maybeColor.value();
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);
110 // Setting the default colors will put them into "Custom" colors list.
111 for (const nsString& defaultColor : mDefaultColors) {
112 if (auto color = HTMLInputElement::ParseSimpleColor(defaultColor)) {
113 GdkRGBA color_rgba = convertToRgbaColor(*color);
114 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser), &color_rgba);
118 // The initial color needs to be set last.
119 GdkRGBA color_rgba = convertToRgbaColor(color);
120 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser), &color_rgba);
122 g_signal_connect(GTK_COLOR_CHOOSER(color_chooser), "color-activated",
123 G_CALLBACK(OnColorChanged), this);
124 #else
125 GtkWidget* color_chooser = gtk_color_selection_dialog_new(title.get());
127 if (parent_window) {
128 GtkWindow* window = GTK_WINDOW(color_chooser);
129 gtk_window_set_transient_for(window, parent_window);
130 gtk_window_set_destroy_with_parent(window, TRUE);
131 if (gtk_window_get_modal(parent_window)) {
132 gtk_window_set_modal(window, TRUE);
136 GdkColor color_gdk = convertToGdkColor(color);
137 gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser),
138 &color_gdk);
140 g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed",
141 G_CALLBACK(OnColorChanged), this);
142 #endif
144 NS_ADDREF_THIS();
146 g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this);
147 g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this);
148 gtk_widget_show(color_chooser);
150 return NS_OK;
153 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
154 /* static */
155 void nsColorPicker::OnColorChanged(GtkColorChooser* color_chooser,
156 GdkRGBA* color, gpointer user_data) {
157 static_cast<nsColorPicker*>(user_data)->Update(color);
160 void nsColorPicker::Update(GdkRGBA* color) {
161 SetColor(color);
162 if (mCallback) {
163 mCallback->Update(mColor);
167 void nsColorPicker::SetColor(const GdkRGBA* color) {
168 mColor.Assign('#');
169 mColor += ToHexString(convertGdkRgbaComponent(color->red));
170 mColor += ToHexString(convertGdkRgbaComponent(color->green));
171 mColor += ToHexString(convertGdkRgbaComponent(color->blue));
173 #else
174 /* static */
175 void nsColorPicker::OnColorChanged(GtkColorSelection* colorselection,
176 gpointer user_data) {
177 static_cast<nsColorPicker*>(user_data)->Update(colorselection);
180 void nsColorPicker::Update(GtkColorSelection* colorselection) {
181 ReadValueFromColorSelection(colorselection);
182 if (mCallback) {
183 mCallback->Update(mColor);
187 void nsColorPicker::ReadValueFromColorSelection(
188 GtkColorSelection* colorselection) {
189 GdkColor rgba;
190 gtk_color_selection_get_current_color(colorselection, &rgba);
192 mColor.Assign('#');
193 mColor += ToHexString(convertGdkColorComponent(rgba.red));
194 mColor += ToHexString(convertGdkColorComponent(rgba.green));
195 mColor += ToHexString(convertGdkColorComponent(rgba.blue));
197 #endif
199 /* static */
200 void nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id,
201 gpointer user_data) {
202 static_cast<nsColorPicker*>(user_data)->Done(color_chooser, response_id);
205 /* static */
206 void nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) {
207 static_cast<nsColorPicker*>(user_data)->Done(color_chooser,
208 GTK_RESPONSE_CANCEL);
211 void nsColorPicker::Done(GtkWidget* color_chooser, gint response) {
212 switch (response) {
213 case GTK_RESPONSE_OK:
214 case GTK_RESPONSE_ACCEPT:
215 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
216 GdkRGBA color;
217 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser), &color);
218 SetColor(&color);
219 #else
220 ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser));
221 #endif
222 break;
223 case GTK_RESPONSE_CANCEL:
224 case GTK_RESPONSE_CLOSE:
225 case GTK_RESPONSE_DELETE_EVENT:
226 mColor = mInitialColor;
227 break;
228 default:
229 NS_WARNING("Unexpected response");
230 break;
233 // A "response" signal won't be sent again but "destroy" will be.
234 g_signal_handlers_disconnect_by_func(color_chooser, FuncToGpointer(OnDestroy),
235 this);
237 gtk_widget_destroy(color_chooser);
238 if (mCallback) {
239 mCallback->Done(mColor);
240 mCallback = nullptr;
243 NS_RELEASE_THIS();
246 nsString nsColorPicker::ToHexString(int n) {
247 nsString result;
248 if (n <= 0x0F) {
249 result.Append('0');
251 result.AppendInt(n, 16);
252 return result;