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/. */
8 #include "mozilla/Maybe.h"
9 #include "mozilla/dom/HTMLInputElement.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
))};
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
))};
58 GtkColorSelection
* nsColorPicker::WidgetGetColorSelection(GtkWidget
* widget
) {
59 return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
60 GTK_COLOR_SELECTION_DIALOG(widget
)));
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
);
71 mInitialColor
= initialColor
;
72 mDefaultColors
.Assign(aDefaultColors
);
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();
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
);
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);
125 GtkWidget
* color_chooser
= gtk_color_selection_dialog_new(title
.get());
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
),
140 g_signal_connect(WidgetGetColorSelection(color_chooser
), "color-changed",
141 G_CALLBACK(OnColorChanged
), 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
);
153 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
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
) {
163 mCallback
->Update(mColor
);
167 void nsColorPicker::SetColor(const GdkRGBA
* color
) {
169 mColor
+= ToHexString(convertGdkRgbaComponent(color
->red
));
170 mColor
+= ToHexString(convertGdkRgbaComponent(color
->green
));
171 mColor
+= ToHexString(convertGdkRgbaComponent(color
->blue
));
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
);
183 mCallback
->Update(mColor
);
187 void nsColorPicker::ReadValueFromColorSelection(
188 GtkColorSelection
* colorselection
) {
190 gtk_color_selection_get_current_color(colorselection
, &rgba
);
193 mColor
+= ToHexString(convertGdkColorComponent(rgba
.red
));
194 mColor
+= ToHexString(convertGdkColorComponent(rgba
.green
));
195 mColor
+= ToHexString(convertGdkColorComponent(rgba
.blue
));
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
);
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
) {
213 case GTK_RESPONSE_OK
:
214 case GTK_RESPONSE_ACCEPT
:
215 #if defined(ACTIVATE_GTK3_COLOR_PICKER)
217 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser
), &color
);
220 ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser
));
223 case GTK_RESPONSE_CANCEL
:
224 case GTK_RESPONSE_CLOSE
:
225 case GTK_RESPONSE_DELETE_EVENT
:
226 mColor
= mInitialColor
;
229 NS_WARNING("Unexpected response");
233 // A "response" signal won't be sent again but "destroy" will be.
234 g_signal_handlers_disconnect_by_func(color_chooser
, FuncToGpointer(OnDestroy
),
237 gtk_widget_destroy(color_chooser
);
239 mCallback
->Done(mColor
);
246 nsString
nsColorPicker::ToHexString(int n
) {
251 result
.AppendInt(n
, 16);