summaryrefslogtreecommitdiffstats
path: root/widget/gtk/nsColorPicker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/gtk/nsColorPicker.cpp')
-rw-r--r--widget/gtk/nsColorPicker.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/widget/gtk/nsColorPicker.cpp b/widget/gtk/nsColorPicker.cpp
new file mode 100644
index 0000000000..4719710d9e
--- /dev/null
+++ b/widget/gtk/nsColorPicker.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <gtk/gtk.h>
+
+#include "mozilla/Maybe.h"
+#include "mozilla/dom/HTMLInputElement.h"
+#include "nsColor.h"
+#include "nsColorPicker.h"
+#include "nsGtkUtils.h"
+#include "nsIWidget.h"
+#include "WidgetUtils.h"
+#include "nsPIDOMWindow.h"
+
+using mozilla::dom::HTMLInputElement;
+
+NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
+
+#if defined(ACTIVATE_GTK3_COLOR_PICKER)
+int nsColorPicker::convertGdkRgbaComponent(gdouble color_component) {
+ // GdkRGBA value is in range [0.0..1.0]. We need something in range [0..255]
+ return color_component * 255 + 0.5;
+}
+
+gdouble nsColorPicker::convertToGdkRgbaComponent(int color_component) {
+ return color_component / 255.0;
+}
+
+GdkRGBA nsColorPicker::convertToRgbaColor(nscolor color) {
+ GdkRGBA result = {convertToGdkRgbaComponent(NS_GET_R(color)),
+ convertToGdkRgbaComponent(NS_GET_G(color)),
+ convertToGdkRgbaComponent(NS_GET_B(color)),
+ convertToGdkRgbaComponent(NS_GET_A(color))};
+
+ return result;
+}
+#else
+int nsColorPicker::convertGdkColorComponent(guint16 color_component) {
+ // GdkColor value is in range [0..65535]. We need something in range [0..255]
+ return (color_component * 255 + 127) / 65535;
+}
+
+guint16 nsColorPicker::convertToGdkColorComponent(int color_component) {
+ return color_component * 65535 / 255;
+}
+
+GdkColor nsColorPicker::convertToGdkColor(nscolor color) {
+ GdkColor result = {0 /* obsolete, unused 'pixel' value */,
+ convertToGdkColorComponent(NS_GET_R(color)),
+ convertToGdkColorComponent(NS_GET_G(color)),
+ convertToGdkColorComponent(NS_GET_B(color))};
+
+ return result;
+}
+
+GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget) {
+ return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
+ GTK_COLOR_SELECTION_DIALOG(widget)));
+}
+#endif
+
+NS_IMETHODIMP nsColorPicker::Init(mozIDOMWindowProxy* aParent,
+ const nsAString& title,
+ const nsAString& initialColor,
+ const nsTArray<nsString>& aDefaultColors) {
+ auto* parent = nsPIDOMWindowOuter::From(aParent);
+ mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
+ mTitle = title;
+ mInitialColor = initialColor;
+ mDefaultColors.Assign(aDefaultColors);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsColorPicker::Open(
+ nsIColorPickerShownCallback* aColorPickerShownCallback) {
+ auto maybeColor = HTMLInputElement::ParseSimpleColor(mInitialColor);
+ if (maybeColor.isNothing()) {
+ return NS_ERROR_FAILURE;
+ }
+ nscolor color = maybeColor.value();
+
+ if (mCallback) {
+ // It means Open has already been called: this is not allowed
+ NS_WARNING("mCallback is already set. Open called twice?");
+ return NS_ERROR_FAILURE;
+ }
+ mCallback = aColorPickerShownCallback;
+
+ NS_ConvertUTF16toUTF8 title(mTitle);
+ GtkWindow* parent_window =
+ GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
+
+#if defined(ACTIVATE_GTK3_COLOR_PICKER)
+ GtkWidget* color_chooser =
+ gtk_color_chooser_dialog_new(title.get(), parent_window);
+
+ if (parent_window) {
+ GtkWindow* window = GTK_WINDOW(color_chooser);
+ gtk_window_set_destroy_with_parent(window, TRUE);
+ if (gtk_window_get_modal(parent_window)) {
+ gtk_window_set_modal(window, TRUE);
+ }
+ }
+
+ gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_chooser), FALSE);
+
+ // Setting the default colors will put them into "Custom" colors list.
+ for (const nsString& defaultColor : mDefaultColors) {
+ if (auto color = HTMLInputElement::ParseSimpleColor(defaultColor)) {
+ GdkRGBA color_rgba = convertToRgbaColor(*color);
+ gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser), &color_rgba);
+ }
+ }
+
+ // The initial color needs to be set last.
+ GdkRGBA color_rgba = convertToRgbaColor(color);
+ gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser), &color_rgba);
+
+ g_signal_connect(GTK_COLOR_CHOOSER(color_chooser), "color-activated",
+ G_CALLBACK(OnColorChanged), this);
+#else
+ GtkWidget* color_chooser = gtk_color_selection_dialog_new(title.get());
+
+ if (parent_window) {
+ GtkWindow* window = GTK_WINDOW(color_chooser);
+ gtk_window_set_transient_for(window, parent_window);
+ gtk_window_set_destroy_with_parent(window, TRUE);
+ if (gtk_window_get_modal(parent_window)) {
+ gtk_window_set_modal(window, TRUE);
+ }
+ }
+
+ GdkColor color_gdk = convertToGdkColor(color);
+ gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser),
+ &color_gdk);
+
+ g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed",
+ G_CALLBACK(OnColorChanged), this);
+#endif
+
+ NS_ADDREF_THIS();
+
+ g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this);
+ g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this);
+ gtk_widget_show(color_chooser);
+
+ return NS_OK;
+}
+
+#if defined(ACTIVATE_GTK3_COLOR_PICKER)
+/* static */
+void nsColorPicker::OnColorChanged(GtkColorChooser* color_chooser,
+ GdkRGBA* color, gpointer user_data) {
+ static_cast<nsColorPicker*>(user_data)->Update(color);
+}
+
+void nsColorPicker::Update(GdkRGBA* color) {
+ SetColor(color);
+ if (mCallback) {
+ mCallback->Update(mColor);
+ }
+}
+
+void nsColorPicker::SetColor(const GdkRGBA* color) {
+ mColor.Assign('#');
+ mColor += ToHexString(convertGdkRgbaComponent(color->red));
+ mColor += ToHexString(convertGdkRgbaComponent(color->green));
+ mColor += ToHexString(convertGdkRgbaComponent(color->blue));
+}
+#else
+/* static */
+void nsColorPicker::OnColorChanged(GtkColorSelection* colorselection,
+ gpointer user_data) {
+ static_cast<nsColorPicker*>(user_data)->Update(colorselection);
+}
+
+void nsColorPicker::Update(GtkColorSelection* colorselection) {
+ ReadValueFromColorSelection(colorselection);
+ if (mCallback) {
+ mCallback->Update(mColor);
+ }
+}
+
+void nsColorPicker::ReadValueFromColorSelection(
+ GtkColorSelection* colorselection) {
+ GdkColor rgba;
+ gtk_color_selection_get_current_color(colorselection, &rgba);
+
+ mColor.Assign('#');
+ mColor += ToHexString(convertGdkColorComponent(rgba.red));
+ mColor += ToHexString(convertGdkColorComponent(rgba.green));
+ mColor += ToHexString(convertGdkColorComponent(rgba.blue));
+}
+#endif
+
+/* static */
+void nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id,
+ gpointer user_data) {
+ static_cast<nsColorPicker*>(user_data)->Done(color_chooser, response_id);
+}
+
+/* static */
+void nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) {
+ static_cast<nsColorPicker*>(user_data)->Done(color_chooser,
+ GTK_RESPONSE_CANCEL);
+}
+
+void nsColorPicker::Done(GtkWidget* color_chooser, gint response) {
+ switch (response) {
+ case GTK_RESPONSE_OK:
+ case GTK_RESPONSE_ACCEPT:
+#if defined(ACTIVATE_GTK3_COLOR_PICKER)
+ GdkRGBA color;
+ gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser), &color);
+ SetColor(&color);
+#else
+ ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser));
+#endif
+ break;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_CLOSE:
+ case GTK_RESPONSE_DELETE_EVENT:
+ mColor = mInitialColor;
+ break;
+ default:
+ NS_WARNING("Unexpected response");
+ break;
+ }
+
+ // A "response" signal won't be sent again but "destroy" will be.
+ g_signal_handlers_disconnect_by_func(color_chooser, FuncToGpointer(OnDestroy),
+ this);
+
+ gtk_widget_destroy(color_chooser);
+ if (mCallback) {
+ mCallback->Done(mColor);
+ mCallback = nullptr;
+ }
+
+ NS_RELEASE_THIS();
+}
+
+nsString nsColorPicker::ToHexString(int n) {
+ nsString result;
+ if (n <= 0x0F) {
+ result.Append('0');
+ }
+ result.AppendInt(n, 16);
+ return result;
+}