diff -r 000000000000 -r 6474c204b198 widget/gtk/nsColorPicker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widget/gtk/nsColorPicker.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,182 @@ +/* -*- 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 + +#include "nsColor.h" +#include "nsColorPicker.h" +#include "nsGtkUtils.h" +#include "nsIWidget.h" +#include "WidgetUtils.h" + +NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) + +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))); +} + +/* void init (in nsIDOMWindow parent, in AString title, in short mode); */ +NS_IMETHODIMP nsColorPicker::Init(nsIDOMWindow *parent, + const nsAString& title, + const nsAString& initialColor) +{ + mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent); + mTitle = title; + mInitialColor = initialColor; + + return NS_OK; +} + +/* void open (in nsIColorPickerShownCallback aColorPickerShownCallback); */ +NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShownCallback) +{ + + // Input color string should be 7 length (i.e. a string representing a valid + // simple color) + if (mInitialColor.Length() != 7) { + return NS_ERROR_FAILURE; + } + + const nsAString& withoutHash = StringTail(mInitialColor, 6); + nscolor color; + if (!NS_HexToRGB(withoutHash, &color)) { + return NS_ERROR_FAILURE; + } + + GdkColor color_gdk = convertToGdkColor(color); + + 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; + + nsXPIDLCString title; + title.Adopt(ToNewUTF8String(mTitle)); + GtkWidget *color_chooser = gtk_color_selection_dialog_new(title); + + GtkWindow *parent_window = GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)); + 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); + } + + gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser), + &color_gdk); + + NS_ADDREF_THIS(); + g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed", + G_CALLBACK(OnColorChanged), 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; +} + +/* static */ void +nsColorPicker::OnColorChanged(GtkColorSelection* colorselection, + gpointer user_data) +{ + static_cast(user_data)->Update(colorselection); +} + +/* static */ void +nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id, + gpointer user_data) +{ + static_cast(user_data)-> + Done(color_chooser, response_id); +} + +/* static */ void +nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) +{ + static_cast(user_data)-> + Done(color_chooser, GTK_RESPONSE_CANCEL); +} + +void +nsColorPicker::Update(GtkColorSelection* colorselection) +{ + ReadValueFromColorSelection(colorselection); + if (mCallback) { + mCallback->Update(mColor); + } +} + +void +nsColorPicker::Done(GtkWidget* color_chooser, gint response) +{ + switch (response) { + case GTK_RESPONSE_OK: + case GTK_RESPONSE_ACCEPT: + ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser)); + 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; +} + +void nsColorPicker::ReadValueFromColorSelection(GtkColorSelection* colorselection) +{ + GdkColor rgba; + gtk_color_selection_get_current_color(colorselection, &rgba); + + mColor.AssignLiteral("#"); + mColor += ToHexString(convertGdkColorComponent(rgba.red)); + mColor += ToHexString(convertGdkColorComponent(rgba.green)); + mColor += ToHexString(convertGdkColorComponent(rgba.blue)); +}