Use views to implement NativeWindow and MessageBox on Linux.
This commit is contained in:
parent
1965a5ee50
commit
61db17412c
22 changed files with 384 additions and 1777 deletions
16
atom.gyp
16
atom.gyp
|
@ -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',
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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_
|
295
atom/browser/native_window_views.cc
Normal file
295
atom/browser/native_window_views.cc
Normal 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
|
|
@ -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_
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a348865e723b73cd01d0b976f2d0b8d9b836176d
|
||||
Subproject commit f8baf4a4bad51536ab013b4ee2edd9d749df695d
|
Loading…
Reference in a new issue