Line data Source code
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/. */
5 :
6 : #include <gtk/gtk.h>
7 :
8 : #include "nsColor.h"
9 : #include "nsColorPicker.h"
10 : #include "nsGtkUtils.h"
11 : #include "nsIWidget.h"
12 : #include "WidgetUtils.h"
13 : #include "nsPIDOMWindow.h"
14 :
15 0 : NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
16 :
17 : #if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0)
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;
21 : }
22 :
23 : gdouble nsColorPicker::convertToGdkRgbaComponent(int color_component) {
24 : return color_component / 255.0;
25 : }
26 :
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)) };
32 :
33 : return result;
34 : }
35 : #else
36 0 : int nsColorPicker::convertGdkColorComponent(guint16 color_component) {
37 : // GdkColor value is in range [0..65535]. We need something in range [0..255]
38 0 : return (color_component * 255 + 127) / 65535;
39 : }
40 :
41 0 : guint16 nsColorPicker::convertToGdkColorComponent(int color_component) {
42 0 : return color_component * 65535 / 255;
43 : }
44 :
45 0 : GdkColor nsColorPicker::convertToGdkColor(nscolor color) {
46 : GdkColor result = { 0 /* obsolete, unused 'pixel' value */,
47 0 : convertToGdkColorComponent(NS_GET_R(color)),
48 0 : convertToGdkColorComponent(NS_GET_G(color)),
49 0 : convertToGdkColorComponent(NS_GET_B(color)) };
50 :
51 0 : return result;
52 : }
53 :
54 0 : GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget)
55 : {
56 0 : return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
57 : GTK_COLOR_SELECTION_DIALOG(widget)));
58 : }
59 : #endif
60 :
61 0 : NS_IMETHODIMP nsColorPicker::Init(mozIDOMWindowProxy *aParent,
62 : const nsAString& title,
63 : const nsAString& initialColor)
64 : {
65 0 : auto* parent = nsPIDOMWindowOuter::From(aParent);
66 0 : mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
67 0 : mTitle = title;
68 0 : mInitialColor = initialColor;
69 :
70 0 : return NS_OK;
71 : }
72 :
73 0 : NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShownCallback)
74 : {
75 :
76 : // Input color string should be 7 length (i.e. a string representing a valid
77 : // simple color)
78 0 : if (mInitialColor.Length() != 7) {
79 0 : return NS_ERROR_FAILURE;
80 : }
81 :
82 0 : const nsAString& withoutHash = StringTail(mInitialColor, 6);
83 : nscolor color;
84 0 : if (!NS_HexToRGBA(withoutHash, nsHexColorType::NoAlpha, &color)) {
85 0 : return NS_ERROR_FAILURE;
86 : }
87 :
88 0 : if (mCallback) {
89 : // It means Open has already been called: this is not allowed
90 0 : NS_WARNING("mCallback is already set. Open called twice?");
91 0 : return NS_ERROR_FAILURE;
92 : }
93 0 : mCallback = aColorPickerShownCallback;
94 :
95 0 : nsXPIDLCString title;
96 0 : title.Adopt(ToNewUTF8String(mTitle));
97 0 : GtkWindow *parent_window = GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
98 :
99 : #if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0)
100 : GtkWidget* color_chooser = gtk_color_chooser_dialog_new(title, parent_window);
101 :
102 : if (parent_window) {
103 : gtk_window_set_destroy_with_parent(GTK_WINDOW(color_chooser), TRUE);
104 : }
105 :
106 : gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_chooser), FALSE);
107 : GdkRGBA color_rgba = convertToRgbaColor(color);
108 : gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser),
109 : &color_rgba);
110 :
111 : g_signal_connect(GTK_COLOR_CHOOSER(color_chooser), "color-activated",
112 : G_CALLBACK(OnColorChanged), this);
113 : #else
114 0 : GtkWidget *color_chooser = gtk_color_selection_dialog_new(title);
115 :
116 0 : if (parent_window) {
117 0 : GtkWindow *window = GTK_WINDOW(color_chooser);
118 0 : gtk_window_set_transient_for(window, parent_window);
119 0 : gtk_window_set_destroy_with_parent(window, TRUE);
120 : }
121 :
122 0 : GdkColor color_gdk = convertToGdkColor(color);
123 0 : gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser),
124 0 : &color_gdk);
125 :
126 0 : g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed",
127 0 : G_CALLBACK(OnColorChanged), this);
128 : #endif
129 :
130 0 : NS_ADDREF_THIS();
131 :
132 0 : g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this);
133 0 : g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this);
134 0 : gtk_widget_show(color_chooser);
135 :
136 0 : return NS_OK;
137 : }
138 :
139 : #if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0)
140 : /* static */ void
141 : nsColorPicker::OnColorChanged(GtkColorChooser* color_chooser, GdkRGBA* color,
142 : gpointer user_data)
143 : {
144 : static_cast<nsColorPicker*>(user_data)->Update(color);
145 : }
146 :
147 : void
148 : nsColorPicker::Update(GdkRGBA* color)
149 : {
150 : SetColor(color);
151 : if (mCallback) {
152 : mCallback->Update(mColor);
153 : }
154 : }
155 :
156 : void nsColorPicker::SetColor(const GdkRGBA* color)
157 : {
158 : mColor.Assign('#');
159 : mColor += ToHexString(convertGdkRgbaComponent(color->red));
160 : mColor += ToHexString(convertGdkRgbaComponent(color->green));
161 : mColor += ToHexString(convertGdkRgbaComponent(color->blue));
162 : }
163 : #else
164 : /* static */ void
165 0 : nsColorPicker::OnColorChanged(GtkColorSelection* colorselection,
166 : gpointer user_data)
167 : {
168 0 : static_cast<nsColorPicker*>(user_data)->Update(colorselection);
169 0 : }
170 :
171 : void
172 0 : nsColorPicker::Update(GtkColorSelection* colorselection)
173 : {
174 0 : ReadValueFromColorSelection(colorselection);
175 0 : if (mCallback) {
176 0 : mCallback->Update(mColor);
177 : }
178 0 : }
179 :
180 0 : void nsColorPicker::ReadValueFromColorSelection(GtkColorSelection* colorselection)
181 : {
182 : GdkColor rgba;
183 0 : gtk_color_selection_get_current_color(colorselection, &rgba);
184 :
185 0 : mColor.Assign('#');
186 0 : mColor += ToHexString(convertGdkColorComponent(rgba.red));
187 0 : mColor += ToHexString(convertGdkColorComponent(rgba.green));
188 0 : mColor += ToHexString(convertGdkColorComponent(rgba.blue));
189 0 : }
190 : #endif
191 :
192 : /* static */ void
193 0 : nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id,
194 : gpointer user_data)
195 : {
196 : static_cast<nsColorPicker*>(user_data)->
197 0 : Done(color_chooser, response_id);
198 0 : }
199 :
200 : /* static */ void
201 0 : nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data)
202 : {
203 : static_cast<nsColorPicker*>(user_data)->
204 0 : Done(color_chooser, GTK_RESPONSE_CANCEL);
205 0 : }
206 :
207 : void
208 0 : nsColorPicker::Done(GtkWidget* color_chooser, gint response)
209 : {
210 0 : switch (response) {
211 : case GTK_RESPONSE_OK:
212 : case GTK_RESPONSE_ACCEPT:
213 : #if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0)
214 : GdkRGBA color;
215 : gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser), &color);
216 : SetColor(&color);
217 : #else
218 0 : ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser));
219 : #endif
220 0 : break;
221 : case GTK_RESPONSE_CANCEL:
222 : case GTK_RESPONSE_CLOSE:
223 : case GTK_RESPONSE_DELETE_EVENT:
224 0 : mColor = mInitialColor;
225 0 : break;
226 : default:
227 0 : NS_WARNING("Unexpected response");
228 0 : break;
229 : }
230 :
231 : // A "response" signal won't be sent again but "destroy" will be.
232 0 : g_signal_handlers_disconnect_by_func(color_chooser,
233 0 : FuncToGpointer(OnDestroy), this);
234 :
235 0 : gtk_widget_destroy(color_chooser);
236 0 : if (mCallback) {
237 0 : mCallback->Done(mColor);
238 0 : mCallback = nullptr;
239 : }
240 :
241 0 : NS_RELEASE_THIS();
242 0 : }
243 :
244 0 : nsString nsColorPicker::ToHexString(int n)
245 : {
246 0 : nsString result;
247 0 : if (n <= 0x0F) {
248 0 : result.Append('0');
249 : }
250 0 : result.AppendInt(n, 16);
251 0 : return result;
252 : }
|