gtk: Use libgtk2ui from chrome.
This commit is contained in:
parent
436deddf68
commit
e5c10f29de
12 changed files with 624 additions and 16 deletions
7
atom.gyp
7
atom.gyp
|
@ -234,6 +234,13 @@
|
|||
'chrome/browser/ui/gtk/gtk_window_util.h',
|
||||
'chrome/browser/ui/gtk/menu_gtk.cc',
|
||||
'chrome/browser/ui/gtk/menu_gtk.h',
|
||||
'chrome/browser/ui/libgtk2ui/g_object_destructor_filo.cc',
|
||||
'chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h',
|
||||
'chrome/browser/ui/libgtk2ui/gtk2_signal.h',
|
||||
'chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.cc',
|
||||
'chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.h',
|
||||
'chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc',
|
||||
'chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h',
|
||||
'chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc',
|
||||
'chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h',
|
||||
'<@(native_mate_files)',
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "base/environment.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "chrome/browser/ui/gtk/gtk_window_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
|
@ -25,7 +26,6 @@
|
|||
#include "ui/gfx/gtk_util.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/skia_utils_gtk.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -131,7 +131,8 @@ NativeWindowGtk::NativeWindowGtk(content::WebContents* web_contents,
|
|||
gtk_widget_realize(GTK_WIDGET(window_));
|
||||
|
||||
if (icon_)
|
||||
gtk_window_set_icon(window_, icon_->ToGdkPixbuf());
|
||||
gtk_window_set_icon(window_,
|
||||
libgtk2ui::GdkPixbufFromSkBitmap(*icon_->ToSkBitmap()));
|
||||
|
||||
ui::ActiveWindowWatcherX::AddObserver(this);
|
||||
|
||||
|
@ -443,7 +444,7 @@ void NativeWindowGtk::SetWebKitColorStyle() {
|
|||
GetWebContents()->GetMutableRendererPrefs();
|
||||
GtkStyle* frame_style = gtk_rc_get_style(GTK_WIDGET(window_));
|
||||
prefs->focus_ring_color =
|
||||
gfx::GdkColorToSkColor(frame_style->bg[GTK_STATE_SELECTED]);
|
||||
libgtk2ui::GdkColorToSkColor(frame_style->bg[GTK_STATE_SELECTED]);
|
||||
prefs->thumb_active_color = SkColorSetRGB(244, 244, 244);
|
||||
prefs->thumb_inactive_color = SkColorSetRGB(234, 234, 234);
|
||||
prefs->track_color = SkColorSetRGB(211, 211, 211);
|
||||
|
@ -451,13 +452,13 @@ void NativeWindowGtk::SetWebKitColorStyle() {
|
|||
GtkWidget* url_entry = gtk_entry_new();
|
||||
GtkStyle* entry_style = gtk_rc_get_style(url_entry);
|
||||
prefs->active_selection_bg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
|
||||
libgtk2ui::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
|
||||
prefs->active_selection_fg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
|
||||
libgtk2ui::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
|
||||
prefs->inactive_selection_bg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
|
||||
libgtk2ui::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
|
||||
prefs->inactive_selection_fg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]);
|
||||
libgtk2ui::GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]);
|
||||
gtk_widget_destroy(url_entry);
|
||||
|
||||
const base::TimeDelta cursor_blink_time = gfx::GetCursorBlinkCycle();
|
||||
|
|
|
@ -17,7 +17,7 @@ class AtomBindings {
|
|||
AtomBindings();
|
||||
virtual ~AtomBindings();
|
||||
|
||||
// Add process.atom_binding function, which behaves like process.atomBinding but
|
||||
// Add process.atomBinding function, which behaves like process.binding but
|
||||
// load native code from atom-shell instead.
|
||||
virtual void BindTo(v8::Isolate* isolate, v8::Handle<v8::Object> process);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "chrome/browser/ui/gtk/gtk_custom_menu.h"
|
||||
#include "chrome/browser/ui/gtk/gtk_custom_menu_item.h"
|
||||
#include "chrome/browser/ui/gtk/gtk_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_gtk.h"
|
||||
|
@ -350,8 +351,10 @@ GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
|
|||
|
||||
GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
|
||||
const gfx::Image& icon) {
|
||||
GtkWidget* menu_item = BuildMenuItemWithImage(label,
|
||||
gtk_image_new_from_pixbuf(icon.ToGdkPixbuf()));
|
||||
GtkWidget* menu_item = BuildMenuItemWithImage(
|
||||
label,
|
||||
gtk_image_new_from_pixbuf(
|
||||
libgtk2ui::GdkPixbufFromSkBitmap(*icon.ToSkBitmap())));
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
|
@ -856,9 +859,10 @@ void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
|
|||
if (GTK_IS_IMAGE_MENU_ITEM(widget)) {
|
||||
gfx::Image icon;
|
||||
if (model->GetIconAt(id, &icon)) {
|
||||
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget),
|
||||
gtk_image_new_from_pixbuf(
|
||||
icon.ToGdkPixbuf()));
|
||||
gtk_image_menu_item_set_image(
|
||||
GTK_IMAGE_MENU_ITEM(widget),
|
||||
gtk_image_new_from_pixbuf(
|
||||
libgtk2ui::GdkPixbufFromSkBitmap(*icon.ToSkBitmap())));
|
||||
} else {
|
||||
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "ui/base/gtk/gtk_signal.h"
|
||||
#include "ui/base/gtk/gtk_signal_registrar.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.h"
|
||||
#include "ui/gfx/point.h"
|
||||
|
||||
namespace gfx {
|
||||
|
@ -216,7 +216,7 @@ class MenuGtk {
|
|||
// menu.
|
||||
static bool block_activation_;
|
||||
|
||||
ui::GtkSignalRegistrar signal_;
|
||||
libgtk2ui::Gtk2SignalRegistrar signal_;
|
||||
|
||||
base::WeakPtrFactory<MenuGtk> weak_factory_;
|
||||
};
|
||||
|
|
89
chrome/browser/ui/libgtk2ui/g_object_destructor_filo.cc
Normal file
89
chrome/browser/ui/libgtk2ui/g_object_destructor_filo.cc
Normal file
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/singleton.h"
|
||||
|
||||
namespace libgtk2ui {
|
||||
|
||||
GObjectDestructorFILO::GObjectDestructorFILO() {
|
||||
}
|
||||
|
||||
GObjectDestructorFILO::~GObjectDestructorFILO() {
|
||||
// Probably CHECK(handler_map_.empty()) would look natural here. But
|
||||
// some tests (some views_unittests) violate this assertion.
|
||||
}
|
||||
|
||||
// static
|
||||
GObjectDestructorFILO* GObjectDestructorFILO::GetInstance() {
|
||||
return Singleton<GObjectDestructorFILO>::get();
|
||||
}
|
||||
|
||||
void GObjectDestructorFILO::Connect(
|
||||
GObject* object, DestructorHook callback, void* context) {
|
||||
const Hook hook(object, callback, context);
|
||||
HandlerMap::iterator iter = handler_map_.find(object);
|
||||
if (iter == handler_map_.end()) {
|
||||
g_object_weak_ref(object, WeakNotifyThunk, this);
|
||||
handler_map_[object].push_front(hook);
|
||||
} else {
|
||||
iter->second.push_front(hook);
|
||||
}
|
||||
}
|
||||
|
||||
void GObjectDestructorFILO::Disconnect(
|
||||
GObject* object, DestructorHook callback, void* context) {
|
||||
HandlerMap::iterator iter = handler_map_.find(object);
|
||||
if (iter == handler_map_.end()) {
|
||||
LOG(DFATAL) << "Unable to disconnect destructor hook for object " << object
|
||||
<< ": hook not found (" << callback << ", " << context << ").";
|
||||
return;
|
||||
}
|
||||
HandlerList& dtors = iter->second;
|
||||
if (dtors.empty()) {
|
||||
LOG(DFATAL) << "Destructor list is empty for specified object " << object
|
||||
<< " Maybe it is being executed?";
|
||||
return;
|
||||
}
|
||||
if (!dtors.front().equal(object, callback, context)) {
|
||||
// Reenable this warning once this bug is fixed:
|
||||
// http://code.google.com/p/chromium/issues/detail?id=85603
|
||||
DVLOG(1) << "Destructors should be unregistered the reverse order they "
|
||||
<< "were registered. But for object " << object << " "
|
||||
<< "deleted hook is "<< context << ", the last queued hook is "
|
||||
<< dtors.front().context;
|
||||
}
|
||||
for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i) {
|
||||
if (i->equal(object, callback, context)) {
|
||||
dtors.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dtors.empty()) {
|
||||
g_object_weak_unref(object, WeakNotifyThunk, this);
|
||||
handler_map_.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void GObjectDestructorFILO::WeakNotify(GObject* where_the_object_was) {
|
||||
HandlerMap::iterator iter = handler_map_.find(where_the_object_was);
|
||||
DCHECK(iter != handler_map_.end());
|
||||
DCHECK(!iter->second.empty());
|
||||
|
||||
// Save destructor list for given object into local copy to avoid reentrancy
|
||||
// problem: if callee wants to modify the caller list.
|
||||
HandlerList dtors;
|
||||
iter->second.swap(dtors);
|
||||
handler_map_.erase(iter);
|
||||
|
||||
// Execute hooks in local list in FILO order.
|
||||
for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i)
|
||||
i->callback(i->context, where_the_object_was);
|
||||
}
|
||||
|
||||
} // namespace libgtk2ui
|
90
chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h
Normal file
90
chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_UI_LIBGTK2UI_G_OBJECT_DESTRUCTOR_FILO_H_
|
||||
#define CHROME_BROWSER_UI_LIBGTK2UI_G_OBJECT_DESTRUCTOR_FILO_H_
|
||||
|
||||
#include <glib.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
template <typename T> struct DefaultSingletonTraits;
|
||||
|
||||
typedef struct _GObject GObject;
|
||||
|
||||
namespace libgtk2ui {
|
||||
|
||||
// This class hooks calls to g_object_weak_ref()/unref() and executes them in
|
||||
// FILO order. This is important if there are several hooks to the single object
|
||||
// (set up at different levels of class hierarchy) and the lowest hook (set up
|
||||
// first) is deleting self - it must be called last (among hooks for the given
|
||||
// object). Unfortunately Glib does not provide this guarantee.
|
||||
//
|
||||
// Use it as follows:
|
||||
//
|
||||
// static void OnDestroyedThunk(gpointer data, GObject *where_the_object_was) {
|
||||
// reinterpret_cast<MyClass*>(data)->OnDestroyed(where_the_object_was);
|
||||
// }
|
||||
// void MyClass::OnDestroyed(GObject *where_the_object_was) {
|
||||
// destroyed_ = true;
|
||||
// delete this;
|
||||
// }
|
||||
// MyClass::Init() {
|
||||
// ...
|
||||
// ui::GObjectDestructorFILO::GetInstance()->Connect(
|
||||
// G_OBJECT(my_widget), &OnDestroyedThunk, this);
|
||||
// }
|
||||
// MyClass::~MyClass() {
|
||||
// if (!destroyed_) {
|
||||
// ui::GObjectDestructorFILO::GetInstance()->Disconnect(
|
||||
// G_OBJECT(my_widget), &OnDestroyedThunk, this);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// TODO(glotov): Probably worth adding ScopedGObjectDtor<T>.
|
||||
//
|
||||
// This class is a singleton. Not thread safe. Must be called within UI thread.
|
||||
class GObjectDestructorFILO {
|
||||
public:
|
||||
typedef void (*DestructorHook)(void* context, GObject* where_the_object_was);
|
||||
|
||||
static GObjectDestructorFILO* GetInstance();
|
||||
void Connect(GObject* object, DestructorHook callback, void* context);
|
||||
void Disconnect(GObject* object, DestructorHook callback, void* context);
|
||||
|
||||
private:
|
||||
struct Hook {
|
||||
Hook(GObject* o, DestructorHook cb, void* ctx)
|
||||
: object(o), callback(cb), context(ctx) {
|
||||
}
|
||||
bool equal(GObject* o, DestructorHook cb, void* ctx) const {
|
||||
return object == o && callback == cb && context == ctx;
|
||||
}
|
||||
GObject* object;
|
||||
DestructorHook callback;
|
||||
void* context;
|
||||
};
|
||||
typedef std::list<Hook> HandlerList;
|
||||
typedef std::map<GObject*, HandlerList> HandlerMap;
|
||||
|
||||
GObjectDestructorFILO();
|
||||
~GObjectDestructorFILO();
|
||||
friend struct DefaultSingletonTraits<GObjectDestructorFILO>;
|
||||
|
||||
void WeakNotify(GObject* where_the_object_was);
|
||||
static void WeakNotifyThunk(gpointer data, GObject* where_the_object_was) {
|
||||
reinterpret_cast<GObjectDestructorFILO*>(data)->WeakNotify(
|
||||
where_the_object_was);
|
||||
}
|
||||
|
||||
HandlerMap handler_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GObjectDestructorFILO);
|
||||
};
|
||||
|
||||
} // namespace libgtk2ui
|
||||
|
||||
#endif // CHROME_BROWSER_UI_LIBGTK2UI_G_OBJECT_DESTRUCTOR_FILO_H_
|
68
chrome/browser/ui/libgtk2ui/gtk2_signal.h
Normal file
68
chrome/browser/ui/libgtk2ui/gtk2_signal.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_SIGNAL_H_
|
||||
#define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_SIGNAL_H_
|
||||
|
||||
#include "ui/base/glib/glib_signal.h"
|
||||
|
||||
typedef struct _GtkWidget GtkWidget;
|
||||
|
||||
// These macros handle the common case where the sender object will be a
|
||||
// GtkWidget*.
|
||||
#define CHROMEGTK_CALLBACK_0(CLASS, RETURN, METHOD) \
|
||||
CHROMEG_CALLBACK_0(CLASS, RETURN, METHOD, GtkWidget*);
|
||||
|
||||
#define CHROMEGTK_CALLBACK_1(CLASS, RETURN, METHOD, ARG1) \
|
||||
CHROMEG_CALLBACK_1(CLASS, RETURN, METHOD, GtkWidget*, ARG1);
|
||||
|
||||
#define CHROMEGTK_CALLBACK_2(CLASS, RETURN, METHOD, ARG1, ARG2) \
|
||||
CHROMEG_CALLBACK_2(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2);
|
||||
|
||||
#define CHROMEGTK_CALLBACK_3(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3) \
|
||||
CHROMEG_CALLBACK_3(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3);
|
||||
|
||||
#define CHROMEGTK_CALLBACK_4(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, ARG4) \
|
||||
CHROMEG_CALLBACK_4(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3, \
|
||||
ARG4);
|
||||
|
||||
#define CHROMEGTK_CALLBACK_5(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, ARG4, \
|
||||
ARG5) \
|
||||
CHROMEG_CALLBACK_5(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3, \
|
||||
ARG4, ARG5);
|
||||
|
||||
#define CHROMEGTK_CALLBACK_6(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, ARG4, \
|
||||
ARG5, ARG6) \
|
||||
CHROMEG_CALLBACK_6(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3, \
|
||||
ARG4, ARG5, ARG6);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_0(CLASS, RETURN, METHOD) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_0(CLASS, RETURN, METHOD, GtkWidget*);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_1(CLASS, RETURN, METHOD, ARG1) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_1(CLASS, RETURN, METHOD, GtkWidget*, ARG1);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_2(CLASS, RETURN, METHOD, ARG1, ARG2) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_2(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_3(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_3(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
|
||||
ARG3);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_4(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, \
|
||||
ARG4) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_4(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
|
||||
ARG3, ARG4);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_5(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, \
|
||||
ARG4, ARG5) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_5(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
|
||||
ARG3, ARG4, ARG5);
|
||||
|
||||
#define CHROMEGTK_VIRTUAL_CALLBACK_6(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, \
|
||||
ARG4, ARG5, ARG6) \
|
||||
CHROMEG_VIRTUAL_CALLBACK_6(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
|
||||
ARG3, ARG4, ARG5, ARG6);
|
||||
|
||||
#endif // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_SIGNAL_H_
|
98
chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.cc
Normal file
98
chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.cc
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h"
|
||||
|
||||
namespace libgtk2ui {
|
||||
|
||||
Gtk2SignalRegistrar::Gtk2SignalRegistrar() {
|
||||
}
|
||||
|
||||
Gtk2SignalRegistrar::~Gtk2SignalRegistrar() {
|
||||
for (HandlerMap::iterator list_iter = handler_lists_.begin();
|
||||
list_iter != handler_lists_.end(); ++list_iter) {
|
||||
GObject* object = list_iter->first;
|
||||
GObjectDestructorFILO::GetInstance()->Disconnect(
|
||||
object, WeakNotifyThunk, this);
|
||||
|
||||
HandlerList& handlers = list_iter->second;
|
||||
for (HandlerList::iterator ids_iter = handlers.begin();
|
||||
ids_iter != handlers.end(); ++ids_iter) {
|
||||
g_signal_handler_disconnect(object, *ids_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glong Gtk2SignalRegistrar::Connect(gpointer instance,
|
||||
const gchar* detailed_signal,
|
||||
GCallback signal_handler,
|
||||
gpointer data) {
|
||||
return ConnectInternal(instance, detailed_signal, signal_handler, data,
|
||||
false);
|
||||
}
|
||||
|
||||
glong Gtk2SignalRegistrar::ConnectAfter(gpointer instance,
|
||||
const gchar* detailed_signal,
|
||||
GCallback signal_handler,
|
||||
gpointer data) {
|
||||
return ConnectInternal(instance, detailed_signal, signal_handler, data, true);
|
||||
}
|
||||
|
||||
glong Gtk2SignalRegistrar::ConnectInternal(gpointer instance,
|
||||
const gchar* detailed_signal,
|
||||
GCallback signal_handler,
|
||||
gpointer data,
|
||||
bool after) {
|
||||
GObject* object = G_OBJECT(instance);
|
||||
|
||||
HandlerMap::iterator iter = handler_lists_.find(object);
|
||||
if (iter == handler_lists_.end()) {
|
||||
GObjectDestructorFILO::GetInstance()->Connect(
|
||||
object, WeakNotifyThunk, this);
|
||||
handler_lists_[object] = HandlerList();
|
||||
iter = handler_lists_.find(object);
|
||||
}
|
||||
|
||||
glong handler_id = after ?
|
||||
g_signal_connect_after(instance, detailed_signal, signal_handler, data) :
|
||||
g_signal_connect(instance, detailed_signal, signal_handler, data);
|
||||
iter->second.push_back(handler_id);
|
||||
|
||||
return handler_id;
|
||||
}
|
||||
|
||||
void Gtk2SignalRegistrar::WeakNotify(GObject* where_the_object_was) {
|
||||
HandlerMap::iterator iter = handler_lists_.find(where_the_object_was);
|
||||
if (iter == handler_lists_.end()) {
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
// The signal handlers will be disconnected automatically. Just erase the
|
||||
// handler id list.
|
||||
handler_lists_.erase(iter);
|
||||
}
|
||||
|
||||
void Gtk2SignalRegistrar::DisconnectAll(gpointer instance) {
|
||||
GObject* object = G_OBJECT(instance);
|
||||
HandlerMap::iterator iter = handler_lists_.find(object);
|
||||
if (iter == handler_lists_.end())
|
||||
return;
|
||||
|
||||
GObjectDestructorFILO::GetInstance()->Disconnect(
|
||||
object, WeakNotifyThunk, this);
|
||||
HandlerList& handlers = iter->second;
|
||||
for (HandlerList::iterator ids_iter = handlers.begin();
|
||||
ids_iter != handlers.end(); ++ids_iter) {
|
||||
g_signal_handler_disconnect(object, *ids_iter);
|
||||
}
|
||||
|
||||
handler_lists_.erase(iter);
|
||||
}
|
||||
|
||||
} // namespace libgtk2ui
|
74
chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.h
Normal file
74
chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_SIGNAL_REGISTRAR_H_
|
||||
#define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_SIGNAL_REGISTRAR_H_
|
||||
|
||||
#include <glib.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
typedef void (*GCallback) (void);
|
||||
typedef struct _GObject GObject;
|
||||
typedef struct _GtkWidget GtkWidget;
|
||||
|
||||
namespace libgtk2ui {
|
||||
|
||||
// A class that ensures that callbacks don't run on stale owner objects. Similar
|
||||
// in spirit to NotificationRegistrar. Use as follows:
|
||||
//
|
||||
// class ChromeObject {
|
||||
// public:
|
||||
// ChromeObject() {
|
||||
// ...
|
||||
//
|
||||
// signals_.Connect(widget, "event", CallbackThunk, this);
|
||||
// }
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// private:
|
||||
// Gtk2SignalRegistrar signals_;
|
||||
// };
|
||||
//
|
||||
// When |signals_| goes down, it will disconnect the handlers connected via
|
||||
// Connect.
|
||||
class Gtk2SignalRegistrar {
|
||||
public:
|
||||
Gtk2SignalRegistrar();
|
||||
~Gtk2SignalRegistrar();
|
||||
|
||||
// Connect before the default handler. Returns the handler id.
|
||||
glong Connect(gpointer instance, const gchar* detailed_signal,
|
||||
GCallback signal_handler, gpointer data);
|
||||
// Connect after the default handler. Returns the handler id.
|
||||
glong ConnectAfter(gpointer instance, const gchar* detailed_signal,
|
||||
GCallback signal_handler, gpointer data);
|
||||
|
||||
// Disconnects all signal handlers connected to |instance|.
|
||||
void DisconnectAll(gpointer instance);
|
||||
|
||||
private:
|
||||
typedef std::vector<glong> HandlerList;
|
||||
typedef std::map<GObject*, HandlerList> HandlerMap;
|
||||
|
||||
static void WeakNotifyThunk(gpointer data, GObject* where_the_object_was) {
|
||||
reinterpret_cast<Gtk2SignalRegistrar*>(data)->WeakNotify(
|
||||
where_the_object_was);
|
||||
}
|
||||
void WeakNotify(GObject* where_the_object_was);
|
||||
|
||||
glong ConnectInternal(gpointer instance, const gchar* detailed_signal,
|
||||
GCallback signal_handler, gpointer data, bool after);
|
||||
|
||||
HandlerMap handler_lists_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Gtk2SignalRegistrar);
|
||||
};
|
||||
|
||||
} // namespace libgtk2ui
|
||||
|
||||
#endif // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_SIGNAL_REGISTRAR_H_
|
135
chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc
Normal file
135
chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc
Normal file
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/skia/include/core/SkUnPreMultiply.h"
|
||||
|
||||
namespace libgtk2ui {
|
||||
|
||||
// GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly
|
||||
// See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html
|
||||
// To get back, we can just right shift by eight
|
||||
// (or, formulated differently, i == (i*257)/256 for all i < 256).
|
||||
|
||||
SkColor GdkColorToSkColor(GdkColor color) {
|
||||
return SkColorSetRGB(color.red >> 8, color.green >> 8, color.blue >> 8);
|
||||
}
|
||||
|
||||
GdkColor SkColorToGdkColor(SkColor color) {
|
||||
GdkColor gdk_color = {
|
||||
0,
|
||||
static_cast<guint16>(SkColorGetR(color) * kSkiaToGDKMultiplier),
|
||||
static_cast<guint16>(SkColorGetG(color) * kSkiaToGDKMultiplier),
|
||||
static_cast<guint16>(SkColorGetB(color) * kSkiaToGDKMultiplier)
|
||||
};
|
||||
return gdk_color;
|
||||
}
|
||||
|
||||
const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf) {
|
||||
// TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
|
||||
// I would prefer to use our gtk based canvas, but that would require
|
||||
// recompiling half of our skia extensions with gtk support, which we can't
|
||||
// do in this build.
|
||||
DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));
|
||||
|
||||
int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
|
||||
int w = gdk_pixbuf_get_width(pixbuf);
|
||||
int h = gdk_pixbuf_get_height(pixbuf);
|
||||
|
||||
SkBitmap ret;
|
||||
ret.setConfig(SkBitmap::kARGB_8888_Config, w, h);
|
||||
ret.allocPixels();
|
||||
ret.eraseColor(0);
|
||||
|
||||
uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));
|
||||
|
||||
if (n_channels == 4) {
|
||||
int total_length = w * h;
|
||||
guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
|
||||
|
||||
// Now here's the trick: we need to convert the gdk data (which is RGBA and
|
||||
// isn't premultiplied) to skia (which can be anything and premultiplied).
|
||||
for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
|
||||
const unsigned char& red = gdk_pixels[0];
|
||||
const unsigned char& green = gdk_pixels[1];
|
||||
const unsigned char& blue = gdk_pixels[2];
|
||||
const unsigned char& alpha = gdk_pixels[3];
|
||||
|
||||
skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
|
||||
}
|
||||
} else if (n_channels == 3) {
|
||||
// Because GDK makes rowstrides word aligned, we need to do something a bit
|
||||
// more complex when a pixel isn't perfectly a word of memory.
|
||||
int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
|
||||
guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
|
||||
for (int y = 0; y < h; ++y) {
|
||||
int row = y * rowstride;
|
||||
|
||||
for (int x = 0; x < w; ++x) {
|
||||
guchar* pixel = gdk_pixels + row + (x * 3);
|
||||
const unsigned char& red = pixel[0];
|
||||
const unsigned char& green = pixel[1];
|
||||
const unsigned char& blue = pixel[2];
|
||||
|
||||
skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
|
||||
if (bitmap.isNull())
|
||||
return NULL;
|
||||
|
||||
SkAutoLockPixels lock_pixels(bitmap);
|
||||
|
||||
int width = bitmap.width();
|
||||
int height = bitmap.height();
|
||||
|
||||
GdkPixbuf* pixbuf =
|
||||
gdk_pixbuf_new(GDK_COLORSPACE_RGB, // The only colorspace gtk supports.
|
||||
TRUE, // There is an alpha channel.
|
||||
8,
|
||||
width,
|
||||
height);
|
||||
|
||||
// SkBitmaps are premultiplied, we need to unpremultiply them.
|
||||
const int kBytesPerPixel = 4;
|
||||
uint8* divided = gdk_pixbuf_get_pixels(pixbuf);
|
||||
|
||||
for (int y = 0, i = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint32 pixel = bitmap.getAddr32(0, y)[x];
|
||||
|
||||
int alpha = SkColorGetA(pixel);
|
||||
if (alpha != 0 && alpha != 255) {
|
||||
SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
|
||||
divided[i + 0] = SkColorGetR(unmultiplied);
|
||||
divided[i + 1] = SkColorGetG(unmultiplied);
|
||||
divided[i + 2] = SkColorGetB(unmultiplied);
|
||||
divided[i + 3] = alpha;
|
||||
} else {
|
||||
divided[i + 0] = SkColorGetR(pixel);
|
||||
divided[i + 1] = SkColorGetG(pixel);
|
||||
divided[i + 2] = SkColorGetB(pixel);
|
||||
divided[i + 3] = alpha;
|
||||
}
|
||||
i += kBytesPerPixel;
|
||||
}
|
||||
}
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
} // namespace libgtk2ui
|
42
chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h
Normal file
42
chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_UI_LIBGTK2UI_SKIA_UTILS_GTK2_H_
|
||||
#define CHROME_BROWSER_UI_LIBGTK2UI_SKIA_UTILS_GTK2_H_
|
||||
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
|
||||
typedef struct _GdkColor GdkColor;
|
||||
typedef struct _GdkPixbuf GdkPixbuf;
|
||||
|
||||
class SkBitmap;
|
||||
|
||||
// Define a macro for creating GdkColors from RGB values. This is a macro to
|
||||
// allow static construction of literals, etc. Use this like:
|
||||
// GdkColor white = GDK_COLOR_RGB(0xff, 0xff, 0xff);
|
||||
#define GDK_COLOR_RGB(r, g, b) {0, r * ::libgtk2ui::kSkiaToGDKMultiplier, \
|
||||
g * ::libgtk2ui::kSkiaToGDKMultiplier, \
|
||||
b * ::libgtk2ui::kSkiaToGDKMultiplier}
|
||||
|
||||
namespace libgtk2ui {
|
||||
|
||||
// Multiply uint8 color components by this.
|
||||
const int kSkiaToGDKMultiplier = 257;
|
||||
|
||||
// Converts GdkColors to the ARGB layout Skia expects.
|
||||
SkColor GdkColorToSkColor(GdkColor color);
|
||||
|
||||
// Converts ARGB to GdkColor.
|
||||
GdkColor SkColorToGdkColor(SkColor color);
|
||||
|
||||
const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf);
|
||||
|
||||
// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
|
||||
// it is an expensive operation. The returned GdkPixbuf will have a refcount of
|
||||
// 1, and the caller is responsible for unrefing it when done.
|
||||
GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap);
|
||||
|
||||
} // namespace libgtk2ui
|
||||
|
||||
#endif // CHROME_BROWSER_UI_LIBGTK2UI_SKIA_UTILS_GTK2_H_
|
Loading…
Add table
Reference in a new issue