Use views to implement NativeWindow and MessageBox on Linux.

This commit is contained in:
Cheng Zhao 2014-07-04 01:30:36 +08:00
parent 1965a5ee50
commit 61db17412c
22 changed files with 384 additions and 1777 deletions

View file

@ -101,10 +101,8 @@
'atom/browser/mac/atom_application_delegate.mm',
'atom/browser/native_window.cc',
'atom/browser/native_window.h',
'atom/browser/native_window_aura.cc',
'atom/browser/native_window_aura.h',
# 'atom/browser/native_window_gtk.cc',
# 'atom/browser/native_window_gtk.h',
'atom/browser/native_window_views.cc',
'atom/browser/native_window_views.h',
'atom/browser/native_window_mac.h',
'atom/browser/native_window_mac.mm',
'atom/browser/native_window_win.cc',
@ -136,9 +134,8 @@
'atom/browser/ui/gtk/status_icon.cc',
'atom/browser/ui/gtk/status_icon.h',
'atom/browser/ui/message_box.h',
'atom/browser/ui/message_box_gtk.cc',
'atom/browser/ui/message_box_mac.mm',
'atom/browser/ui/message_box_win.cc',
'atom/browser/ui/message_box_views.cc',
'atom/browser/ui/tray_icon.cc',
'atom/browser/ui/tray_icon.h',
'atom/browser/ui/tray_icon_gtk.cc',
@ -236,13 +233,6 @@
'chromium_src/chrome/browser/ui/gtk/gtk_window_util.h',
'chromium_src/chrome/browser/ui/gtk/menu_gtk.cc',
'chromium_src/chrome/browser/ui/gtk/menu_gtk.h',
'chromium_src/chrome/browser/ui/libgtk2ui/g_object_destructor_filo.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_signal.h',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_signal_registrar.h',
'chromium_src/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h',
'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc',
'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h',
'chromium_src/ui/base/accelerators/platform_accelerator_gtk.cc',

View file

@ -246,7 +246,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
#if defined(OS_WIN) || defined(OS_LINUX)
.SetMethod("_attachToWindow", &Menu::AttachToWindow)
#endif
#if defined(OS_WIN)

View file

@ -4,7 +4,6 @@
#include "atom/browser/api/atom_api_menu_gtk.h"
#include "atom/browser/native_window_gtk.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"

View file

@ -9,12 +9,17 @@
#include "atom/browser/browser.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
#include "net/proxy/proxy_resolver_v8.h"
#if defined(OS_WIN)
#include "ui/gfx/win/dpi.h"
#endif
#if defined(USE_X11)
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
#endif
#include "atom/common/node_includes.h"
namespace atom {
@ -48,6 +53,14 @@ brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
return new AtomBrowserContext();
}
void AtomBrowserMainParts::InitProxyResolverV8() {
// Since we are integrating node in browser, we can just be sure that an
// V8 instance would be prepared, while the ProxyResolverV8::CreateIsolate()
// would try to create a V8 isolate, which messed everything on Windows, so
// we have to override and call RememberDefaultIsolate on Windows instead.
net::ProxyResolverV8::RememberDefaultIsolate();
}
void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization();
@ -64,6 +77,10 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
void AtomBrowserMainParts::PreMainMessageLoopRun() {
brightray::BrowserMainParts::PreMainMessageLoopRun();
#if defined(USE_X11)
libgtk2ui::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
#endif
node_bindings_->PrepareMessageLoop();
node_bindings_->RunMessageLoop();
@ -79,19 +96,4 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif
}
int AtomBrowserMainParts::PreCreateThreads() {
// Note that we are overriding the PreCreateThreads of brightray, since we
// are integrating node in browser, we can just be sure that an V8 instance
// would be prepared, while the ProxyResolverV8::CreateIsolate() would
// try to create a V8 isolate, which messed everything on Windows, so we
// have to override and call RememberDefaultIsolate on Windows instead.
net::ProxyResolverV8::RememberDefaultIsolate();
#if defined(OS_WIN)
gfx::EnableHighDPISupport();
#endif
return 0;
}
} // namespace atom

View file

@ -26,11 +26,11 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
protected:
// Implementations of brightray::BrowserMainParts.
virtual brightray::BrowserContext* CreateBrowserContext() OVERRIDE;
virtual void InitProxyResolverV8() OVERRIDE;
// Implementations of content::BrowserMainParts.
virtual void PostEarlyInitialization() OVERRIDE;
virtual void PreMainMessageLoopRun() OVERRIDE;
virtual int PreCreateThreads() OVERRIDE;
#if defined(OS_MACOSX)
virtual void PreMainMessageLoopStart() OVERRIDE;
virtual void PostDestroyThreads() OVERRIDE;

View file

@ -1,202 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/native_window_aura.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
namespace atom {
namespace {
class FillLayout : public aura::LayoutManager {
public:
explicit FillLayout(aura::Window* root)
: root_(root) {
}
virtual ~FillLayout() {}
private:
// aura::LayoutManager:
virtual void OnWindowResized() OVERRIDE {
}
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
child->SetBounds(root_->bounds());
}
virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
}
virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
}
virtual void OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) OVERRIDE {
}
virtual void SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) OVERRIDE {
SetChildBoundsDirect(child, requested_bounds);
}
aura::Window* root_;
DISALLOW_COPY_AND_ASSIGN(FillLayout);
};
} // namespace
NativeWindowAura::NativeWindowAura(content::WebContents* web_contents,
const mate::Dictionary& options)
: NativeWindow(web_contents, options) {
aura::Env::CreateInstance();
host_.reset(aura::WindowTreeHost::Create(gfx::Rect(gfx::Size(800, 600))));
host_->InitHost();
host_->window()->SetLayoutManager(new FillLayout(host_->window()));
host_->window()->AddChild(web_contents->GetView()->GetNativeView());
}
NativeWindowAura::~NativeWindowAura() {
}
void NativeWindowAura::Close() {
}
void NativeWindowAura::CloseImmediately() {
}
void NativeWindowAura::Move(const gfx::Rect& pos) {
}
void NativeWindowAura::Focus(bool focus) {
}
bool NativeWindowAura::IsFocused() {
return false;
}
void NativeWindowAura::Show() {
host_->Show();
}
void NativeWindowAura::Hide() {
host_->Hide();
}
bool NativeWindowAura::IsVisible() {
return false;
}
void NativeWindowAura::Maximize() {
}
void NativeWindowAura::Unmaximize() {
}
void NativeWindowAura::Minimize() {
}
void NativeWindowAura::Restore() {
}
void NativeWindowAura::SetFullscreen(bool fullscreen) {
}
bool NativeWindowAura::IsFullscreen() {
return false;
}
void NativeWindowAura::SetSize(const gfx::Size& size) {
}
gfx::Size NativeWindowAura::GetSize() {
return gfx::Size();
}
void NativeWindowAura::SetContentSize(const gfx::Size& size) {
}
gfx::Size NativeWindowAura::GetContentSize() {
return gfx::Size();
}
void NativeWindowAura::SetMinimumSize(const gfx::Size& size) {
}
gfx::Size NativeWindowAura::GetMinimumSize() {
return gfx::Size();
}
void NativeWindowAura::SetMaximumSize(const gfx::Size& size) {
}
gfx::Size NativeWindowAura::GetMaximumSize() {
return gfx::Size();
}
void NativeWindowAura::SetResizable(bool resizable) {
}
bool NativeWindowAura::IsResizable() {
return false;
}
void NativeWindowAura::SetAlwaysOnTop(bool top) {
}
bool NativeWindowAura::IsAlwaysOnTop() {
return false;
}
void NativeWindowAura::Center() {
}
void NativeWindowAura::SetPosition(const gfx::Point& position) {
}
gfx::Point NativeWindowAura::GetPosition() {
return gfx::Point(0, 0);
}
void NativeWindowAura::SetTitle(const std::string& title) {
}
std::string NativeWindowAura::GetTitle() {
return "";
}
void NativeWindowAura::FlashFrame(bool flash) {
}
void NativeWindowAura::SetSkipTaskbar(bool skip) {
}
void NativeWindowAura::SetKiosk(bool kiosk) {
}
bool NativeWindowAura::IsKiosk() {
return false;
}
gfx::NativeWindow NativeWindowAura::GetNativeWindow() {
return NULL;
}
void NativeWindowAura::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
const mate::Dictionary& options) {
return new NativeWindowAura(web_contents, options);
}
} // namespace atom

View file

@ -1,617 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/native_window_gtk.h"
#include <string>
#include <vector>
#include "atom/common/draggable_region.h"
#include "atom/common/options_switches.h"
#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"
#include "content/public/common/renderer_preferences.h"
#include "native_mate/dictionary.h"
#include "ui/base/accelerators/platform_accelerator_gtk.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/x/active_window_watcher_x.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/font_render_params_linux.h"
#include "ui/gfx/gtk_util.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
namespace atom {
namespace {
// Dividing GTK's cursor blink cycle time (in milliseconds) by this value yields
// an appropriate value for content::RendererPreferences::caret_blink_interval.
// This matches the logic in the WebKit GTK port.
const double kGtkCursorBlinkCycleFactor = 2000.0;
// Substract window border's size from window size according to current window
// manager.
void SubstractBorderSize(int* width, int* height) {
scoped_ptr<base::Environment> env(base::Environment::Create());
base::nix::DesktopEnvironment de(base::nix::GetDesktopEnvironment(env.get()));
if (de == base::nix::DESKTOP_ENVIRONMENT_UNITY) {
*width -= 2;
*height -= 29;
} else if (de == base::nix::DESKTOP_ENVIRONMENT_GNOME) {
*width -= 2;
*height -= 33;
} else if (de == base::nix::DESKTOP_ENVIRONMENT_XFCE) {
*width -= 6;
*height -= 27;
} else {
*width -= 2;
*height -= 29;
}
}
content::RendererPreferencesHintingEnum GetRendererPreferencesHintingEnum(
gfx::FontRenderParams::Hinting hinting) {
switch (hinting) {
case gfx::FontRenderParams::HINTING_NONE:
return content::RENDERER_PREFERENCES_HINTING_NONE;
case gfx::FontRenderParams::HINTING_SLIGHT:
return content::RENDERER_PREFERENCES_HINTING_SLIGHT;
case gfx::FontRenderParams::HINTING_MEDIUM:
return content::RENDERER_PREFERENCES_HINTING_MEDIUM;
case gfx::FontRenderParams::HINTING_FULL:
return content::RENDERER_PREFERENCES_HINTING_FULL;
default:
NOTREACHED() << "Unhandled hinting style " << hinting;
return content::RENDERER_PREFERENCES_HINTING_SYSTEM_DEFAULT;
}
}
content::RendererPreferencesSubpixelRenderingEnum
GetRendererPreferencesSubpixelRenderingEnum(
gfx::FontRenderParams::SubpixelRendering subpixel_rendering) {
switch (subpixel_rendering) {
case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_NONE;
case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_RGB;
case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_BGR;
case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VRGB;
case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VBGR;
default:
NOTREACHED() << "Unhandled subpixel rendering style "
<< subpixel_rendering;
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_SYSTEM_DEFAULT;
}
}
} // namespace
NativeWindowGtk::NativeWindowGtk(content::WebContents* web_contents,
const mate::Dictionary& options)
: NativeWindow(web_contents, options),
window_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))),
vbox_(gtk_vbox_new(FALSE, 0)),
state_(GDK_WINDOW_STATE_WITHDRAWN),
is_always_on_top_(false),
is_active_(false),
suppress_window_raise_(false),
has_ever_been_shown_(false),
frame_cursor_(NULL) {
gtk_container_add(GTK_CONTAINER(window_), vbox_);
gtk_container_add(GTK_CONTAINER(vbox_),
GetWebContents()->GetView()->GetNativeView());
int width = 800, height = 600;
options.Get(switches::kWidth, &width);
options.Get(switches::kHeight, &height);
bool use_content_size = false;
options.Get(switches::kUseContentSize, &use_content_size);
if (has_frame_ && !use_content_size)
SubstractBorderSize(&width, &height);
// Force a size allocation so the web page of hidden window can have correct
// value of $(window).width().
GtkAllocation size = { 0, 0, width, height };
gtk_widget_show_all(vbox_);
gtk_widget_size_allocate(GTK_WIDGET(window_), &size);
gtk_window_util::SetWindowSize(window_, gfx::Size(width, height));
// Create the underlying gdk window.
gtk_widget_realize(GTK_WIDGET(window_));
if (icon_)
gtk_window_set_icon(window_,
libgtk2ui::GdkPixbufFromSkBitmap(*icon_->ToSkBitmap()));
ui::ActiveWindowWatcherX::AddObserver(this);
// In some (older) versions of compiz, raising top-level windows when they
// are partially off-screen causes them to get snapped back on screen, not
// always even on the current virtual desktop. If we are running under
// compiz, suppress such raises, as they are not necessary in compiz anyway.
if (ui::GuessWindowManager() == ui::WM_COMPIZ)
suppress_window_raise_ = true;
g_signal_connect(window_, "delete-event",
G_CALLBACK(OnWindowDeleteEventThunk), this);
g_signal_connect(window_, "focus-out-event",
G_CALLBACK(OnFocusOutThunk), this);
g_signal_connect(window_, "focus-in-event",
G_CALLBACK(OnFocusInThunk), this);
g_signal_connect(window_, "window-state-event",
G_CALLBACK(OnWindowStateThunk), this);
if (!has_frame_) {
gtk_window_set_decorated(window_, false);
g_signal_connect(window_, "motion-notify-event",
G_CALLBACK(OnMouseMoveEventThunk), this);
g_signal_connect(window_, "button-press-event",
G_CALLBACK(OnButtonPressThunk), this);
}
SetWebKitColorStyle();
SetFontRenderering();
}
NativeWindowGtk::~NativeWindowGtk() {
CloseImmediately();
}
void NativeWindowGtk::Close() {
CloseWebContents();
}
void NativeWindowGtk::CloseImmediately() {
if (window_ == NULL)
return;
NotifyWindowClosed();
ui::ActiveWindowWatcherX::RemoveObserver(this);
gtk_widget_destroy(GTK_WIDGET(window_));
window_ = NULL;
}
void NativeWindowGtk::Move(const gfx::Rect& pos) {
gtk_window_move(window_, pos.x(), pos.y());
SetSize(pos.size());
}
void NativeWindowGtk::Focus(bool focus) {
if (!IsVisible())
return;
if (focus)
gtk_window_present(window_);
else
gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
}
bool NativeWindowGtk::IsFocused() {
if (ui::ActiveWindowWatcherX::WMSupportsActivation())
return is_active_;
// This still works even though we don't get the activation notification.
return gtk_window_is_active(window_);
}
void NativeWindowGtk::Show() {
has_ever_been_shown_ = true;
gtk_widget_show_all(GTK_WIDGET(window_));
}
void NativeWindowGtk::Hide() {
gtk_widget_hide(GTK_WIDGET(window_));
}
bool NativeWindowGtk::IsVisible() {
return gtk_widget_get_visible(GTK_WIDGET(window_));
}
void NativeWindowGtk::Maximize() {
gtk_window_maximize(window_);
}
void NativeWindowGtk::Unmaximize() {
gtk_window_unmaximize(window_);
}
void NativeWindowGtk::Minimize() {
gtk_window_iconify(window_);
}
void NativeWindowGtk::Restore() {
gtk_window_present(window_);
}
void NativeWindowGtk::SetFullscreen(bool fullscreen) {
if (fullscreen)
gtk_window_fullscreen(window_);
else
gtk_window_unfullscreen(window_);
}
bool NativeWindowGtk::IsFullscreen() {
return state_ & GDK_WINDOW_STATE_FULLSCREEN;
}
void NativeWindowGtk::SetSize(const gfx::Size& size) {
// When the window has not been mapped the window size does not include frame.
int width = size.width();
int height = size.height();
if (has_frame_ && !has_ever_been_shown_)
SubstractBorderSize(&width, &height);
gtk_window_util::SetWindowSize(window_, gfx::Size(width, height));
}
gfx::Size NativeWindowGtk::GetSize() {
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
GdkRectangle frame_extents;
gdk_window_get_frame_extents(gdk_window, &frame_extents);
return gfx::Size(frame_extents.width, frame_extents.height);
}
void NativeWindowGtk::SetContentSize(const gfx::Size& size) {
if (!has_frame_ || !has_ever_been_shown_) {
gtk_window_util::SetWindowSize(window_, size);
} else {
gfx::Size large = GetSize();
gfx::Size small = GetContentSize();
gfx::Size target(size.width() + large.width() - small.width(),
size.height() + large.height() - small.height());
gtk_window_util::SetWindowSize(window_, target);
}
}
gfx::Size NativeWindowGtk::GetContentSize() {
gint width, height;
gtk_window_get_size(window_, &width, &height);
return gfx::Size(width, height);
}
void NativeWindowGtk::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size;
GdkGeometry geometry = { 0 };
geometry.min_width = size.width();
geometry.min_height = size.height();
int hints = GDK_HINT_POS | GDK_HINT_MIN_SIZE;
gtk_window_set_geometry_hints(
window_, GTK_WIDGET(window_), &geometry, (GdkWindowHints)hints);
}
gfx::Size NativeWindowGtk::GetMinimumSize() {
return minimum_size_;
}
void NativeWindowGtk::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
GdkGeometry geometry = { 0 };
geometry.max_width = size.width();
geometry.max_height = size.height();
int hints = GDK_HINT_POS | GDK_HINT_MAX_SIZE;
gtk_window_set_geometry_hints(
window_, GTK_WIDGET(window_), &geometry, (GdkWindowHints)hints);
}
gfx::Size NativeWindowGtk::GetMaximumSize() {
return maximum_size_;
}
void NativeWindowGtk::SetResizable(bool resizable) {
// Should request widget size after setting unresizable, otherwise the
// window will shrink to a very small size.
if (!IsResizable() || !has_ever_been_shown_) {
gint width, height;
gtk_window_get_size(window_, &width, &height);
gtk_widget_set_size_request(GTK_WIDGET(window_), width, height);
}
gtk_window_set_resizable(window_, resizable);
}
bool NativeWindowGtk::IsResizable() {
return gtk_window_get_resizable(window_);
}
void NativeWindowGtk::SetAlwaysOnTop(bool top) {
is_always_on_top_ = top;
gtk_window_set_keep_above(window_, top ? TRUE : FALSE);
}
bool NativeWindowGtk::IsAlwaysOnTop() {
return is_always_on_top_;
}
void NativeWindowGtk::Center() {
gtk_window_set_position(window_, GTK_WIN_POS_CENTER);
}
void NativeWindowGtk::SetPosition(const gfx::Point& position) {
gtk_window_move(window_, position.x(), position.y());
}
gfx::Point NativeWindowGtk::GetPosition() {
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
GdkRectangle frame_extents;
gdk_window_get_frame_extents(gdk_window, &frame_extents);
return gfx::Point(frame_extents.x, frame_extents.y);
}
void NativeWindowGtk::SetTitle(const std::string& title) {
gtk_window_set_title(window_, title.c_str());
}
std::string NativeWindowGtk::GetTitle() {
return gtk_window_get_title(window_);
}
void NativeWindowGtk::FlashFrame(bool flash) {
gtk_window_set_urgency_hint(window_, flash);
}
void NativeWindowGtk::SetSkipTaskbar(bool skip) {
gtk_window_set_skip_taskbar_hint(window_, skip);
gtk_window_set_skip_pager_hint(window_, skip);
}
void NativeWindowGtk::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
}
bool NativeWindowGtk::IsKiosk() {
return IsFullscreen();
}
gfx::NativeWindow NativeWindowGtk::GetNativeWindow() {
return window_;
}
void NativeWindowGtk::SetMenu(ui::MenuModel* menu_model) {
menu_.reset(new ::MenuGtk(this, menu_model, true));
gtk_box_pack_start(GTK_BOX(vbox_), menu_->widget(), FALSE, FALSE, 0);
gtk_box_reorder_child(GTK_BOX(vbox_), menu_->widget(), 0);
gtk_widget_show_all(vbox_);
RegisterAccelerators();
}
void NativeWindowGtk::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
draggable_region_.reset(new SkRegion);
// By default, the whole window is non-draggable. We need to explicitly
// include those draggable regions.
for (std::vector<DraggableRegion>::const_iterator iter =
regions.begin();
iter != regions.end(); ++iter) {
const DraggableRegion& region = *iter;
draggable_region_->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
}
void NativeWindowGtk::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
if (event.type == blink::WebInputEvent::RawKeyDown) {
GdkEventKey* os_event = reinterpret_cast<GdkEventKey*>(event.os_event);
ui::Accelerator accelerator = ui::AcceleratorForGdkKeyCodeAndModifier(
os_event->keyval, static_cast<GdkModifierType>(os_event->state));
accelerator_util::TriggerAcceleratorTableCommand(&accelerator_table_,
accelerator);
}
}
void NativeWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
is_active_ = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
}
void NativeWindowGtk::RegisterAccelerators() {
DCHECK(menu_);
accelerator_table_.clear();
accelerator_util::GenerateAcceleratorTable(&accelerator_table_,
menu_->model());
}
void NativeWindowGtk::SetWebKitColorStyle() {
content::RendererPreferences* prefs =
GetWebContents()->GetMutableRendererPrefs();
GtkStyle* frame_style = gtk_rc_get_style(GTK_WIDGET(window_));
prefs->focus_ring_color =
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);
GtkWidget* url_entry = gtk_entry_new();
GtkStyle* entry_style = gtk_rc_get_style(url_entry);
prefs->active_selection_bg_color =
libgtk2ui::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
prefs->active_selection_fg_color =
libgtk2ui::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
prefs->inactive_selection_bg_color =
libgtk2ui::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
prefs->inactive_selection_fg_color =
libgtk2ui::GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]);
gtk_widget_destroy(url_entry);
const base::TimeDelta cursor_blink_time = gfx::GetCursorBlinkCycle();
prefs->caret_blink_interval =
cursor_blink_time.InMilliseconds() ?
cursor_blink_time.InMilliseconds() / kGtkCursorBlinkCycleFactor :
0;
}
void NativeWindowGtk::SetFontRenderering() {
content::RendererPreferences* prefs =
GetWebContents()->GetMutableRendererPrefs();
const gfx::FontRenderParams& params = gfx::GetDefaultWebKitFontRenderParams();
prefs->should_antialias_text = params.antialiasing;
prefs->use_subpixel_positioning = params.subpixel_positioning;
prefs->hinting = GetRendererPreferencesHintingEnum(params.hinting);
prefs->use_autohinter = params.autohinter;
prefs->use_bitmaps = params.use_bitmaps;
prefs->subpixel_rendering =
GetRendererPreferencesSubpixelRenderingEnum(params.subpixel_rendering);
}
bool NativeWindowGtk::IsMaximized() const {
return state_ & GDK_WINDOW_STATE_MAXIMIZED;
}
bool NativeWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) {
if (has_frame_)
return false;
if (IsMaximized() || IsFullscreen())
return false;
return gtk_window_util::GetWindowEdge(GetSize(), 0, x, y, edge);
}
gboolean NativeWindowGtk::OnWindowDeleteEvent(GtkWidget* widget,
GdkEvent* event) {
Close();
return TRUE;
}
gboolean NativeWindowGtk::OnFocusIn(GtkWidget* window, GdkEventFocus*) {
NotifyWindowFocus();
return FALSE;
}
gboolean NativeWindowGtk::OnFocusOut(GtkWidget* window, GdkEventFocus*) {
NotifyWindowBlur();
return FALSE;
}
gboolean NativeWindowGtk::OnWindowState(GtkWidget* window,
GdkEventWindowState* event) {
state_ = event->new_window_state;
return FALSE;
}
gboolean NativeWindowGtk::OnMouseMoveEvent(GtkWidget* widget,
GdkEventMotion* event) {
if (has_frame_) {
// Reset the cursor.
if (frame_cursor_) {
frame_cursor_ = NULL;
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL);
}
return FALSE;
}
if (!IsResizable())
return FALSE;
// Update the cursor if we're on the custom frame border.
GdkWindowEdge edge;
bool has_hit_edge = GetWindowEdge(static_cast<int>(event->x),
static_cast<int>(event->y), &edge);
GdkCursorType new_cursor = GDK_LAST_CURSOR;
if (has_hit_edge)
new_cursor = gtk_window_util::GdkWindowEdgeToGdkCursorType(edge);
GdkCursorType last_cursor = GDK_LAST_CURSOR;
if (frame_cursor_)
last_cursor = frame_cursor_->type;
if (last_cursor != new_cursor) {
frame_cursor_ = has_hit_edge ? gfx::GetCursor(new_cursor) : NULL;
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)),
frame_cursor_);
}
return FALSE;
}
gboolean NativeWindowGtk::OnButtonPress(GtkWidget* widget,
GdkEventButton* event) {
DCHECK(!has_frame_);
// Make the button press coordinate relative to the browser window.
int win_x, win_y;
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
gdk_window_get_origin(gdk_window, &win_x, &win_y);
GdkWindowEdge edge;
gfx::Point point(static_cast<int>(event->x_root - win_x),
static_cast<int>(event->y_root - win_y));
bool has_hit_edge = IsResizable() &&
GetWindowEdge(point.x(), point.y(), &edge);
bool has_hit_titlebar =
draggable_region_ && draggable_region_->contains(event->x, event->y);
if (event->button == 1) {
if (GDK_BUTTON_PRESS == event->type) {
// Raise the window after a click on either the titlebar or the border to
// match the behavior of most window managers, unless that behavior has
// been suppressed.
if ((has_hit_titlebar || has_hit_edge) && !suppress_window_raise_)
gdk_window_raise(GTK_WIDGET(widget)->window);
if (has_hit_edge) {
gtk_window_begin_resize_drag(window_, edge, event->button,
static_cast<gint>(event->x_root),
static_cast<gint>(event->y_root),
event->time);
return TRUE;
} else if (has_hit_titlebar) {
GdkRectangle window_bounds = {0};
gdk_window_get_frame_extents(gdk_window, &window_bounds);
gfx::Rect bounds(window_bounds.x, window_bounds.y,
window_bounds.width, window_bounds.height);
return gtk_window_util::HandleTitleBarLeftMousePress(
window_, bounds, event);
}
} else if (GDK_2BUTTON_PRESS == event->type) {
if (has_hit_titlebar && IsResizable()) {
// Maximize/restore on double click.
if (IsMaximized())
gtk_window_unmaximize(window_);
else
gtk_window_maximize(window_);
return TRUE;
}
}
} else if (event->button == 2) {
if (has_hit_titlebar || has_hit_edge)
gdk_window_lower(gdk_window);
return TRUE;
}
return FALSE;
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
const mate::Dictionary& options) {
return new NativeWindowGtk(web_contents, options);
}
} // namespace atom

View file

@ -1,157 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
#define ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
#include <gtk/gtk.h>
#include <string>
#include <vector>
#include "atom/browser/native_window.h"
#include "atom/browser/ui/accelerator_util.h"
#include "chrome/browser/ui/gtk/menu_gtk.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/gtk/gtk_signal.h"
#include "ui/base/x/active_window_watcher_x_observer.h"
#include "ui/gfx/size.h"
namespace atom {
class NativeWindowGtk : public NativeWindow,
public MenuGtk::Delegate,
public ui::ActiveWindowWatcherXObserver {
public:
explicit NativeWindowGtk(content::WebContents* web_contents,
const mate::Dictionary& options);
virtual ~NativeWindowGtk();
// NativeWindow implementation.
virtual void Close() OVERRIDE;
virtual void CloseImmediately() OVERRIDE;
virtual void Move(const gfx::Rect& pos) OVERRIDE;
virtual void Focus(bool focus) OVERRIDE;
virtual bool IsFocused() OVERRIDE;
virtual void Show() OVERRIDE;
virtual void Hide() OVERRIDE;
virtual bool IsVisible() OVERRIDE;
virtual void Maximize() OVERRIDE;
virtual void Unmaximize() OVERRIDE;
virtual void Minimize() OVERRIDE;
virtual void Restore() OVERRIDE;
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
virtual bool IsFullscreen() OVERRIDE;
virtual void SetSize(const gfx::Size& size) OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual void SetContentSize(const gfx::Size& size) OVERRIDE;
virtual gfx::Size GetContentSize() OVERRIDE;
virtual void SetMinimumSize(const gfx::Size& size) OVERRIDE;
virtual gfx::Size GetMinimumSize() OVERRIDE;
virtual void SetMaximumSize(const gfx::Size& size) OVERRIDE;
virtual gfx::Size GetMaximumSize() OVERRIDE;
virtual void SetResizable(bool resizable) OVERRIDE;
virtual bool IsResizable() OVERRIDE;
virtual void SetAlwaysOnTop(bool top) OVERRIDE;
virtual bool IsAlwaysOnTop() OVERRIDE;
virtual void Center() OVERRIDE;
virtual void SetPosition(const gfx::Point& position) OVERRIDE;
virtual gfx::Point GetPosition() OVERRIDE;
virtual void SetTitle(const std::string& title) OVERRIDE;
virtual std::string GetTitle() OVERRIDE;
virtual void FlashFrame(bool flash) OVERRIDE;
virtual void SetSkipTaskbar(bool skip) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
// Set the native window menu.
void SetMenu(ui::MenuModel* menu_model);
protected:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
// Overridden from content::WebContentsDelegate:
virtual void HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE;
// Overridden from ActiveWindowWatcherXObserver.
virtual void ActiveWindowChanged(GdkWindow* active_window) OVERRIDE;
private:
// Register accelerators supported by the menu model.
void RegisterAccelerators();
// Set WebKit's style from current theme.
void SetWebKitColorStyle();
// Set how font is renderered.
void SetFontRenderering();
// Whether window is maximized.
bool IsMaximized() const;
// If the point (|x|, |y|) is within the resize border area of the window,
// returns true and sets |edge| to the appropriate GdkWindowEdge value.
// Otherwise, returns false.
bool GetWindowEdge(int x, int y, GdkWindowEdge* edge);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowDeleteEvent,
GdkEvent*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusIn, GdkEventFocus*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusOut, GdkEventFocus*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowState,
GdkEventWindowState*);
// Mouse move and mouse button press callbacks.
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnMouseMoveEvent,
GdkEventMotion*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnButtonPress,
GdkEventButton*);
GtkWindow* window_;
GtkWidget* vbox_;
GdkWindowState state_;
bool is_always_on_top_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
// The region is treated as title bar, can be dragged to move and double
// clicked to maximize.
scoped_ptr<SkRegion> draggable_region_;
// True if the window manager thinks the window is active. It could happpen
// that the WM thinks a window is active but it's actually not, like when
// showing a context menu.
bool is_active_;
// If true, don't call gdk_window_raise() when we get a click in the title
// bar or window border. This is to work around a compiz bug.
bool suppress_window_raise_;
// True if the window has been visible for once, on Linux the window frame
// would // only be considered as part of the window untill the window has
// been shown, so we need it to correctly set the window size.
bool has_ever_been_shown_;
// The current window cursor. We set it to a resize cursor when over the
// custom frame border. We set it to NULL if we want the default cursor.
GdkCursor* frame_cursor_;
// The window menu.
scoped_ptr<MenuGtk> menu_;
// Map from accelerator to menu item's command id.
accelerator_util::AcceleratorTable accelerator_table_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowGtk);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_GTK_H_

View file

@ -0,0 +1,295 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/native_window_views.h"
#include <string>
#include <vector>
#include "atom/common/options_switches.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents_view.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/background.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/native_frame_view.h"
#include "ui/views/widget/widget.h"
namespace atom {
namespace {
class NativeWindowClientView : public views::ClientView {
public:
NativeWindowClientView(views::Widget* widget,
NativeWindowViews* contents_view)
: views::ClientView(widget, contents_view) {
}
virtual ~NativeWindowClientView() {}
virtual bool CanClose() OVERRIDE {
static_cast<NativeWindowViews*>(contents_view())->CloseWebContents();
return false;
}
private:
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
};
} // namespace
NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
const mate::Dictionary& options)
: NativeWindow(web_contents, options),
window_(new views::Widget),
web_view_(new views::WebView(web_contents->GetBrowserContext())),
resizable_(true) {
options.Get(switches::kResizable, &resizable_);
options.Get(switches::kTitle, &title_);
views::Widget::InitParams params;
params.delegate = this;
params.top_level = true;
params.remove_standard_frame = !has_frame_;
window_->Init(params);
int width = 800, height = 600;
options.Get(switches::kWidth, &width);
options.Get(switches::kHeight, &height);
window_->CenterWindow(gfx::Size(width, height));
SetLayoutManager(new views::FillLayout);
set_background(views::Background::CreateStandardPanelBackground());
web_view_->SetWebContents(web_contents);
}
NativeWindowViews::~NativeWindowViews() {
}
void NativeWindowViews::Close() {
window_->Close();
}
void NativeWindowViews::CloseImmediately() {
window_->CloseNow();
}
void NativeWindowViews::Move(const gfx::Rect& bounds) {
window_->SetBounds(bounds);
}
void NativeWindowViews::Focus(bool focus) {
if (focus)
window_->Activate();
else
window_->Deactivate();
}
bool NativeWindowViews::IsFocused() {
return window_->IsActive();
}
void NativeWindowViews::Show() {
window_->Show();
}
void NativeWindowViews::Hide() {
window_->Hide();
}
bool NativeWindowViews::IsVisible() {
return window_->IsVisible();
}
void NativeWindowViews::Maximize() {
window_->Maximize();
}
void NativeWindowViews::Unmaximize() {
window_->Restore();
}
void NativeWindowViews::Minimize() {
window_->Minimize();
}
void NativeWindowViews::Restore() {
window_->Restore();
}
void NativeWindowViews::SetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
}
bool NativeWindowViews::IsFullscreen() {
return window_->IsFullscreen();
}
void NativeWindowViews::SetSize(const gfx::Size& size) {
window_->SetSize(size);
}
gfx::Size NativeWindowViews::GetSize() {
return window_->GetWindowBoundsInScreen().size();
}
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
// FIXME
SetSize(size);
}
gfx::Size NativeWindowViews::GetContentSize() {
// FIXME
return GetSize();
}
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size;
}
gfx::Size NativeWindowViews::GetMinimumSize() {
return minimum_size_;
}
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
}
gfx::Size NativeWindowViews::GetMaximumSize() {
return maximum_size_;
}
void NativeWindowViews::SetResizable(bool resizable) {
// FIXME
resizable_ = resizable;
}
bool NativeWindowViews::IsResizable() {
return resizable_;
}
void NativeWindowViews::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top);
}
bool NativeWindowViews::IsAlwaysOnTop() {
// FIXME
return false;
}
void NativeWindowViews::Center() {
window_->CenterWindow(GetSize());
}
void NativeWindowViews::SetPosition(const gfx::Point& position) {
window_->SetBounds(gfx::Rect(position, GetSize()));
}
gfx::Point NativeWindowViews::GetPosition() {
return window_->GetWindowBoundsInScreen().origin();
}
void NativeWindowViews::SetTitle(const std::string& title) {
title_ = title;
window_->UpdateWindowTitle();
}
std::string NativeWindowViews::GetTitle() {
return title_;
}
void NativeWindowViews::FlashFrame(bool flash) {
window_->FlashFrame(flash);
}
void NativeWindowViews::SetSkipTaskbar(bool skip) {
// FIXME
}
void NativeWindowViews::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
}
bool NativeWindowViews::IsKiosk() {
return IsFullscreen();
}
gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
return window_->GetNativeWindow();
}
void NativeWindowViews::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
}
void NativeWindowViews::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && details.child == this) {
AddChildView(web_view_);
}
}
void NativeWindowViews::DeleteDelegate() {
NotifyWindowClosed();
}
views::View* NativeWindowViews::GetInitiallyFocusedView() {
return web_view_;
}
bool NativeWindowViews::CanResize() const {
return resizable_;
}
bool NativeWindowViews::CanMaximize() const {
return resizable_;
}
base::string16 NativeWindowViews::GetWindowTitle() const {
return base::UTF8ToUTF16(title_);
}
bool NativeWindowViews::ShouldHandleSystemCommands() const {
return true;
}
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
if (icon_)
return *(icon_->ToImageSkia());
else
return gfx::ImageSkia();
}
gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
return GetWindowAppIcon();
}
views::Widget* NativeWindowViews::GetWidget() {
return window_.get();
}
const views::Widget* NativeWindowViews::GetWidget() const {
return window_.get();
}
views::View* NativeWindowViews::GetContentsView() {
return this;
}
views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
return new NativeWindowClientView(widget, this);
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
const mate::Dictionary& options) {
return new NativeWindowViews(web_contents, options);
}
} // namespace atom

View file

@ -2,20 +2,29 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_WINDOW_AURA_H_
#define ATOM_BROWSER_NATIVE_WINDOW_AURA_H_
#ifndef ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
#define ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
#include "atom/browser/native_window.h"
#include "ui/aura/window_tree_host.h"
#include <string>
#include <vector>
#include "ui/views/widget/widget_delegate.h"
namespace views {
class WebView;
class Widget;
}
namespace atom {
class NativeWindowAura : public NativeWindow {
class NativeWindowViews : public NativeWindow,
public views::WidgetDelegateView {
public:
explicit NativeWindowAura(content::WebContents* web_contents,
explicit NativeWindowViews(content::WebContents* web_contents,
const mate::Dictionary& options);
virtual ~NativeWindowAura();
virtual ~NativeWindowViews();
// NativeWindow:
virtual void Close() OVERRIDE;
@ -60,11 +69,35 @@ class NativeWindowAura : public NativeWindow {
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
scoped_ptr<aura::WindowTreeHost> host_;
// views::View:
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(NativeWindowAura);
// views::WidgetDelegate:
virtual void DeleteDelegate() OVERRIDE;
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
virtual bool CanResize() const OVERRIDE;
virtual bool CanMaximize() const OVERRIDE;
virtual base::string16 GetWindowTitle() const OVERRIDE;
virtual bool ShouldHandleSystemCommands() const OVERRIDE;
virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
scoped_ptr<views::Widget> window_;
views::WebView* web_view_; // managed by window_.
bool resizable_;
std::string title_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
};
} // namespace atom
#endif // ATOM_BROWSER_NATR_NATIVE_WINDOW_AURA_H_
#endif // ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_

View file

@ -27,7 +27,6 @@ class FileChooserDialog {
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
confirm_text = GTK_STOCK_OPEN;
// GtkWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
GtkWindow* window = NULL;
dialog_ = gtk_file_chooser_dialog_new(
title.c_str(),

View file

@ -1,136 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/message_box.h"
#include "atom/browser/native_window.h"
#include "base/callback.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "ui/base/gtk/gtk_signal.h"
namespace atom {
namespace {
class MessageBox {
public:
MessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail)
: cancel_id_(0),
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
// GtkWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
GtkWindow* window = NULL;
dialog_ = gtk_dialog_new_with_buttons(
title.c_str(),
window,
static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
NULL);
for (size_t i = 0; i < buttons.size(); ++i)
gtk_dialog_add_button(GTK_DIALOG(dialog_),
TranslateToStock(i, buttons[i]),
i);
GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_));
GtkWidget* message_label = gtk_util::CreateBoldLabel(message);
gtk_util::LeftAlignMisc(message_label);
gtk_box_pack_start(GTK_BOX(content_area), message_label, FALSE, FALSE, 0);
GtkWidget* detail_label = gtk_label_new(detail.c_str());
gtk_util::LeftAlignMisc(detail_label);
gtk_box_pack_start(GTK_BOX(content_area), detail_label, FALSE, FALSE, 0);
gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
}
~MessageBox() {
gtk_widget_destroy(dialog_);
}
const char* TranslateToStock(int id, const std::string& text) {
if (LowerCaseEqualsASCII(text, "cancel")) {
cancel_id_ = id;
return GTK_STOCK_CANCEL;
} else if (LowerCaseEqualsASCII(text, "no")) {
cancel_id_ = id;
return GTK_STOCK_NO;
} else if (LowerCaseEqualsASCII(text, "ok")) {
return GTK_STOCK_OK;
} else if (LowerCaseEqualsASCII(text, "yes")) {
return GTK_STOCK_YES;
} else {
return text.c_str();
}
}
void RunAsynchronous(const MessageBoxCallback& callback) {
callback_ = callback;
g_signal_connect(dialog_, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(dialog_, "response",
G_CALLBACK(OnResponseDialogThunk), this);
gtk_widget_show_all(dialog_);
}
CHROMEGTK_CALLBACK_1(MessageBox, void, OnResponseDialog, int);
GtkWidget* dialog() const { return dialog_; }
int cancel_id() const { return cancel_id_; }
private:
GtkWidget* dialog_;
MessageBoxCallback callback_;
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
// The id to return when the dialog is closed without pressing buttons.
int cancel_id_;
DISALLOW_COPY_AND_ASSIGN(MessageBox);
};
void MessageBox::OnResponseDialog(GtkWidget* widget, int response) {
gtk_widget_hide_all(dialog_);
if (response < 0)
callback_.Run(cancel_id_);
else
callback_.Run(response);
delete this;
}
} // namespace
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail) {
MessageBox message_box(parent_window, type, buttons, title, message, detail);
gtk_widget_show_all(message_box.dialog());
int response = gtk_dialog_run(GTK_DIALOG(message_box.dialog()));
if (response < 0)
return message_box.cancel_id();
else
return response;
}
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback) {
MessageBox* message_box = new MessageBox(
parent_window, type, buttons, title, message, detail);
message_box->RunAsynchronous(callback);
}
} // namespace atom

View file

@ -9,8 +9,9 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "skia/ext/skia_utils_win.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/layout/grid_layout.h"
@ -26,8 +27,7 @@ namespace {
// conflict with other groups that could be in the dialog content.
const int kButtonGroup = 1127;
class MessageDialog : public base::MessageLoop::Dispatcher,
public views::WidgetDelegate,
class MessageDialog : public views::WidgetDelegate,
public views::View,
public views::ButtonListener {
public:
@ -39,7 +39,7 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
const std::string& detail);
virtual ~MessageDialog();
void Show();
void Show(base::RunLoop* run_loop = NULL);
int GetResult() const;
@ -49,9 +49,6 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
}
private:
// Overridden from MessageLoop::Dispatcher:
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
// Overridden from views::WidgetDelegate:
virtual base::string16 GetWindowTitle() const;
virtual void WindowClosing() OVERRIDE;
@ -76,6 +73,7 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
base::string16 title_;
views::Widget* widget_;
views::MessageBoxView* message_box_view_;
base::RunLoop* run_loop_;
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
std::vector<views::LabelButton*> buttons_;
MessageBoxCallback callback_;
@ -95,24 +93,27 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
: should_close_(false),
delete_on_close_(false),
result_(-1),
title_(UTF8ToUTF16(title)),
title_(base::UTF8ToUTF16(title)),
widget_(NULL),
message_box_view_(NULL),
run_loop_(NULL),
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
DCHECK_GT(buttons.size(), 0u);
set_owned_by_client();
set_background(views::Background::CreateStandardPanelBackground());
views::MessageBoxView::InitParams params(UTF8ToUTF16(title));
params.message = UTF8ToUTF16(message + "\n" + detail);
std::string content = message + "\n" + detail;
views::MessageBoxView::InitParams params(base::UTF8ToUTF16(content));
message_box_view_ = new views::MessageBoxView(params);
AddChildView(message_box_view_);
for (size_t i = 0; i < buttons.size(); ++i) {
views::LabelButton* button = new views::LabelButton(
this, UTF8ToUTF16(buttons[i]));
this, base::UTF8ToUTF16(buttons[i]));
button->set_tag(i);
button->set_min_size(gfx::Size(60, 20));
button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
button->set_min_size(gfx::Size(60, 30));
button->SetStyle(views::Button::STYLE_BUTTON);
button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
button->SetGroup(kButtonGroup);
buttons_.push_back(button);
@ -129,20 +130,17 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
if (parent_window)
widget_params.parent = parent_window->GetNativeWindow();
widget_ = new views::Widget;
widget_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
widget_->Init(widget_params);
// Bind to ESC.
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
set_background(views::Background::CreateSolidBackground(
skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW))));
}
MessageDialog::~MessageDialog() {
}
void MessageDialog::Show() {
void MessageDialog::Show(base::RunLoop* run_loop) {
run_loop_ = run_loop;
widget_->Show();
}
@ -164,13 +162,7 @@ int MessageDialog::GetResult() const {
////////////////////////////////////////////////////////////////////////////////
// MessageDialog, private:
bool MessageDialog::Dispatch(const base::NativeEvent& event) {
TranslateMessage(&event);
DispatchMessage(&event);
return !should_close_;
}
string16 MessageDialog::GetWindowTitle() const {
base::string16 MessageDialog::GetWindowTitle() const {
return title_;
}
@ -181,6 +173,8 @@ void MessageDialog::WindowClosing() {
if (delete_on_close_) {
callback_.Run(GetResult());
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
} else if (run_loop_) {
run_loop_->Quit();
}
}
@ -269,11 +263,11 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message,
const std::string& detail) {
MessageDialog dialog(parent_window, type, buttons, title, message, detail);
dialog.Show();
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoopForUI::current());
base::RunLoop run_loop(&dialog);
base::RunLoop run_loop;
dialog.Show(&run_loop);
run_loop.Run();
}

View file

@ -20,6 +20,9 @@ struct Converter<base::string16> {
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
base::string16* out) {
if (!val->IsString())
return false;
v8::String::Value s(val);
out->assign(reinterpret_cast<const base::char16*>(*s), s.length());
return true;

View file

@ -1,89 +0,0 @@
// 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

View file

@ -1,90 +0,0 @@
// 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_

View file

@ -1,68 +0,0 @@
// 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_

View file

@ -1,98 +0,0 @@
// 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

View file

@ -1,74 +0,0 @@
// 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_

View file

@ -1,135 +0,0 @@
// 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

View file

@ -1,42 +0,0 @@
// 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_

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit a348865e723b73cd01d0b976f2d0b8d9b836176d
Subproject commit f8baf4a4bad51536ab013b4ee2edd9d749df695d