michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: michael@0: #include "nsColor.h" michael@0: #include "nsColorPicker.h" michael@0: #include "nsGtkUtils.h" michael@0: #include "nsIWidget.h" michael@0: #include "WidgetUtils.h" michael@0: michael@0: NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) michael@0: michael@0: int nsColorPicker::convertGdkColorComponent(guint16 color_component) { michael@0: // GdkColor value is in range [0..65535]. We need something in range [0..255] michael@0: return (color_component * 255 + 127) / 65535; michael@0: } michael@0: michael@0: guint16 nsColorPicker::convertToGdkColorComponent(int color_component) { michael@0: return color_component * 65535 / 255; michael@0: } michael@0: michael@0: GdkColor nsColorPicker::convertToGdkColor(nscolor color) { michael@0: GdkColor result = { 0 /* obsolete, unused 'pixel' value */, michael@0: convertToGdkColorComponent(NS_GET_R(color)), michael@0: convertToGdkColorComponent(NS_GET_G(color)), michael@0: convertToGdkColorComponent(NS_GET_B(color)) }; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget) michael@0: { michael@0: return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection( michael@0: GTK_COLOR_SELECTION_DIALOG(widget))); michael@0: } michael@0: michael@0: /* void init (in nsIDOMWindow parent, in AString title, in short mode); */ michael@0: NS_IMETHODIMP nsColorPicker::Init(nsIDOMWindow *parent, michael@0: const nsAString& title, michael@0: const nsAString& initialColor) michael@0: { michael@0: mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent); michael@0: mTitle = title; michael@0: mInitialColor = initialColor; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void open (in nsIColorPickerShownCallback aColorPickerShownCallback); */ michael@0: NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShownCallback) michael@0: { michael@0: michael@0: // Input color string should be 7 length (i.e. a string representing a valid michael@0: // simple color) michael@0: if (mInitialColor.Length() != 7) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: const nsAString& withoutHash = StringTail(mInitialColor, 6); michael@0: nscolor color; michael@0: if (!NS_HexToRGB(withoutHash, &color)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: GdkColor color_gdk = convertToGdkColor(color); michael@0: michael@0: if (mCallback) { michael@0: // It means Open has already been called: this is not allowed michael@0: NS_WARNING("mCallback is already set. Open called twice?"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: mCallback = aColorPickerShownCallback; michael@0: michael@0: nsXPIDLCString title; michael@0: title.Adopt(ToNewUTF8String(mTitle)); michael@0: GtkWidget *color_chooser = gtk_color_selection_dialog_new(title); michael@0: michael@0: GtkWindow *parent_window = GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)); michael@0: if (parent_window) { michael@0: GtkWindow *window = GTK_WINDOW(color_chooser); michael@0: gtk_window_set_transient_for(window, parent_window); michael@0: gtk_window_set_destroy_with_parent(window, TRUE); michael@0: } michael@0: michael@0: gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser), michael@0: &color_gdk); michael@0: michael@0: NS_ADDREF_THIS(); michael@0: g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed", michael@0: G_CALLBACK(OnColorChanged), this); michael@0: g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this); michael@0: g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this); michael@0: gtk_widget_show(color_chooser); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* static */ void michael@0: nsColorPicker::OnColorChanged(GtkColorSelection* colorselection, michael@0: gpointer user_data) michael@0: { michael@0: static_cast(user_data)->Update(colorselection); michael@0: } michael@0: michael@0: /* static */ void michael@0: nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id, michael@0: gpointer user_data) michael@0: { michael@0: static_cast(user_data)-> michael@0: Done(color_chooser, response_id); michael@0: } michael@0: michael@0: /* static */ void michael@0: nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) michael@0: { michael@0: static_cast(user_data)-> michael@0: Done(color_chooser, GTK_RESPONSE_CANCEL); michael@0: } michael@0: michael@0: void michael@0: nsColorPicker::Update(GtkColorSelection* colorselection) michael@0: { michael@0: ReadValueFromColorSelection(colorselection); michael@0: if (mCallback) { michael@0: mCallback->Update(mColor); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsColorPicker::Done(GtkWidget* color_chooser, gint response) michael@0: { michael@0: switch (response) { michael@0: case GTK_RESPONSE_OK: michael@0: case GTK_RESPONSE_ACCEPT: michael@0: ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser)); michael@0: break; michael@0: case GTK_RESPONSE_CANCEL: michael@0: case GTK_RESPONSE_CLOSE: michael@0: case GTK_RESPONSE_DELETE_EVENT: michael@0: mColor = mInitialColor; michael@0: break; michael@0: default: michael@0: NS_WARNING("Unexpected response"); michael@0: break; michael@0: } michael@0: michael@0: // A "response" signal won't be sent again but "destroy" will be. michael@0: g_signal_handlers_disconnect_by_func(color_chooser, michael@0: FuncToGpointer(OnDestroy), this); michael@0: michael@0: gtk_widget_destroy(color_chooser); michael@0: if (mCallback) { michael@0: mCallback->Done(mColor); michael@0: mCallback = nullptr; michael@0: } michael@0: michael@0: NS_RELEASE_THIS(); michael@0: } michael@0: michael@0: nsString nsColorPicker::ToHexString(int n) michael@0: { michael@0: nsString result; michael@0: if (n <= 0x0F) { michael@0: result.Append('0'); michael@0: } michael@0: result.AppendInt(n, 16); michael@0: return result; michael@0: } michael@0: michael@0: void nsColorPicker::ReadValueFromColorSelection(GtkColorSelection* colorselection) michael@0: { michael@0: GdkColor rgba; michael@0: gtk_color_selection_get_current_color(colorselection, &rgba); michael@0: michael@0: mColor.AssignLiteral("#"); michael@0: mColor += ToHexString(convertGdkColorComponent(rgba.red)); michael@0: mColor += ToHexString(convertGdkColorComponent(rgba.green)); michael@0: mColor += ToHexString(convertGdkColorComponent(rgba.blue)); michael@0: }