Bug 875753 - Color input: Gtk widget. r=karlt

This commit is contained in:
Arnaud Bienner 2013-06-22 15:39:43 +02:00
parent fd8eb7c308
commit 70bdf3b468
11 changed files with 279 additions and 36 deletions

View File

@ -91,10 +91,10 @@ static int ComponentValue(const PRUnichar* aColorSpec, int aLen, int color, int
return component;
}
NS_GFX_(bool) NS_HexToRGB(const nsString& aColorSpec,
NS_GFX_(bool) NS_HexToRGB(const nsAString& aColorSpec,
nscolor* aResult)
{
const PRUnichar* buffer = aColorSpec.get();
const PRUnichar* buffer = aColorSpec.BeginReading();
int nameLen = aColorSpec.Length();
if ((nameLen == 3) || (nameLen == 6)) {

View File

@ -48,7 +48,7 @@ typedef uint32_t nscolor;
// Translate a hex string to a color. Return true if it parses ok,
// otherwise return false.
// This accepts only 3 or 6 digits
NS_GFX_(bool) NS_HexToRGB(const nsString& aBuf, nscolor* aResult);
NS_GFX_(bool) NS_HexToRGB(const nsAString& aBuf, nscolor* aResult);
// Compose one NS_RGB color onto another. The result is what
// you get if you draw aFG on top of aBG with operator OVER.

View File

@ -0,0 +1,17 @@
#ifndef GTKCOLORSELECTIONDIALOG_WRAPPER_H
#define GTKCOLORSELECTIONDIALOG_WRAPPER_H
#include_next <gtk/gtkselection.h>
#include <gtk/gtkversion.h>
#if !GTK_CHECK_VERSION(2, 14, 0)
static inline GtkWidget*
gtk_color_selection_dialog_get_color_selection(GtkColorSelectionDialog* colorseldialog)
{
GtkWidget* colorsel;
g_object_get(colorseldialog, "color-selection", &colorsel, NULL);
return colorsel;
}
#endif // GTK_CHECK_VERSION
#endif // GTKCOLORSELECTIONDIALOG_WRAPPER_H

View File

@ -16,6 +16,7 @@ CPP_SOURCES += [
'WidgetTraceEvent.cpp',
'nsAppShell.cpp',
'nsBidiKeyboard.cpp',
'nsColorPicker.cpp',
'nsFilePicker.cpp',
'nsGtkIMModule.cpp',
'nsGtkKeyUtils.cpp',

View File

@ -0,0 +1,161 @@
/* -*- 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/Util.h"
#include "nsColor.h"
#include "nsColorPicker.h"
#include "nsGtkUtils.h"
#include "nsIWidget.h"
#include "WidgetUtils.h"
NS_IMPL_ISUPPORTS1(nsColorPicker, nsIColorPicker)
int nsColorPicker::convertGdkColorComponent(guint16 color_component) {
// GdkColor value is in range [0..65535]. We need something in range [0..255]
return (int(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;
}
/* void init (in nsIDOMWindow parent, in AString title, in short mode); */
NS_IMETHODIMP nsColorPicker::Init(nsIDOMWindow *parent,
const nsAString& title,
const nsAString& initialColor)
{
// Input color string should be 7 length (i.e. a string representing a valid
// simple color)
if (initialColor.Length() != 7) {
return NS_ERROR_INVALID_ARG;
}
const nsAString& withoutHash = StringTail(initialColor, 6);
nscolor color;
if (!NS_HexToRGB(withoutHash, &color)) {
return NS_ERROR_INVALID_ARG;
}
mDefaultColor = convertToGdkColor(color);
mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
mTitle.Assign(title);
return NS_OK;
}
/* void open (in nsIColorPickerShownCallback aColorPickerShownCallback); */
NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShownCallback)
{
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(
GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
GTK_COLOR_SELECTION_DIALOG(color_chooser))),
&mDefaultColor);
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;
}
/* 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:
ReadValueFromColorChooser(color_chooser);
break;
case GTK_RESPONSE_CANCEL:
case GTK_RESPONSE_CLOSE:
case GTK_RESPONSE_DELETE_EVENT:
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::ReadValueFromColorChooser(GtkWidget* color_chooser)
{
GdkColor rgba;
gtk_color_selection_get_current_color(
GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(
GTK_COLOR_SELECTION_DIALOG(color_chooser))),
&rgba);
mColor.AssignLiteral("#");
mColor += ToHexString(convertGdkColorComponent(rgba.red));
mColor += ToHexString(convertGdkColorComponent(rgba.green));
mColor += ToHexString(convertGdkColorComponent(rgba.blue));
}

View File

@ -0,0 +1,48 @@
/* -*- 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/. */
#ifndef nsColorPicker_h__
#define nsColorPicker_h__
#include <gtk/gtk.h>
#include "nsCOMPtr.h"
#include "nsIColorPicker.h"
#include "nsString.h"
class nsIWidget;
class nsColorPicker : public nsIColorPicker
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICOLORPICKER
nsColorPicker() {};
private:
~nsColorPicker() {};
static void OnResponse(GtkWidget* dialog, gint response_id,
gpointer user_data);
static void OnDestroy(GtkWidget* dialog, gpointer user_data);
// Conversion functions for color
static int convertGdkColorComponent(guint16 color_component);
static guint16 convertToGdkColorComponent(int color_component);
static GdkColor convertToGdkColor(nscolor color);
static nsString ToHexString(int n);
void Done(GtkWidget* dialog, gint response_id);
void ReadValueFromColorChooser(GtkWidget* color_chooser);
nsCOMPtr<nsIWidget> mParentWidget;
nsCOMPtr<nsIColorPickerShownCallback> mCallback;
nsString mTitle;
nsString mColor;
GdkColor mDefaultColor;
};
#endif // nsColorPicker_h__

View File

@ -33,6 +33,7 @@
#include "nsISelection.h"
#include "nsViewManager.h"
#include "nsIFrame.h"
#include "nsGtkUtils.h"
// This sets how opaque the drag image is
#define DRAG_IMAGE_ALPHA_LEVEL 0.5
@ -46,17 +47,6 @@ enum {
MOZ_GTK_DRAG_RESULT_NO_TARGET
};
// Some gobject functions expect functions for gpointer arguments.
// gpointer is void* but C++ doesn't like casting functions to void*.
template<class T> static inline gpointer
FuncToGpointer(T aFunction)
{
return reinterpret_cast<gpointer>
(reinterpret_cast<uintptr_t>
// This cast just provides a warning if T is not a function.
(reinterpret_cast<void (*)()>(aFunction)));
}
static PRLogModuleInfo *sDragLm = NULL;
// data used for synthetic periodic motion events sent to the source widget

View File

@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include "nsGtkUtils.h"
#include "nsIFileURL.h"
#include "nsIURI.h"
#include "nsIWidget.h"
@ -32,17 +33,6 @@ using namespace mozilla;
nsIFile *nsFilePicker::mPrevDisplayDirectory = nullptr;
// Some GObject functions expect functions for gpointer arguments.
// gpointer is void* but C++ doesn't like casting functions to void*.
template<class T> static inline gpointer
FuncToGpointer(T aFunction)
{
return reinterpret_cast<gpointer>
(reinterpret_cast<uintptr_t>
// This cast just provides a warning if T is not a function.
(reinterpret_cast<void (*)()>(aFunction)));
}
void
nsFilePicker::Shutdown()
{

24
widget/gtk2/nsGtkUtils.h Normal file
View File

@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* 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/. */
#ifndef nsGtkUtils_h__
#define nsGtkUtils_h__
#include <glib.h>
// Some gobject functions expect functions for gpointer arguments.
// gpointer is void* but C++ doesn't like casting functions to void*.
template<class T> static inline gpointer
FuncToGpointer(T aFunction)
{
return reinterpret_cast<gpointer>
(reinterpret_cast<uintptr_t>
// This cast just provides a warning if T is not a function.
(reinterpret_cast<void (*)()>(aFunction)));
}
#endif // nsGtkUtils_h__

View File

@ -19,6 +19,7 @@
#include "nsClipboard.h"
#include "nsDragService.h"
#endif
#include "nsColorPicker.h"
#include "nsFilePicker.h"
#include "nsSound.h"
#include "nsBidiKeyboard.h"
@ -152,6 +153,24 @@ nsFilePickerConstructor(nsISupports *aOuter, REFNSIID aIID,
return picker->QueryInterface(aIID, aResult);
}
static nsresult
nsColorPickerConstructor(nsISupports *aOuter, REFNSIID aIID,
void **aResult)
{
*aResult = nullptr;
if (aOuter != nullptr) {
return NS_ERROR_NO_AGGREGATION;
}
nsCOMPtr<nsIColorPicker> picker = new nsColorPicker;
if (!picker) {
return NS_ERROR_OUT_OF_MEMORY;
}
return picker->QueryInterface(aIID, aResult);
}
static nsresult
nsNativeKeyBindingsConstructor(nsISupports *aOuter, REFNSIID aIID,
void **aResult,
@ -199,6 +218,7 @@ nsNativeKeyBindingsTextAreaConstructor(nsISupports *aOuter, REFNSIID aIID,
NS_DEFINE_NAMED_CID(NS_WINDOW_CID);
NS_DEFINE_NAMED_CID(NS_CHILD_CID);
NS_DEFINE_NAMED_CID(NS_APPSHELL_CID);
NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID);
NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
NS_DEFINE_NAMED_CID(NS_SOUND_CID);
NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID);
@ -234,6 +254,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
{ &kNS_WINDOW_CID, false, NULL, nsWindowConstructor },
{ &kNS_CHILD_CID, false, NULL, nsChildWindowConstructor },
{ &kNS_APPSHELL_CID, false, NULL, nsAppShellConstructor },
{ &kNS_COLORPICKER_CID, false, NULL, nsColorPickerConstructor },
{ &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor },
{ &kNS_SOUND_CID, false, NULL, nsSoundConstructor },
{ &kNS_TRANSFERABLE_CID, false, NULL, nsTransferableConstructor },
@ -270,6 +291,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
{ "@mozilla.org/widget/window/gtk;1", &kNS_WINDOW_CID },
{ "@mozilla.org/widgets/child_window/gtk;1", &kNS_CHILD_CID },
{ "@mozilla.org/widget/appshell/gtk;1", &kNS_APPSHELL_CID },
{ "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID },
{ "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID },
{ "@mozilla.org/sound;1", &kNS_SOUND_CID },
{ "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID },

View File

@ -67,6 +67,7 @@
#include "nsIServiceManager.h"
#include "nsIStringBundle.h"
#include "nsGfxCIID.h"
#include "nsGtkUtils.h"
#include "nsIObserverService.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsIIdleServiceInternal.h"
@ -283,17 +284,6 @@ static GtkWidget *gInvisibleContainer = NULL;
// only the button state bits are used.
static guint gButtonState;
// Some gobject functions expect functions for gpointer arguments.
// gpointer is void* but C++ doesn't like casting functions to void*.
template<class T> static inline gpointer
FuncToGpointer(T aFunction)
{
return reinterpret_cast<gpointer>
(reinterpret_cast<uintptr_t>
// This cast just provides a warning if T is not a function.
(reinterpret_cast<void (*)()>(aFunction)));
}
// nsAutoRef<pixman_region32> uses nsSimpleRef<> to know how to automatically
// destroy regions.
template <>