Merge pull request #440 from atom/chrome35

Upgrade to Chrome35
This commit is contained in:
Cheng Zhao 2014-07-21 22:23:04 +08:00
commit e803d3cc7a
159 changed files with 4159 additions and 6768 deletions

View file

@ -54,12 +54,10 @@
'atom/browser/api/atom_api_dialog.cc',
'atom/browser/api/atom_api_menu.cc',
'atom/browser/api/atom_api_menu.h',
'atom/browser/api/atom_api_menu_gtk.cc',
'atom/browser/api/atom_api_menu_gtk.h',
'atom/browser/api/atom_api_menu_views.cc',
'atom/browser/api/atom_api_menu_views.h',
'atom/browser/api/atom_api_menu_mac.h',
'atom/browser/api/atom_api_menu_mac.mm',
'atom/browser/api/atom_api_menu_win.cc',
'atom/browser/api/atom_api_menu_win.h',
'atom/browser/api/atom_api_power_monitor.cc',
'atom/browser/api/atom_api_power_monitor.h',
'atom/browser/api/atom_api_protocol.cc',
@ -101,12 +99,10 @@
'atom/browser/mac/atom_application_delegate.mm',
'atom/browser/native_window.cc',
'atom/browser/native_window.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',
'atom/browser/native_window_win.h',
'atom/browser/native_window_observer.h',
'atom/browser/net/adapter_request_job.cc',
'atom/browser/net/adapter_request_job.h',
@ -118,9 +114,8 @@
'atom/browser/net/url_request_string_job.h',
'atom/browser/ui/accelerator_util.cc',
'atom/browser/ui/accelerator_util.h',
'atom/browser/ui/accelerator_util_gtk.cc',
'atom/browser/ui/accelerator_util_mac.mm',
'atom/browser/ui/accelerator_util_win.cc',
'atom/browser/ui/accelerator_util_views.cc',
'atom/browser/ui/cocoa/atom_menu_controller.h',
'atom/browser/ui/cocoa/atom_menu_controller.mm',
'atom/browser/ui/cocoa/event_processing_window.h',
@ -129,25 +124,31 @@
'atom/browser/ui/file_dialog_gtk.cc',
'atom/browser/ui/file_dialog_mac.mm',
'atom/browser/ui/file_dialog_win.cc',
'atom/browser/ui/gtk/app_indicator_icon.cc',
'atom/browser/ui/gtk/app_indicator_icon.h',
'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',
'atom/browser/ui/tray_icon_gtk.h',
'atom/browser/ui/tray_icon_cocoa.h',
'atom/browser/ui/tray_icon_cocoa.mm',
'atom/browser/ui/tray_icon_observer.h',
'atom/browser/ui/tray_icon_win.cc',
'atom/browser/ui/win/menu_2.cc',
'atom/browser/ui/win/menu_2.h',
'atom/browser/ui/win/native_menu_win.cc',
'atom/browser/ui/win/native_menu_win.h',
'atom/browser/ui/views/frameless_view.cc',
'atom/browser/ui/views/frameless_view.h',
'atom/browser/ui/views/global_menu_bar_x11.cc',
'atom/browser/ui/views/global_menu_bar_x11.h',
'atom/browser/ui/views/linux_frame_view.cc',
'atom/browser/ui/views/linux_frame_view.h',
'atom/browser/ui/views/menu_bar.cc',
'atom/browser/ui/views/menu_bar.h',
'atom/browser/ui/views/menu_delegate.cc',
'atom/browser/ui/views/menu_delegate.h',
'atom/browser/ui/views/menu_layout.cc',
'atom/browser/ui/views/menu_layout.h',
'atom/browser/ui/views/win_frame_view.cc',
'atom/browser/ui/views/win_frame_view.h',
'atom/browser/ui/win/notify_icon_host.cc',
'atom/browser/ui/win/notify_icon_host.h',
'atom/browser/ui/win/notify_icon.cc',
@ -167,8 +168,6 @@
'atom/common/api/atom_api_v8_util.cc',
'atom/common/api/atom_bindings.cc',
'atom/common/api/atom_bindings.h',
'atom/common/api/atom_extensions.cc',
'atom/common/api/atom_extensions.h',
'atom/common/api/object_life_monitor.cc',
'atom/common/api/object_life_monitor.h',
'atom/common/browser_v8_locker.cc',
@ -224,20 +223,14 @@
'atom/renderer/atom_render_view_observer.h',
'atom/renderer/atom_renderer_client.cc',
'atom/renderer/atom_renderer_client.h',
'chrome/browser/ui/gtk/event_utils.cc',
'chrome/browser/ui/gtk/event_utils.h',
'chrome/browser/ui/gtk/gtk_custom_menu.cc',
'chrome/browser/ui/gtk/gtk_custom_menu.h',
'chrome/browser/ui/gtk/gtk_custom_menu_item.cc',
'chrome/browser/ui/gtk/gtk_custom_menu_item.h',
'chrome/browser/ui/gtk/gtk_util.cc',
'chrome/browser/ui/gtk/gtk_util.h',
'chrome/browser/ui/gtk/gtk_window_util.cc',
'chrome/browser/ui/gtk/gtk_window_util.h',
'chrome/browser/ui/gtk/menu_gtk.cc',
'chrome/browser/ui/gtk/menu_gtk.h',
'chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc',
'chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h',
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h',
'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc',
'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.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',
'<@(native_mate_files)',
],
'framework_sources': [
@ -379,10 +372,12 @@
'files': [
'<(libchromiumcontent_library_dir)/chromiumcontent.dll',
'<(libchromiumcontent_library_dir)/ffmpegsumo.dll',
'<(libchromiumcontent_library_dir)/icudt.dll',
'<(libchromiumcontent_library_dir)/libEGL.dll',
'<(libchromiumcontent_library_dir)/libGLESv2.dll',
'<(libchromiumcontent_resources_dir)/icudtl.dat',
'<(libchromiumcontent_resources_dir)/content_shell.pak',
'<(libchromiumcontent_resources_dir)/ui_resources_200_percent.pak',
'<(libchromiumcontent_resources_dir)/webkit_resources_200_percent.pak',
'external_binaries/d3dcompiler_43.dll',
'external_binaries/xinput1_3.dll',
],
@ -402,6 +397,7 @@
'files': [
'<(libchromiumcontent_library_dir)/libchromiumcontent.so',
'<(libchromiumcontent_library_dir)/libffmpegsumo.so',
'<(libchromiumcontent_resources_dir)/icudtl.dat',
'<(libchromiumcontent_resources_dir)/content_shell.pak',
],
},
@ -427,6 +423,7 @@
],
'include_dirs': [
'.',
'chromium_src',
'vendor/brightray',
'vendor/native_mate',
# Include directories for uv and node.
@ -454,7 +451,6 @@
'-loleacc.lib',
'-lComdlg32.lib',
'-lWininet.lib',
'<(atom_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
],
},
'dependencies': [
@ -654,6 +650,7 @@
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
'$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
@ -663,6 +660,7 @@
'mac_bundle_resources': [
'atom/common/resources/mac/MainMenu.xib',
'<(libchromiumcontent_resources_dir)/content_shell.pak',
'<(libchromiumcontent_resources_dir)/icudtl.dat',
],
'xcode_settings': {
'INFOPLIST_FILE': 'atom/common/resources/mac/Info.plist',

View file

@ -10,6 +10,9 @@
#if defined(OS_MACOSX)
int AtomMain(int argc, const char* argv[]) {
atom::AtomMainDelegate delegate;
return content::ContentMain(argc, argv, &delegate);
content::ContentMainParams params(&delegate);
params.argc = argc;
params.argv = argv;
return content::ContentMain(params);
}
#endif // OS_MACOSX

View file

@ -16,10 +16,12 @@
#include <shellapi.h>
#include "atom/app/atom_main_delegate.h"
#include "base/environment.h"
#include "atom/common/crash_reporter/win/crash_service_main.h"
#include "base/environment.h"
#include "base/win/registry.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
#include "ui/gfx/win/dpi.h"
#elif defined(OS_LINUX) // defined(OS_WIN)
#include "atom/app/atom_main_delegate.h" // NOLINT
#include "content/public/app/content_main.h"
@ -34,6 +36,13 @@ int Start(int argc, char *argv[]);
#if defined(OS_WIN)
namespace {
const wchar_t kRegistryProfilePath[] = L"SOFTWARE\\Google\\Chrome\\Profile";
const wchar_t kHighDPISupportW[] = L"high-dpi-support";
} // namespace
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
int argc = 0;
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
@ -98,7 +107,18 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
sandbox::SandboxInterfaceInfo sandbox_info = {0};
content::InitializeSandboxInfo(&sandbox_info);
atom::AtomMainDelegate delegate;
return content::ContentMain(instance, &sandbox_info, &delegate);
// Now chrome relies on a regkey to enable high dpi support.
base::win::RegKey high_dpi_key(HKEY_CURRENT_USER);
high_dpi_key.CreateKey(kRegistryProfilePath, KEY_SET_VALUE);
high_dpi_key.WriteValue(kHighDPISupportW, 1);
gfx::EnableHighDPISupport();
content::ContentMainParams params(&delegate);
params.instance = instance;
params.sandbox_info = &sandbox_info;
return content::ContentMain(params);
}
#elif defined(OS_LINUX) // defined(OS_WIN)
@ -109,7 +129,10 @@ int main(int argc, const char* argv[]) {
return node::Start(argc, const_cast<char**>(argv));
atom::AtomMainDelegate delegate;
return content::ContentMain(argc, argv, &delegate);
content::ContentMainParams params(&delegate);
params.argc = argc;
params.argv = argv;
return content::ContentMain(params);
}
#else // defined(OS_LINUX)

View file

@ -6,14 +6,13 @@
#include <string>
#include "atom/browser/atom_browser_client.h"
#include "atom/renderer/atom_renderer_client.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "atom/browser/atom_browser_client.h"
#include "content/public/common/content_switches.h"
#include "atom/renderer/atom_renderer_client.h"
#include "ui/base/resource/resource_bundle.h"
#include "base/path_service.h"
namespace atom {
@ -23,6 +22,18 @@ AtomMainDelegate::AtomMainDelegate() {
AtomMainDelegate::~AtomMainDelegate() {
}
void AtomMainDelegate::AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) {
#if defined(OS_WIN)
bundle->AddDataPackFromPath(
pak_dir.Append(FILE_PATH_LITERAL("ui_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
bundle->AddDataPackFromPath(
pak_dir.Append(FILE_PATH_LITERAL("webkit_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
#endif
}
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Disable logging out to debug.log on Windows
#if defined(OS_WIN)
@ -35,8 +46,6 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#else
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif
settings.dcheck_state =
logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
logging::InitLogging(settings);
#endif // defined(OS_WIN)
@ -52,11 +61,7 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
}
void AtomMainDelegate::PreSandboxStartup() {
#if defined(OS_MACOSX)
OverrideChildProcessPath();
OverrideFrameworkBundlePath();
#endif
InitializeResourceBundle();
brightray::MainDelegate::PreSandboxStartup();
CommandLine* command_line = CommandLine::ForCurrentProcess();
std::string process_type = command_line->GetSwitchValueASCII(
@ -76,19 +81,6 @@ void AtomMainDelegate::PreSandboxStartup() {
command_line->AppendSwitch("atom-shell-switches-end");
}
void AtomMainDelegate::InitializeResourceBundle() {
base::FilePath path;
#if defined(OS_MACOSX)
path = GetResourcesPakFilePath();
#else
base::FilePath pak_dir;
PathService::Get(base::DIR_MODULE, &pak_dir);
path = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
#endif
ui::ResourceBundle::InitSharedInstanceWithPakPath(path);
}
content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
browser_client_.reset(new AtomBrowserClient);
return browser_client_.get();

View file

@ -6,6 +6,7 @@
#define ATOM_APP_ATOM_MAIN_DELEGATE_H_
#include "brightray/common/main_delegate.h"
#include "brightray/common/content_client.h"
namespace atom {
@ -15,14 +16,17 @@ class AtomMainDelegate : public brightray::MainDelegate {
~AtomMainDelegate();
protected:
// brightray::MainDelegate:
virtual void AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) OVERRIDE;
// content::ContentMainDelegate:
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
virtual void PreSandboxStartup() OVERRIDE;
virtual void InitializeResourceBundle();
#if defined(OS_MACOSX)
virtual base::FilePath GetResourcesPakFilePath();
virtual void OverrideChildProcessPath();
virtual void OverrideFrameworkBundlePath();
virtual void OverrideChildProcessPath() OVERRIDE;
virtual void OverrideFrameworkBundlePath() OVERRIDE;
#endif
private:
@ -30,6 +34,7 @@ class AtomMainDelegate : public brightray::MainDelegate {
virtual content::ContentRendererClient*
CreateContentRendererClient() OVERRIDE;
brightray::ContentClient content_client_;
scoped_ptr<content::ContentBrowserClient> browser_client_;
scoped_ptr<content::ContentRendererClient> renderer_client_;

View file

@ -4,16 +4,11 @@
#include "atom/app/atom_main_delegate.h"
#import "base/mac/bundle_locations.h"
#import "base/mac/foundation_util.h"
#import "base/mac/mac_util.h"
#include "base/command_line.h"
#include "base/mac/bundle_locations.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/sys_string_conversions.h"
#include "brightray/common/mac/main_application_bundle.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "vendor/brightray/common/application_info.h"
#include "vendor/brightray/common/mac/main_application_bundle.h"
namespace atom {
@ -26,12 +21,6 @@ base::FilePath GetFrameworksPath() {
} // namespace
base::FilePath AtomMainDelegate::GetResourcesPakFilePath() {
NSString* path = [base::mac::FrameworkBundle()
pathForResource:@"content_shell" ofType:@"pak"];
return base::mac::NSStringToFilePath(path);
}
void AtomMainDelegate::OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(
GetFrameworksPath().Append("Atom Framework.framework"));

View file

@ -109,8 +109,9 @@ int DockBounce(const std::string& type) {
}
#endif
void Initialize(v8::Handle<v8::Object> exports) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
Browser* browser = Browser::Get();
CommandLine* command_line = CommandLine::ForCurrentProcess();
@ -140,4 +141,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_browser_app, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_app, Initialize)

View file

@ -85,12 +85,13 @@ mate::Handle<AutoUpdater> AutoUpdater::Create(v8::Isolate* isolate) {
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.Set("autoUpdater", atom::api::AutoUpdater::Create(isolate));
}
} // namespace
NODE_MODULE(atom_browser_auto_updater, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_auto_updater, Initialize)

View file

@ -27,7 +27,7 @@ void ShowMessageBox(int type,
mate::Arguments* args) {
v8::Handle<v8::Value> peek = args->PeekNext();
atom::MessageBoxCallback callback;
if (mate::Converter<atom::MessageBoxCallback>::FromV8(node_isolate,
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
peek,
&callback)) {
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, title,
@ -46,7 +46,7 @@ void ShowOpenDialog(const std::string& title,
mate::Arguments* args) {
v8::Handle<v8::Value> peek = args->PeekNext();
file_dialog::OpenDialogCallback callback;
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(node_isolate,
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
peek,
&callback)) {
file_dialog::ShowOpenDialog(window, title, default_path, properties,
@ -65,7 +65,7 @@ void ShowSaveDialog(const std::string& title,
mate::Arguments* args) {
v8::Handle<v8::Value> peek = args->PeekNext();
file_dialog::SaveDialogCallback callback;
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(node_isolate,
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
peek,
&callback)) {
file_dialog::ShowSaveDialog(window, title, default_path, callback);
@ -76,8 +76,9 @@ void ShowSaveDialog(const std::string& title,
}
}
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("showMessageBox", &ShowMessageBox);
dict.SetMethod("showOpenDialog", &ShowOpenDialog);
dict.SetMethod("showSaveDialog", &ShowSaveDialog);
@ -85,4 +86,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_browser_dialog, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_dialog, Initialize)

View file

@ -4,7 +4,7 @@
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/accelerator_util.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/constructor.h"
@ -20,26 +20,23 @@ namespace api {
namespace {
// Call method of delegate object.
v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
v8::Handle<v8::Value> CallDelegate(v8::Isolate* isolate,
v8::Handle<v8::Value> default_value,
v8::Handle<v8::Object> menu,
const char* method,
int command_id) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> delegate = menu->Get(v8::String::New("delegate"));
v8::Handle<v8::Value> delegate = menu->Get(
MATE_STRING_NEW(isolate, "delegate"));
if (!delegate->IsObject())
return default_value;
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(
delegate->ToObject()->Get(v8::String::New(method)));
delegate->ToObject()->Get(MATE_STRING_NEW(isolate, method)));
if (!function->IsFunction())
return default_value;
v8::Handle<v8::Value> argv = v8::Integer::New(command_id);
return handle_scope.Close(
function->Call(v8::Context::GetCurrent()->Global(), 1, &argv));
v8::Handle<v8::Value> argv = MATE_INTEGER_NEW(isolate, command_id);
return function->Call(isolate->GetCurrentContext()->Global(), 1, &argv);
}
} // namespace
@ -53,38 +50,46 @@ Menu::~Menu() {
}
bool Menu::IsCommandIdChecked(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::False(),
const_cast<Menu*>(this)->GetWrapper(node_isolate),
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
return CallDelegate(isolate,
MATE_FALSE(isolate),
const_cast<Menu*>(this)->GetWrapper(isolate),
"isCommandIdChecked",
command_id)->BooleanValue();
}
bool Menu::IsCommandIdEnabled(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::True(),
const_cast<Menu*>(this)->GetWrapper(node_isolate),
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
return CallDelegate(isolate,
MATE_TRUE(isolate),
const_cast<Menu*>(this)->GetWrapper(isolate),
"isCommandIdEnabled",
command_id)->BooleanValue();
}
bool Menu::IsCommandIdVisible(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::True(),
const_cast<Menu*>(this)->GetWrapper(node_isolate),
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
return CallDelegate(isolate,
MATE_TRUE(isolate),
const_cast<Menu*>(this)->GetWrapper(isolate),
"isCommandIdVisible",
command_id)->BooleanValue();
}
bool Menu::GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> shortcut = CallDelegate(v8::Undefined(),
GetWrapper(node_isolate),
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::Value> shortcut = CallDelegate(isolate,
MATE_UNDEFINED(isolate),
GetWrapper(isolate),
"getAcceleratorForCommandId",
command_id);
if (shortcut->IsString()) {
@ -96,51 +101,64 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
}
bool Menu::IsItemForCommandIdDynamic(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::False(),
const_cast<Menu*>(this)->GetWrapper(node_isolate),
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
return CallDelegate(isolate,
MATE_FALSE(isolate),
const_cast<Menu*>(this)->GetWrapper(isolate),
"isItemForCommandIdDynamic",
command_id)->BooleanValue();
}
string16 Menu::GetLabelForCommandId(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
base::string16 Menu::GetLabelForCommandId(int command_id) const {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::Value> result = CallDelegate(
v8::False(),
const_cast<Menu*>(this)->GetWrapper(node_isolate),
isolate,
MATE_FALSE(isolate),
const_cast<Menu*>(this)->GetWrapper(isolate),
"getLabelForCommandId",
command_id);
string16 label;
mate::ConvertFromV8(node_isolate, result, &label);
base::string16 label;
mate::ConvertFromV8(isolate, result, &label);
return label;
}
string16 Menu::GetSublabelForCommandId(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
base::string16 Menu::GetSublabelForCommandId(int command_id) const {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::Value> result = CallDelegate(
v8::False(),
const_cast<Menu*>(this)->GetWrapper(node_isolate),
isolate,
MATE_FALSE(isolate),
const_cast<Menu*>(this)->GetWrapper(isolate),
"getSubLabelForCommandId",
command_id);
string16 label;
mate::ConvertFromV8(node_isolate, result, &label);
base::string16 label;
mate::ConvertFromV8(isolate, result, &label);
return label;
}
void Menu::ExecuteCommand(int command_id, int event_flags) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
CallDelegate(v8::False(), GetWrapper(node_isolate), "executeCommand",
command_id);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
CallDelegate(isolate, MATE_FALSE(isolate), GetWrapper(isolate),
"executeCommand", command_id);
}
void Menu::MenuWillShow(ui::SimpleMenuModel* source) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
CallDelegate(v8::False(), GetWrapper(node_isolate), "menuWillShow", -1);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
CallDelegate(isolate, MATE_FALSE(isolate), GetWrapper(isolate),
"menuWillShow", -1);
}
void Menu::AttachToWindow(Window* window) {
window->window()->SetMenu(model_.get());
}
void Menu::InsertItemAt(
@ -232,12 +250,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)
.SetMethod("_attachToWindow", &Menu::AttachToWindow)
#endif
#if defined(OS_WIN)
.SetMethod("_updateStates", &Menu::UpdateStates)
#endif
.SetMethod("attachToWindow", &Menu::AttachToWindow)
.SetMethod("_popup", &Menu::Popup);
}
@ -248,11 +261,13 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
using atom::api::Menu;
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<Menu>(
node_isolate, "Menu", base::Bind(&Menu::Create));
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
isolate, "Menu", base::Bind(&Menu::Create));
mate::Dictionary dict(isolate, exports);
dict.Set("Menu", static_cast<v8::Handle<v8::Value>>(constructor));
#if defined(OS_MACOSX)
dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu);
@ -263,4 +278,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_browser_menu, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_menu, Initialize)

View file

@ -48,11 +48,12 @@ class Menu : public mate::Wrappable,
int command_id,
ui::Accelerator* accelerator) OVERRIDE;
virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
virtual string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE;
virtual base::string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
virtual void MenuWillShow(ui::SimpleMenuModel* source) OVERRIDE;
virtual void AttachToWindow(Window* window);
virtual void Popup(Window* window) = 0;
scoped_ptr<ui::SimpleMenuModel> model_;
@ -83,14 +84,6 @@ class Menu : public mate::Wrappable,
bool IsEnabledAt(int index) const;
bool IsVisibleAt(int index) const;
#if defined(OS_WIN)
virtual void UpdateStates() = 0;
#endif
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
virtual void AttachToWindow(Window* window) = 0;
#endif
DISALLOW_COPY_AND_ASSIGN(Menu);
};

View file

@ -1,51 +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/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"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
MenuGtk::MenuGtk() {
}
void MenuGtk::Popup(Window* window) {
uint32_t triggering_event_time;
gfx::Point point;
NativeWindow* native_window = window->window();
GdkEventButton* event = native_window->GetWebContents()->
GetRenderWidgetHostView()->GetLastMouseDown();
if (event) {
triggering_event_time = event->time;
point = gfx::Point(event->x_root, event->y_root);
} else {
triggering_event_time = GDK_CURRENT_TIME;
point = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
}
menu_gtk_.reset(new ::MenuGtk(this, model_.get()));
menu_gtk_->PopupAsContext(point, triggering_event_time);
}
void MenuGtk::AttachToWindow(Window* window) {
static_cast<NativeWindowGtk*>(window->window())->SetMenu(model_.get());
}
// static
mate::Wrappable* Menu::Create() {
return new MenuGtk();
}
} // namespace api
} // namespace atom

View file

@ -1,34 +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_API_ATOM_API_MENU_GTK_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_GTK_H_
#include "atom/browser/api/atom_api_menu.h"
#include "chrome/browser/ui/gtk/menu_gtk.h"
namespace atom {
namespace api {
class MenuGtk : public Menu,
public ::MenuGtk::Delegate {
public:
MenuGtk();
protected:
virtual void Popup(Window* window) OVERRIDE;
virtual void AttachToWindow(Window* window) OVERRIDE;
private:
scoped_ptr<::MenuGtk> menu_gtk_;
DISALLOW_COPY_AND_ASSIGN(MenuGtk);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_GTK_H_

View file

@ -0,0 +1,45 @@
// 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/api/atom_api_menu_views.h"
#include "atom/browser/native_window_views.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_runner.h"
#if defined(OS_WIN)
#include "ui/gfx/win/dpi.h"
#endif
namespace atom {
namespace api {
MenuViews::MenuViews() {
}
void MenuViews::Popup(Window* window) {
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
#if defined(OS_WIN)
cursor = gfx::win::ScreenToDIPPoint(cursor);
#endif
views::MenuRunner menu_runner(model());
ignore_result(menu_runner.RunMenuAt(
static_cast<NativeWindowViews*>(window->window())->widget(),
NULL,
gfx::Rect(cursor, gfx::Size()),
views::MenuItemView::TOPLEFT,
ui::MENU_SOURCE_MOUSE,
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
}
// static
mate::Wrappable* Menu::Create() {
return new MenuViews();
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,29 @@
// 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_API_ATOM_API_MENU_VIEWS_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
#include "atom/browser/api/atom_api_menu.h"
namespace atom {
namespace api {
class MenuViews : public Menu {
public:
MenuViews();
protected:
virtual void Popup(Window* window) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(MenuViews);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_

View file

@ -1,49 +0,0 @@
// Copyright (c) 2013 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/api/atom_api_menu_win.h"
#include "atom/browser/native_window_win.h"
#include "atom/browser/ui/win/menu_2.h"
#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
MenuWin::MenuWin() : menu_(NULL) {
}
void MenuWin::Popup(Window* window) {
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
popup_menu_.reset(new atom::Menu2(model_.get()));
menu_ = popup_menu_.get();
menu_->RunContextMenuAt(cursor);
}
void MenuWin::UpdateStates() {
MenuWin* top = this;
while (top->parent_)
top = static_cast<MenuWin*>(top->parent_);
if (top->menu_)
top->menu_->UpdateStates();
}
void MenuWin::AttachToWindow(Window* window) {
NativeWindowWin* nw = static_cast<NativeWindowWin*>(window->window());
nw->SetMenu(model_.get());
menu_ = nw->menu();
}
// static
mate::Wrappable* Menu::Create() {
return new MenuWin();
}
} // namespace api
} // namespace atom

View file

@ -1,36 +0,0 @@
// Copyright (c) 2013 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_API_ATOM_API_MENU_WIN_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_
#include "atom/browser/api/atom_api_menu.h"
namespace atom {
class Menu2;
namespace api {
class MenuWin : public Menu {
public:
MenuWin();
protected:
virtual void Popup(Window* window) OVERRIDE;
virtual void UpdateStates() OVERRIDE;
virtual void AttachToWindow(Window* window) OVERRIDE;
private:
atom::Menu2* menu_; // Weak ref, could be window menu or popup menu.
scoped_ptr<atom::Menu2> popup_menu_;
DISALLOW_COPY_AND_ASSIGN(MenuWin);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_

View file

@ -49,13 +49,14 @@ mate::Handle<PowerMonitor> PowerMonitor::Create(v8::Isolate* isolate) {
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
#if defined(OS_MACOSX)
base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
#endif
using atom::api::PowerMonitor;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Isolate* isolate = context->GetIsolate();
mate::Handle<PowerMonitor> power_monitor = PowerMonitor::Create(isolate);
mate::Dictionary dict(isolate, exports);
dict.Set("powerMonitor", power_monitor);
@ -63,4 +64,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_browser_power_monitor, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_monitor, Initialize)

View file

@ -58,8 +58,9 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
virtual void GetJobTypeInUI() OVERRIDE {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
// Call the JS handler.
Protocol::JsProtocolHandler callback =
@ -75,7 +76,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
return;
} else if (result->IsObject()) {
v8::Handle<v8::Object> obj = result->ToObject();
mate::Dictionary dict(node_isolate, obj);
mate::Dictionary dict(isolate, obj);
std::string name = mate::V8ToString(obj->GetConstructorName());
if (name == "RequestStringJob") {
std::string mime_type, charset, data;
@ -321,16 +322,17 @@ mate::Handle<Protocol> Protocol::Create(v8::Isolate* isolate) {
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
// Make sure the job factory has been created.
atom::AtomBrowserContext::Get()->url_request_context_getter()->
GetURLRequestContext();
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.Set("protocol", atom::api::Protocol::Create(isolate));
}
} // namespace
NODE_MODULE(atom_browser_protocol, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_protocol, Initialize)

View file

@ -69,9 +69,10 @@ void Tray::BuildPrototype(v8::Isolate* isolate,
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
using atom::api::Tray;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Isolate* isolate = context->GetIsolate();
v8::Handle<v8::Function> constructor = mate::CreateConstructor<Tray>(
isolate, "Tray", base::Bind(&Tray::New));
mate::Dictionary dict(isolate, exports);
@ -80,4 +81,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_browser_tray, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_tray, Initialize)

View file

@ -87,7 +87,7 @@ GURL WebContents::GetURL() const {
return web_contents()->GetURL();
}
string16 WebContents::GetTitle() const {
base::string16 WebContents::GetTitle() const {
return web_contents()->GetTitle();
}
@ -154,12 +154,12 @@ bool WebContents::IsCrashed() const {
return web_contents()->IsCrashed();
}
void WebContents::ExecuteJavaScript(const string16& code) {
void WebContents::ExecuteJavaScript(const base::string16& code) {
web_contents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
string16(), code);
base::string16(), code);
}
bool WebContents::SendIPCMessage(const string16& channel,
bool WebContents::SendIPCMessage(const base::string16& channel,
const base::ListValue& args) {
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
}
@ -190,17 +190,17 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("_send", &WebContents::SendIPCMessage);
}
void WebContents::OnRendererMessage(const string16& channel,
void WebContents::OnRendererMessage(const base::string16& channel,
const base::ListValue& args) {
// webContents.emit(channel, new Event(), args...);
Emit(UTF16ToUTF8(channel), args, web_contents(), NULL);
Emit(base::UTF16ToUTF8(channel), args, web_contents(), NULL);
}
void WebContents::OnRendererMessageSync(const string16& channel,
void WebContents::OnRendererMessageSync(const base::string16& channel,
const base::ListValue& args,
IPC::Message* message) {
// webContents.emit(channel, new Event(sender, message), args...);
Emit(UTF16ToUTF8(channel), args, web_contents(), message);
Emit(base::UTF16ToUTF8(channel), args, web_contents(), message);
}
// static

View file

@ -22,7 +22,7 @@ class WebContents : public mate::EventEmitter,
bool IsAlive() const;
void LoadURL(const GURL& url);
GURL GetURL() const;
string16 GetTitle() const;
base::string16 GetTitle() const;
bool IsLoading() const;
bool IsWaitingForResponse() const;
void Stop();
@ -38,8 +38,9 @@ class WebContents : public mate::EventEmitter,
int GetRoutingID() const;
int GetProcessID() const;
bool IsCrashed() const;
void ExecuteJavaScript(const string16& code);
bool SendIPCMessage(const string16& channel, const base::ListValue& args);
void ExecuteJavaScript(const base::string16& code);
bool SendIPCMessage(const base::string16& channel,
const base::ListValue& args);
protected:
explicit WebContents(content::WebContents* web_contents);
@ -65,10 +66,11 @@ class WebContents : public mate::EventEmitter,
private:
// Called when received a message from renderer.
void OnRendererMessage(const string16& channel, const base::ListValue& args);
void OnRendererMessage(const base::string16& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(const string16& channel,
void OnRendererMessageSync(const base::string16& channel,
const base::ListValue& args,
IPC::Message* message);

View file

@ -46,10 +46,11 @@ namespace api {
namespace {
void OnCapturePageDone(
v8::Isolate* isolate,
const base::Callback<void(v8::Handle<v8::Value>)>& callback,
const std::vector<unsigned char>& data) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> buffer = node::Buffer::New(
reinterpret_cast<const char*>(data.data()),
@ -311,7 +312,8 @@ void Window::CapturePage(mate::Arguments* args) {
return;
}
window_->CapturePage(rect, base::Bind(&OnCapturePageDone, callback));
window_->CapturePage(
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
}
void Window::SetRepresentedFilename(const std::string& filename) {
@ -391,14 +393,16 @@ void Window::BuildPrototype(v8::Isolate* isolate,
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
using atom::api::Window;
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<Window>(
node_isolate, "BrowserWindow", base::Bind(&Window::New));
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
isolate, "BrowserWindow", base::Bind(&Window::New));
mate::Dictionary dict(isolate, exports);
dict.Set("BrowserWindow", static_cast<v8::Handle<v8::Value>>(constructor));
}
} // namespace
NODE_MODULE(atom_browser_window, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_window, Initialize)

View file

@ -45,7 +45,7 @@ void Event::PreventDefault() {
prevent_default_ = true;
}
bool Event::SendReply(const string16& json) {
bool Event::SendReply(const base::string16& json) {
if (message_ == NULL || sender_ == NULL)
return false;

View file

@ -27,7 +27,7 @@ class Event : public Wrappable,
void PreventDefault();
// event.sendReply(json), used for replying synchronous message.
bool SendReply(const string16& json);
bool SendReply(const base::string16& json);
// Whether event.preventDefault() is called.
bool prevent_default() const { return prevent_default_; }

View file

@ -31,20 +31,21 @@ bool EventEmitter::Emit(const base::StringPiece& name,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
v8::Handle<v8::Context> context = isolate->GetCurrentContext();
scoped_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter);
mate::Handle<mate::Event> event = mate::Event::Create(node_isolate);
mate::Handle<mate::Event> event = mate::Event::Create(isolate);
if (sender && message)
event->SetSenderAndMessage(sender, message);
// v8_args = [name, event, args...];
std::vector<v8::Handle<v8::Value>> v8_args;
v8_args.reserve(args.GetSize() + 2);
v8_args.push_back(mate::StringToV8(node_isolate, name));
v8_args.push_back(mate::StringToV8(isolate, name));
v8_args.push_back(event.ToV8());
for (size_t i = 0; i < args.GetSize(); i++) {
const base::Value* value(NULL);
@ -53,8 +54,8 @@ bool EventEmitter::Emit(const base::StringPiece& name,
}
// this.emit.apply(this, v8_args);
node::MakeCallback(
GetWrapper(node_isolate), "emit", v8_args.size(), &v8_args[0]);
node::MakeCallback(isolate, GetWrapper(isolate), "emit", v8_args.size(),
&v8_args[0]);
return event->prevent_default();
}

View file

@ -38,16 +38,6 @@ class MenuItem
overrideProperty: (name, defaultValue=null) ->
this[name] ?= defaultValue
# Update states when property is changed on Windows.
return unless process.platform is 'win32'
v8Util.setHiddenValue this, name, this[name]
Object.defineProperty this, name,
enumerable: true
get: => v8Util.getHiddenValue this, name
set: (val) =>
v8Util.setHiddenValue this, name, val
@menu?._updateStates()
overrideReadOnlyProperty: (name, defaultValue=null) ->
this[name] ?= defaultValue
Object.defineProperty this, name,

View file

@ -76,9 +76,6 @@ Menu::insert = (pos, item) ->
v8Util.setHiddenValue otherItem, 'checked', false
v8Util.setHiddenValue item, 'checked', true
# Update states when clicked on Windows.
@_updateStates() if process.platform is 'win32'
@insertRadioItem pos, item.commandId, item.label, item.groupId
@setSublabel pos, item.sublabel if item.sublabel?
@ -90,10 +87,6 @@ Menu::insert = (pos, item) ->
@items.splice pos, 0, item
@commandsMap[item.commandId] = item
Menu::attachToWindow = (window) ->
@_callMenuWillShow() if process.platform is 'win32'
@_attachToWindow window
# Force menuWillShow to be called
Menu::_callMenuWillShow = ->
@delegate?.menuWillShow()

View file

@ -26,6 +26,10 @@ struct FindByProcessId {
}
bool operator() (NativeWindow* const window) {
content::WebContents* web_contents = window->GetWebContents();
if (!web_contents)
return false;
int id = window->GetWebContents()->GetRenderProcessHost()->GetID();
return id == child_process_id_;
}
@ -44,7 +48,8 @@ AtomBrowserClient::~AtomBrowserClient() {
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) {
content::ProtocolHandlerMap* protocol_handlers,
content::ProtocolHandlerScopedVector protocol_interceptors) {
return static_cast<AtomBrowserContext*>(browser_context)->
CreateRequestContext(protocol_handlers);
}
@ -77,7 +82,7 @@ void AtomBrowserClient::OverrideWebkitPrefs(
window->OverrideWebkitPrefs(url, prefs);
}
bool AtomBrowserClient::ShouldSwapProcessesForNavigation(
bool AtomBrowserClient::ShouldSwapBrowsingInstancesForNavigation(
content::SiteInstance* site_instance,
const GURL& current_url,
const GURL& new_url) {
@ -94,7 +99,7 @@ std::string AtomBrowserClient::GetApplicationLocale() {
}
void AtomBrowserClient::AppendExtraCommandLineSwitches(
CommandLine* command_line,
base::CommandLine* command_line,
int child_process_id) {
WindowList* list = WindowList::GetInstance();
NativeWindow* window = NULL;
@ -124,6 +129,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) {
v8::V8::Initialize(); // Init V8 before creating main parts.
return new AtomBrowserMainParts;
}

View file

@ -19,16 +19,17 @@ class AtomBrowserClient : public brightray::BrowserClient {
protected:
net::URLRequestContextGetter* CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
content::ProtocolHandlerMap* protocol_handlers,
content::ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE;
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
const GURL& url,
WebPreferences* prefs) OVERRIDE;
virtual bool ShouldSwapProcessesForNavigation(
virtual bool ShouldSwapBrowsingInstancesForNavigation(
content::SiteInstance* site_instance,
const GURL& current_url,
const GURL& new_url) OVERRIDE;
virtual std::string GetApplicationLocale() OVERRIDE;
virtual void AppendExtraCommandLineSwitches(CommandLine* command_line,
virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id) OVERRIDE;
private:

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 {
@ -25,7 +30,12 @@ AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
AtomBrowserMainParts::AtomBrowserMainParts()
: atom_bindings_(new AtomBindings),
browser_(new Browser),
node_bindings_(NodeBindings::Create(true)) {
node_bindings_(NodeBindings::Create(true)),
isolate_(v8::Isolate::GetCurrent()),
locker_(isolate_),
handle_scope_(isolate_),
context_(isolate_, v8::Context::New(isolate_)),
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
self_ = this;
}
@ -43,31 +53,34 @@ 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();
node_bindings_->Initialize();
v8::V8::Initialize();
// Create context.
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::Context> context = v8::Context::New(node_isolate);
// Create the global environment.
global_env = node_bindings_->CreateEnvironment(context);
// Wrap whole process in one global context.
context->Enter();
global_env = node_bindings_->CreateEnvironment(
v8::Local<v8::Context>::New(isolate_, context_));
// Add atom-shell extended APIs.
atom_bindings_->BindTo(global_env->process_object());
atom_bindings_->BindTo(isolate_, global_env->process_object());
}
void AtomBrowserMainParts::PreMainMessageLoopRun() {
brightray::BrowserMainParts::PreMainMessageLoopRun();
#if defined(USE_X11)
libgtk2ui::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
#endif
node_bindings_->PrepareMessageLoop();
node_bindings_->RunMessageLoop();
@ -83,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

@ -6,6 +6,7 @@
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
#include "brightray/browser/browser_main_parts.h"
#include "v8/include/v8.h"
namespace atom {
@ -25,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;
@ -40,6 +41,13 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
scoped_ptr<Browser> browser_;
scoped_ptr<NodeBindings> node_bindings_;
// The V8 environment of browser process.
v8::Isolate* isolate_;
v8::Locker locker_;
v8::HandleScope handle_scope_;
v8::UniquePersistent<v8::Context> context_;
v8::Context::Scope context_scope_;
static AtomBrowserMainParts* self_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts);

View file

@ -15,21 +15,21 @@ void AtomJavaScriptDialogManager::RunJavaScriptDialog(
const GURL& origin_url,
const std::string& accept_lang,
content::JavaScriptMessageType javascript_message_type,
const string16& message_text,
const string16& default_prompt_text,
const base::string16& message_text,
const base::string16& default_prompt_text,
const DialogClosedCallback& callback,
bool* did_suppress_message) {
callback.Run(false, string16());
callback.Run(false, base::string16());
}
void AtomJavaScriptDialogManager::RunBeforeUnloadDialog(
content::WebContents* web_contents,
const string16& message_text,
const base::string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) {
bool prevent_reload = message_text.empty() ||
message_text == ASCIIToUTF16("false");
message_text == base::ASCIIToUTF16("false");
callback.Run(!prevent_reload, message_text);
}

View file

@ -19,13 +19,13 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager {
const GURL& origin_url,
const std::string& accept_lang,
content::JavaScriptMessageType javascript_message_type,
const string16& message_text,
const string16& default_prompt_text,
const base::string16& message_text,
const base::string16& default_prompt_text,
const DialogClosedCallback& callback,
bool* did_suppress_message) OVERRIDE;
virtual void RunBeforeUnloadDialog(
content::WebContents* web_contents,
const string16& message_text,
const base::string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) OVERRIDE;
virtual void CancelActiveAndPendingDialogs(

View file

@ -44,7 +44,7 @@ std::string Browser::GetExecutableFileVersion() const {
if (PathService::Get(base::FILE_EXE, &path)) {
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(path));
return UTF16ToUTF8(version_info->product_version());
return base::UTF16ToUTF8(version_info->product_version());
}
return ATOM_VERSION_STRING;
@ -55,7 +55,7 @@ std::string Browser::GetExecutableFileProductName() const {
if (PathService::Get(base::FILE_EXE, &path)) {
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(path));
return UTF16ToUTF8(version_info->product_name());
return base::UTF16ToUTF8(version_info->product_name());
}
return "Atom-Shell";

View file

@ -78,7 +78,7 @@
};
</script>
<h2>Welcome to Atom Shell</h2>
<h2 style="-webkit-app-region: drag">Welcome to Atom Shell</h2>
<p>
To run your app with atom-shell, execute the following command under your

View file

@ -34,11 +34,13 @@
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/renderer_preferences.h"
#include "content/public/common/user_agent.h"
#include "ipc/ipc_message_macros.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/codec/png_codec.h"
@ -49,7 +51,6 @@
#include "ui/gfx/size.h"
#include "vendor/brightray/browser/inspectable_web_contents.h"
#include "vendor/brightray/browser/inspectable_web_contents_view.h"
#include "webkit/common/user_agent/user_agent_util.h"
#include "webkit/common/webpreferences.h"
using content::NavigationEntry;
@ -69,12 +70,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
brightray::InspectableWebContents::Create(web_contents)) {
options.Get(switches::kFrame, &has_frame_);
#if defined(OS_MACOSX)
// Temporary fix for flashing devtools, try removing this after upgraded to
// Chrome 32.
web_contents->GetView()->SetAllowOverlappingViews(false);
#endif
// Read icon before window is created.
gfx::ImageSkia icon;
if (options.Get(switches::kIcon, &icon))
@ -84,9 +79,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
options.Get(switches::kNodeIntegration, &node_integration_);
// Read the web preferences.
scoped_ptr<mate::Dictionary> web_preferences(new mate::Dictionary);
if (options.Get(switches::kWebPreferences, web_preferences.get()))
web_preferences_.reset(web_preferences.release());
options.Get(switches::kWebPreferences, &web_preferences_);
// Read the zoom factor before any navigation.
options.Get(switches::kZoomFactor, &zoom_factor_);
@ -104,7 +97,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
browser->GetVersion().c_str(),
CHROME_VERSION_STRING);
web_contents->GetMutableRendererPrefs()->user_agent_override =
webkit_glue::BuildUserAgentFromProduct(product_name);
content::BuildUserAgentFromProduct(product_name);
// Get notified of title updated message.
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
@ -202,17 +195,15 @@ void NativeWindow::SetRepresentedFilename(const std::string& filename) {
void NativeWindow::SetDocumentEdited(bool edited) {
}
void NativeWindow::SetMenu(ui::MenuModel* menu) {
}
bool NativeWindow::HasModalDialog() {
return has_dialog_attached_;
}
void NativeWindow::OpenDevTools() {
inspectable_web_contents()->ShowDevTools();
#if defined(OS_MACOSX)
// Temporary fix for flashing devtools, try removing this after upgraded to
// Chrome 32.
GetDevToolsWebContents()->GetView()->SetAllowOverlappingViews(false);
#endif
}
void NativeWindow::CloseDevTools() {
@ -271,7 +262,8 @@ void NativeWindow::CapturePage(const gfx::Rect& rect,
size,
base::Bind(&NativeWindow::OnCapturePageDone,
weak_factory_.GetWeakPtr(),
callback));
callback),
SkBitmap::kARGB_8888_Config);
}
void NativeWindow::DestroyWebContents() {
@ -305,7 +297,7 @@ void NativeWindow::CloseWebContents() {
ScheduleUnresponsiveEvent(5000);
if (web_contents->NeedToFireBeforeUnload())
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
web_contents->GetMainFrame()->DispatchBeforeUnload(false);
else
web_contents->Close();
}
@ -322,8 +314,8 @@ content::WebContents* NativeWindow::GetDevToolsWebContents() const {
return inspectable_web_contents()->devtools_web_contents();
}
void NativeWindow::AppendExtraCommandLineSwitches(CommandLine* command_line,
int child_process_id) {
void NativeWindow::AppendExtraCommandLineSwitches(
base::CommandLine* command_line, int child_process_id) {
// Append --node-integration to renderer process.
command_line->AppendSwitchASCII(switches::kNodeIntegration,
node_integration_);
@ -335,33 +327,32 @@ void NativeWindow::AppendExtraCommandLineSwitches(CommandLine* command_line,
}
void NativeWindow::OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs) {
// FIXME Disable accelerated composition in frameless window.
if (!has_frame_)
prefs->accelerated_compositing_enabled = false;
if (web_preferences_.IsEmpty())
return;
bool b;
std::vector<base::FilePath> list;
if (!web_preferences_)
return;
if (web_preferences_->Get("javascript", &b))
mate::Dictionary web_preferences(web_preferences_.isolate(),
web_preferences_.NewHandle());
if (web_preferences.Get("javascript", &b))
prefs->javascript_enabled = b;
if (web_preferences_->Get("web-security", &b))
if (web_preferences.Get("web-security", &b))
prefs->web_security_enabled = b;
if (web_preferences_->Get("images", &b))
if (web_preferences.Get("images", &b))
prefs->images_enabled = b;
if (web_preferences_->Get("java", &b))
if (web_preferences.Get("java", &b))
prefs->java_enabled = b;
if (web_preferences_->Get("text-areas-are-resizable", &b))
if (web_preferences.Get("text-areas-are-resizable", &b))
prefs->text_areas_are_resizable = b;
if (web_preferences_->Get("webgl", &b))
if (web_preferences.Get("webgl", &b))
prefs->experimental_webgl_enabled = b;
if (web_preferences_->Get("webaudio", &b))
if (web_preferences.Get("webaudio", &b))
prefs->webaudio_enabled = b;
if (web_preferences_->Get("accelerated-compositing", &b))
if (web_preferences.Get("accelerated-compositing", &b))
prefs->accelerated_compositing_enabled = b;
if (web_preferences_->Get("plugins", &b))
if (web_preferences.Get("plugins", &b))
prefs->plugins_enabled = b;
if (web_preferences_->Get("extra-plugin-dirs", &list))
if (web_preferences.Get("extra-plugin-dirs", &list))
for (size_t i = 0; i < list.size(); ++i)
content::PluginService::GetInstance()->AddExtraPluginDir(list[i]);
}
@ -517,7 +508,7 @@ void NativeWindow::Observe(int type,
if (title->first) {
bool prevent_default = false;
std::string text = UTF16ToUTF8(title->first->GetTitle());
std::string text = base::UTF16ToUTF8(title->first->GetTitle());
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnPageTitleUpdated(&prevent_default, text));
@ -537,19 +528,19 @@ void NativeWindow::DevToolsSaveToFile(const std::string& url,
path = it->second;
} else {
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url));
if (!file_dialog::ShowSaveDialog(this, url, default_path, &path))
if (!file_dialog::ShowSaveDialog(this, url, default_path, &path)) {
base::StringValue url_value(url);
CallDevToolsFunction("InspectorFrontendAPI.canceledSaveURL", &url_value);
return;
}
}
saved_files_[url] = path;
file_util::WriteFile(path, content.data(), content.size());
base::WriteFile(path, content.data(), content.size());
// Notify devtools.
base::StringValue url_value(url);
CallDevToolsFunction("InspectorFrontendAPI.savedURL", &url_value);
// TODO(zcbenz): In later Chrome we need to call canceledSaveURL when the save
// failed.
}
void NativeWindow::DevToolsAppendToFile(const std::string& url,
@ -557,7 +548,7 @@ void NativeWindow::DevToolsAppendToFile(const std::string& url,
PathsMap::iterator it = saved_files_.find(url);
if (it == saved_files_.end())
return;
file_util::AppendToFile(it->second, content.data(), content.size());
base::AppendToFile(it->second, content.data(), content.size());
// Notify devtools.
base::StringValue url_value(url);
@ -613,8 +604,9 @@ void NativeWindow::CallDevToolsFunction(const std::string& function_name,
}
}
}
GetDevToolsWebContents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
string16(), base::UTF8ToUTF16(function_name + "(" + params + ");"));
base::string16 javascript =
base::UTF8ToUTF16(function_name + "(" + params + ");");
GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
}
} // namespace atom

View file

@ -16,15 +16,20 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "atom/browser/native_window_observer.h"
#include "atom/browser/ui/accelerator_util.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_observer.h"
#include "native_mate/scoped_persistent.h"
#include "vendor/brightray/browser/default_web_contents_delegate.h"
#include "vendor/brightray/browser/inspectable_web_contents_delegate.h"
#include "vendor/brightray/browser/inspectable_web_contents_impl.h"
class CommandLine;
struct WebPreferences;
namespace base {
class CommandLine;
}
namespace content {
class BrowserContext;
class WebContents;
@ -41,6 +46,10 @@ namespace mate {
class Dictionary;
}
namespace ui {
class MenuModel;
}
namespace atom {
class AtomJavaScriptDialogManager;
@ -127,6 +136,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual bool IsKiosk() = 0;
virtual void SetRepresentedFilename(const std::string& filename);
virtual void SetDocumentEdited(bool edited);
virtual void SetMenu(ui::MenuModel* menu);
virtual bool HasModalDialog();
virtual gfx::NativeWindow GetNativeWindow() = 0;
@ -161,7 +171,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
content::WebContents* GetDevToolsWebContents() const;
// Called when renderer process is going to be started.
void AppendExtraCommandLineSwitches(CommandLine* command_line,
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id);
void OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs);
@ -281,7 +291,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
base::CancelableClosure window_unresposive_closure_;
// Web preferences.
scoped_ptr<mate::Dictionary> web_preferences_;
mate::ScopedPersistent<v8::Object> web_preferences_;
// Page's default zoom factor.
double zoom_factor_;

View file

@ -1,616 +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 "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"
#include "ui/gfx/skia_utils_gtk.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_, icon_->ToGdkPixbuf());
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 == WebKit::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 =
gfx::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 =
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
prefs->active_selection_fg_color =
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
prefs->inactive_selection_bg_color =
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
prefs->inactive_selection_fg_color =
gfx::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,155 +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 bool IsMaximized() 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();
// 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

@ -524,6 +524,12 @@ void NativeWindowMac::HandleKeyboardEvent(
void NativeWindowMac::InstallView() {
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
if (has_frame_) {
// Add layer with white background for the contents view.
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
[view setLayer:layer];
[view setWantsLayer:YES];
[view setFrame:[[window_ contentView] bounds]];
[[window_ contentView] addSubview:view];
} else {

View file

@ -0,0 +1,497 @@
// 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"
#if defined(OS_WIN)
#include <shobjidl.h>
#endif
#include <string>
#include <vector>
#include "atom/browser/ui/views/menu_bar.h"
#include "atom/browser/ui/views/menu_layout.h"
#include "atom/common/draggable_region.h"
#include "atom/common/options_switches.h"
#include "base/strings/utf_string_conversions.h"
#include "browser/inspectable_web_contents_view.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_contents_view.h"
#include "native_mate/dictionary.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/background.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/window/client_view.h"
#include "ui/views/widget/widget.h"
#if defined(USE_X11)
#include "atom/browser/ui/views/global_menu_bar_x11.h"
#include "atom/browser/ui/views/linux_frame_view.h"
#elif defined(OS_WIN)
#include "atom/browser/ui/views/win_frame_view.h"
#include "base/win/scoped_comptr.h"
#endif
namespace atom {
namespace {
// The menu bar height in pixels.
const int kMenuBarHeight = 25;
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),
menu_bar_(NULL),
web_view_(inspectable_web_contents()->GetView()->GetView()),
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
use_content_size_(false),
resizable_(true) {
options.Get(switches::kResizable, &resizable_);
options.Get(switches::kTitle, &title_);
int width = 800, height = 600;
options.Get(switches::kWidth, &width);
options.Get(switches::kHeight, &height);
gfx::Rect bounds(0, 0, width, height);
window_->AddObserver(this);
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.top_level = true;
#if defined(USE_X11)
// In X11 the window frame is drawn by the application.
params.remove_standard_frame = true;
#elif defined(OS_WIN)
if (!has_frame_)
params.remove_standard_frame = true;
#endif
#if defined(USE_X11)
// FIXME Find out how to do this dynamically on Linux.
bool skip_taskbar = false;
if (options.Get(switches::kSkipTaskbar, &skip_taskbar) && skip_taskbar)
params.type = views::Widget::InitParams::TYPE_BUBBLE;
#endif
window_->Init(params);
// Add web view.
SetLayoutManager(new MenuLayout(kMenuBarHeight));
set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_);
if (has_frame_ &&
options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_)
bounds = ContentBoundsToWindowBounds(bounds);
window_->CenterWindow(bounds.size());
Layout();
}
NativeWindowViews::~NativeWindowViews() {
window_->RemoveObserver(this);
}
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();
}
bool NativeWindowViews::IsMaximized() {
return window_->IsMaximized();
}
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) {
if (!has_frame_) {
SetSize(size);
return;
}
gfx::Rect bounds = window_->GetWindowBoundsInScreen();
bounds.set_size(size);
window_->SetBounds(ContentBoundsToWindowBounds(bounds));
}
gfx::Size NativeWindowViews::GetContentSize() {
if (!has_frame_)
return GetSize();
gfx::Size content_size =
window_->non_client_view()->frame_view()->GetBoundsForClientView().size();
if (menu_bar_)
content_size.set_height(content_size.height() - kMenuBarHeight);
return content_size;
}
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) {
resizable_ = resizable;
}
bool NativeWindowViews::IsResizable() {
return resizable_;
}
void NativeWindowViews::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top);
}
bool NativeWindowViews::IsAlwaysOnTop() {
return window_->IsAlwaysOnTop();
}
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) {
#if defined(OS_WIN)
base::win::ScopedComPtr<ITaskbarList> taskbar;
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
CLSCTX_INPROC_SERVER)) ||
FAILED(taskbar->HrInit()))
return;
if (skip)
taskbar->DeleteTab(GetAcceleratedWidget());
else
taskbar->AddTab(GetAcceleratedWidget());
#endif
}
void NativeWindowViews::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
}
bool NativeWindowViews::IsKiosk() {
return IsFullscreen();
}
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
RegisterAccelerators(menu_model);
#if defined(USE_X11)
if (!global_menu_bar_)
global_menu_bar_.reset(new GlobalMenuBarX11(this));
// Use global application menu bar when possible.
if (global_menu_bar_->IsServerStarted()) {
global_menu_bar_->SetMenu(menu_model);
return;
}
#endif
// Do not show menu bar in frameless window.
if (!has_frame_)
return;
if (!menu_bar_) {
gfx::Size content_size = GetContentSize();
menu_bar_ = new MenuBar;
AddChildViewAt(menu_bar_, 0);
if (use_content_size_)
SetContentSize(content_size);
}
menu_bar_->SetMenu(menu_model);
Layout();
}
gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
return window_->GetNativeWindow();
}
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() {
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
}
void NativeWindowViews::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
if (has_frame_)
return;
SkRegion* draggable_region = 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);
}
draggable_region_.reset(draggable_region);
}
void NativeWindowViews::OnWidgetActivationChanged(
views::Widget* widget, bool active) {
if (widget != window_.get())
return;
if (active)
NotifyWindowFocus();
else
NotifyWindowBlur();
}
void NativeWindowViews::DeleteDelegate() {
NotifyWindowClosed();
}
views::View* NativeWindowViews::GetInitiallyFocusedView() {
return inspectable_web_contents()->GetView()->GetWebView();
}
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;
}
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) {
// App window should claim mouse events that fall within the draggable region.
if (draggable_region_ &&
draggable_region_->contains(location.x(), location.y()))
return false;
// And the events on border for dragging resizable frameless window.
if (!has_frame_ && CanResize()) {
FramelessView* frame = static_cast<FramelessView*>(
window_->non_client_view()->frame_view());
return frame->ResizingBorderHitTest(location) == HTNOWHERE;
}
return true;
}
views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
return new NativeWindowClientView(widget, this);
}
views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
views::Widget* widget) {
#if defined(USE_X11)
LinuxFrameView* frame_view = new LinuxFrameView;
#else
WinFrameView* frame_view = new WinFrameView;
#endif
frame_view->Init(this, widget);
return frame_view;
}
void NativeWindowViews::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
keyboard_event_handler_->HandleKeyboardEvent(event, GetFocusManager());
}
bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
return accelerator_util::TriggerAcceleratorTableCommand(
&accelerator_table_, accelerator);
}
void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
// Clear previous accelerators.
views::FocusManager* focus_manager = GetFocusManager();
accelerator_table_.clear();
focus_manager->UnregisterAccelerators(this);
// Register accelerators with focus manager.
accelerator_util::GenerateAcceleratorTable(&accelerator_table_, menu_model);
accelerator_util::AcceleratorTable::const_iterator iter;
for (iter = accelerator_table_.begin();
iter != accelerator_table_.end();
++iter) {
focus_manager->RegisterAccelerator(
iter->first, ui::AcceleratorManager::kNormalPriority, this);
}
}
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
const gfx::Rect& bounds) {
gfx::Rect window_bounds =
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
if (menu_bar_)
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
return window_bounds;
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
const mate::Dictionary& options) {
return new NativeWindowViews(web_contents, options);
}
} // namespace atom

View file

@ -1,44 +1,38 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// 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_WIN_H_
#define ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
#ifndef ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
#define ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
#include "atom/browser/native_window.h"
#include <map>
#include <string>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/accelerator_util.h"
#include "ui/gfx/size.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/widget/widget_delegate.h"
#include "vendor/brightray/browser/win/inspectable_web_contents_view_win.h"
namespace ui {
class MenuModel;
}
#include "ui/views/widget/widget_observer.h"
namespace views {
class UnhandledKeyboardEventHandler;
class Widget;
}
namespace atom {
class Menu2;
class GlobalMenuBarX11;
class MenuBar;
class NativeWindowWin : public NativeWindow,
public views::WidgetFocusChangeListener,
public views::WidgetDelegateView {
class NativeWindowViews : public NativeWindow,
public views::WidgetDelegateView,
public views::WidgetObserver {
public:
explicit NativeWindowWin(content::WebContents* web_contents,
const mate::Dictionary& options);
virtual ~NativeWindowWin();
explicit NativeWindowViews(content::WebContents* web_contents,
const mate::Dictionary& options);
virtual ~NativeWindowViews();
// NativeWindow implementation.
// NativeWindow:
virtual void Close() OVERRIDE;
virtual void CloseImmediately() OVERRIDE;
virtual void Move(const gfx::Rect& pos) OVERRIDE;
@ -75,89 +69,82 @@ class NativeWindowWin : public NativeWindow,
virtual void SetSkipTaskbar(bool skip) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual void SetMenu(ui::MenuModel* menu_model) OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
void OnMenuCommand(int position, HMENU menu);
gfx::AcceleratedWidget GetAcceleratedWidget();
// Set the native window menu.
void SetMenu(ui::MenuModel* menu_model);
SkRegion* draggable_region() const { return draggable_region_.get(); }
views::Widget* widget() const { return window_.get(); }
brightray::InspectableWebContentsViewWin* inspectable_web_contents_view()
const {
return static_cast<brightray::InspectableWebContentsViewWin*>(
inspectable_web_contents()->GetView());
}
views::Widget* window() const { return window_.get(); }
atom::Menu2* menu() const { return menu_.get(); }
SkRegion* draggable_region() { return draggable_region_.get(); }
protected:
private:
// NativeWindow:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
// Overridden from content::WebContentsDelegate:
virtual void HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE;
// views::WidgetObserver:
virtual void OnWidgetActivationChanged(
views::Widget* widget, bool active) OVERRIDE;
// Overridden from views::View:
virtual void Layout() OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
// Overridden from views::WidgetDelegate:
// views::WidgetDelegate:
virtual void DeleteDelegate() OVERRIDE;
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
virtual bool CanResize() const OVERRIDE;
virtual bool CanMaximize() const OVERRIDE;
virtual string16 GetWindowTitle() 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 bool ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) OVERRIDE;
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
virtual views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) OVERRIDE;
// Overridden from views::WidgetFocusChangeListener:
virtual void OnNativeFocusChange(gfx::NativeView focused_before,
gfx::NativeView focused_now) OVERRIDE;
// content::WebContentsDelegate:
virtual void HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) OVERRIDE;
private:
typedef struct { int position; ui::MenuModel* model; } MenuItem;
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
void ClientAreaSizeToWindowSize(gfx::Size* size);
void OnViewWasResized();
// views::View:
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
// Register accelerators supported by the menu model.
void RegisterAccelerators();
void RegisterAccelerators(ui::MenuModel* menu_model);
// Converts between client area and window area, since we include the menu bar
// in client area we need to substract/add menu bar's height in convertions.
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& content_bounds);
scoped_ptr<views::Widget> window_;
views::View* web_view_; // managed by window_.
MenuBar* menu_bar_;
views::View* web_view_; // Managed by inspectable_web_contents_.
// The window menu.
scoped_ptr<atom::Menu2> menu_;
#if defined(USE_X11)
scoped_ptr<GlobalMenuBarX11> global_menu_bar_;
#endif
// Handles unhandled keyboard messages coming back from the renderer process.
scoped_ptr<views::UnhandledKeyboardEventHandler> keyboard_event_handler_;
// Map from accelerator to menu item's command id.
accelerator_util::AcceleratorTable accelerator_table_;
scoped_ptr<SkRegion> draggable_region_;
bool use_content_size_;
bool resizable_;
string16 title_;
std::string title_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowWin);
scoped_ptr<SkRegion> draggable_region_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
#endif // ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_

View file

@ -1,636 +0,0 @@
// Copyright (c) 2013 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_win.h"
#include <shobjidl.h>
#include <string>
#include <vector>
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/ui/win/menu_2.h"
#include "atom/browser/ui/win/native_menu_win.h"
#include "atom/common/draggable_region.h"
#include "atom/common/options_switches.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_comptr.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/path.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/native_widget_win.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/native_frame_view.h"
namespace atom {
namespace {
const int kResizeInsideBoundsSize = 5;
const int kResizeAreaCornerSize = 16;
// Returns true if |possible_parent| is a parent window of |child|.
bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) {
if (!child)
return false;
if (::GetWindow(child, GW_OWNER) == possible_parent)
return true;
gfx::NativeView parent = ::GetParent(child);
while (parent) {
if (possible_parent == parent)
return true;
parent = ::GetParent(parent);
}
return false;
}
// Wrapper of NativeWidgetWin to handle WM_MENUCOMMAND messages, which are
// triggered by window menus.
class MenuCommandNativeWidget : public views::NativeWidgetWin {
public:
explicit MenuCommandNativeWidget(NativeWindowWin* delegate)
: views::NativeWidgetWin(delegate->window()),
delegate_(delegate) {}
virtual ~MenuCommandNativeWidget() {}
protected:
virtual bool PreHandleMSG(UINT message,
WPARAM w_param,
LPARAM l_param,
LRESULT* result) OVERRIDE {
if (message == WM_MENUCOMMAND) {
delegate_->OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
*result = 0;
return true;
} else {
return false;
}
}
private:
NativeWindowWin* delegate_;
DISALLOW_COPY_AND_ASSIGN(MenuCommandNativeWidget);
};
class NativeWindowClientView : public views::ClientView {
public:
NativeWindowClientView(views::Widget* widget,
NativeWindowWin* contents_view)
: views::ClientView(widget, contents_view) {
}
virtual ~NativeWindowClientView() {}
virtual bool CanClose() OVERRIDE {
static_cast<NativeWindowWin*>(contents_view())->CloseWebContents();
return false;
}
private:
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
};
class NativeWindowFrameView : public views::NativeFrameView {
public:
explicit NativeWindowFrameView(views::Widget* frame, NativeWindowWin* shell)
: NativeFrameView(frame),
shell_(shell) {
}
virtual ~NativeWindowFrameView() {}
virtual gfx::Size GetMinimumSize() OVERRIDE {
return shell_->GetMinimumSize();
}
virtual gfx::Size GetMaximumSize() OVERRIDE {
return shell_->GetMaximumSize();
}
private:
NativeWindowWin* shell_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
};
class NativeWindowFramelessView : public views::NonClientFrameView {
public:
explicit NativeWindowFramelessView(views::Widget* frame,
NativeWindowWin* shell)
: frame_(frame),
shell_(shell) {
}
virtual ~NativeWindowFramelessView() {}
// views::NonClientFrameView implementations:
virtual gfx::Rect NativeWindowFramelessView::GetBoundsForClientView() const
OVERRIDE {
return bounds();
}
virtual gfx::Rect NativeWindowFramelessView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const OVERRIDE {
gfx::Rect window_bounds = client_bounds;
// Enforce minimum size (1, 1) in case that client_bounds is passed with
// empty size. This could occur when the frameless window is being
// initialized.
if (window_bounds.IsEmpty()) {
window_bounds.set_width(1);
window_bounds.set_height(1);
}
return window_bounds;
}
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
if (frame_->IsFullscreen())
return HTCLIENT;
// Check the frame first, as we allow a small area overlapping the contents
// to be used for resize handles.
bool can_ever_resize = frame_->widget_delegate() ?
frame_->widget_delegate()->CanResize() :
false;
// Don't allow overlapping resize handles when the window is maximized or
// fullscreen, as it can't be resized in those states.
int resize_border =
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
kResizeInsideBoundsSize;
int frame_component = GetHTComponentForFrame(point,
resize_border,
resize_border,
kResizeAreaCornerSize,
kResizeAreaCornerSize,
can_ever_resize);
if (frame_component != HTNOWHERE)
return frame_component;
// Check for possible draggable region in the client area for the frameless
// window.
if (shell_->draggable_region() &&
shell_->draggable_region()->contains(point.x(), point.y()))
return HTCAPTION;
int client_component = frame_->client_view()->NonClientHitTest(point);
if (client_component != HTNOWHERE)
return client_component;
// Caption is a safe default.
return HTCAPTION;
}
virtual void GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) OVERRIDE {}
virtual void ResetWindowControls() OVERRIDE {}
virtual void UpdateWindowIcon() OVERRIDE {}
virtual void UpdateWindowTitle() OVERRIDE {}
// views::View implementations:
virtual gfx::Size NativeWindowFramelessView::GetPreferredSize() OVERRIDE {
gfx::Size pref = frame_->client_view()->GetPreferredSize();
gfx::Rect bounds(0, 0, pref.width(), pref.height());
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
bounds).size();
}
virtual gfx::Size GetMinimumSize() OVERRIDE {
return shell_->GetMinimumSize();
}
virtual gfx::Size GetMaximumSize() OVERRIDE {
return shell_->GetMaximumSize();
}
private:
views::Widget* frame_;
NativeWindowWin* shell_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
};
} // namespace
NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
const mate::Dictionary& options)
: NativeWindow(web_contents, options),
window_(new views::Widget),
web_view_(inspectable_web_contents_view()->GetView()),
use_content_size_(false),
resizable_(true) {
options.Get(switches::kResizable, &resizable_);
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.delegate = this;
params.native_widget = new MenuCommandNativeWidget(this);
params.remove_standard_frame = !has_frame_;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
window_->Init(params);
views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
int width = 800, height = 600;
options.Get(switches::kWidth, &width);
options.Get(switches::kHeight, &height);
gfx::Size size(width, height);
options.Get(switches::kUseContentSize, &use_content_size_);
if (has_frame_ && use_content_size_)
ClientAreaSizeToWindowSize(&size);
window_->CenterWindow(size);
window_->UpdateWindowIcon();
OnViewWasResized();
}
NativeWindowWin::~NativeWindowWin() {
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
}
void NativeWindowWin::Close() {
window_->Close();
}
void NativeWindowWin::CloseImmediately() {
window_->CloseNow();
}
void NativeWindowWin::Move(const gfx::Rect& bounds) {
window_->SetBounds(bounds);
}
void NativeWindowWin::Focus(bool focus) {
if (focus)
window_->Activate();
else
window_->Deactivate();
}
bool NativeWindowWin::IsFocused() {
return window_->IsActive();
}
void NativeWindowWin::Show() {
window_->Show();
}
void NativeWindowWin::Hide() {
window_->Hide();
}
void NativeWindowWin::Maximize() {
window_->Maximize();
}
void NativeWindowWin::Unmaximize() {
window_->Restore();
}
bool NativeWindowWin::IsMaximized() {
return window_->IsMaximized();
}
bool NativeWindowWin::IsVisible() {
return window_->IsVisible();
}
void NativeWindowWin::Minimize() {
window_->Minimize();
}
void NativeWindowWin::Restore() {
window_->Restore();
}
void NativeWindowWin::SetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
}
bool NativeWindowWin::IsFullscreen() {
return window_->IsFullscreen();
}
void NativeWindowWin::SetSize(const gfx::Size& size) {
window_->SetSize(size);
}
gfx::Size NativeWindowWin::GetSize() {
return window_->GetWindowBoundsInScreen().size();
}
void NativeWindowWin::SetContentSize(const gfx::Size& size) {
gfx::Size resized(size);
ClientAreaSizeToWindowSize(&resized);
SetSize(resized);
}
gfx::Size NativeWindowWin::GetContentSize() {
return window_->GetClientAreaBoundsInScreen().size();
}
void NativeWindowWin::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size;
}
gfx::Size NativeWindowWin::GetMinimumSize() {
return minimum_size_;
}
void NativeWindowWin::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
}
gfx::Size NativeWindowWin::GetMaximumSize() {
return maximum_size_;
}
void NativeWindowWin::SetResizable(bool resizable) {
resizable_ = resizable;
// WS_MAXIMIZEBOX => Maximize/Minimize button
// WS_THICKFRAME => Resize handle
DWORD style = ::GetWindowLong(GetNativeWindow(), GWL_STYLE);
if (resizable)
style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
else
style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
::SetWindowLong(GetNativeWindow(), GWL_STYLE, style);
}
bool NativeWindowWin::IsResizable() {
return resizable_;
}
void NativeWindowWin::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top);
}
bool NativeWindowWin::IsAlwaysOnTop() {
DWORD style = ::GetWindowLong(window_->GetNativeView(), GWL_EXSTYLE);
return style & WS_EX_TOPMOST;
}
void NativeWindowWin::Center() {
window_->CenterWindow(GetSize());
}
void NativeWindowWin::SetPosition(const gfx::Point& position) {
window_->SetBounds(gfx::Rect(position, GetSize()));
}
gfx::Point NativeWindowWin::GetPosition() {
return window_->GetWindowBoundsInScreen().origin();
}
void NativeWindowWin::SetTitle(const std::string& title) {
title_ = UTF8ToUTF16(title);
window_->UpdateWindowTitle();
}
std::string NativeWindowWin::GetTitle() {
return UTF16ToUTF8(title_);
}
void NativeWindowWin::FlashFrame(bool flash) {
window_->FlashFrame(flash);
}
void NativeWindowWin::SetSkipTaskbar(bool skip) {
base::win::ScopedComPtr<ITaskbarList> taskbar;
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
CLSCTX_INPROC_SERVER)) ||
FAILED(taskbar->HrInit()))
return;
if (skip)
taskbar->DeleteTab(GetNativeWindow());
else
taskbar->AddTab(GetNativeWindow());
}
void NativeWindowWin::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
}
bool NativeWindowWin::IsKiosk() {
return IsFullscreen();
}
gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
return window_->GetNativeView();
}
void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
DCHECK(menu_);
menu_->wrapper()->OnMenuCommand(position, menu);
}
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
menu_.reset(new atom::Menu2(menu_model, true));
menu_->UpdateStates();
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
RegisterAccelerators();
// Resize the window so SetMenu won't change client area size.
if (use_content_size_) {
gfx::Size size = GetSize();
size.set_height(size.height() + GetSystemMetrics(SM_CYMENU));
SetSize(size);
}
}
void NativeWindowWin::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
if (has_frame_)
return;
SkRegion* draggable_region = 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);
}
draggable_region_.reset(draggable_region);
OnViewWasResized();
}
void NativeWindowWin::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
if (event.type == WebKit::WebInputEvent::RawKeyDown) {
ui::Accelerator accelerator(
static_cast<ui::KeyboardCode>(event.windowsKeyCode),
content::GetModifiersFromNativeWebKeyboardEvent(event));
if (GetFocusManager()->ProcessAccelerator(accelerator)) {
return;
}
}
// Any unhandled keyboard/character messages should be defproced.
// This allows stuff like F10, etc to work correctly.
DefWindowProc(event.os_event.hwnd, event.os_event.message,
event.os_event.wParam, event.os_event.lParam);
}
void NativeWindowWin::Layout() {
DCHECK(web_view_);
web_view_->SetBounds(0, 0, width(), height());
OnViewWasResized();
}
void NativeWindowWin::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && details.child == this)
AddChildView(web_view_);
}
bool NativeWindowWin::AcceleratorPressed(
const ui::Accelerator& accelerator) {
return accelerator_util::TriggerAcceleratorTableCommand(
&accelerator_table_, accelerator);
}
void NativeWindowWin::DeleteDelegate() {
NotifyWindowClosed();
}
views::View* NativeWindowWin::GetInitiallyFocusedView() {
return inspectable_web_contents_view()->GetWebView();
}
bool NativeWindowWin::CanResize() const {
return resizable_;
}
bool NativeWindowWin::CanMaximize() const {
return resizable_;
}
string16 NativeWindowWin::GetWindowTitle() const {
return title_;
}
bool NativeWindowWin::ShouldHandleSystemCommands() const {
return true;
}
gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
if (icon_)
return *(icon_->ToImageSkia());
else
return gfx::ImageSkia();
}
gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
return GetWindowAppIcon();
}
views::Widget* NativeWindowWin::GetWidget() {
return window_.get();
}
const views::Widget* NativeWindowWin::GetWidget() const {
return window_.get();
}
views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
return new NativeWindowClientView(widget, this);
}
views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
views::Widget* widget) {
if (has_frame_)
return new NativeWindowFrameView(widget, this);
return new NativeWindowFramelessView(widget, this);
}
void NativeWindowWin::OnNativeFocusChange(gfx::NativeView focused_before,
gfx::NativeView focused_now) {
gfx::NativeView this_window = GetWidget()->GetNativeView();
if (IsParent(focused_now, this_window))
return;
if (focused_now == this_window)
NotifyWindowFocus();
else if (focused_before == this_window)
NotifyWindowBlur();
}
void NativeWindowWin::ClientAreaSizeToWindowSize(gfx::Size* size) {
gfx::Size window = window_->GetWindowBoundsInScreen().size();
gfx::Size client = window_->GetClientAreaBoundsInScreen().size();
size->set_width(size->width() + window.width() - client.width());
size->set_height(size->height() + window.height() - client.height());
}
void NativeWindowWin::OnViewWasResized() {
// Set the window shape of the RWHV.
gfx::Size sz = web_view_->size();
int height = sz.height(), width = sz.width();
gfx::Path path;
path.addRect(0, 0, width, height);
SetWindowRgn(web_contents()->GetView()->GetNativeView(),
path.CreateNativeRegion(),
1);
SkRegion* rgn = new SkRegion;
if (!window_->IsFullscreen() && !window_->IsMaximized()) {
if (draggable_region())
rgn->op(*draggable_region(), SkRegion::kUnion_Op);
if (!has_frame_ && CanResize()) {
rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
SkRegion::kUnion_Op);
rgn->op(0, height - kResizeInsideBoundsSize, width, height,
SkRegion::kUnion_Op);
}
}
content::WebContents* web_contents = GetWebContents();
if (web_contents->GetRenderViewHost()->GetView())
web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
}
void NativeWindowWin::RegisterAccelerators() {
views::FocusManager* focus_manager = GetFocusManager();
accelerator_table_.clear();
focus_manager->UnregisterAccelerators(this);
accelerator_util::GenerateAcceleratorTable(&accelerator_table_,
menu_->model());
accelerator_util::AcceleratorTable::const_iterator iter;
for (iter = accelerator_table_.begin();
iter != accelerator_table_.end();
++iter) {
focus_manager->RegisterAccelerator(
iter->first, ui::AcceleratorManager::kNormalPriority, this);
}
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
const mate::Dictionary& options) {
return new NativeWindowWin(web_contents, options);
}
} // namespace atom

View file

@ -32,6 +32,7 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "vendor/brightray/browser/network_delegate.h"
#include "webkit/browser/quota/special_storage_policy.h"
namespace atom {
@ -75,18 +76,18 @@ net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
url_request_context_->set_network_delegate(network_delegate_.get());
storage_.reset(
new net::URLRequestContextStorage(url_request_context_.get()));
storage_->set_cookie_store(content::CreatePersistentCookieStore(
auto cookie_config = content::CookieStoreConfig(
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
false,
content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
nullptr,
nullptr,
nullptr));
nullptr);
storage_->set_cookie_store(content::CreateCookieStore(cookie_config));
storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
new net::DefaultServerBoundCertStore(NULL),
base::WorkerPool::GetTaskRunner(true)));
storage_->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings(
"en-us,en", EmptyString()));
"en-us,en", base::EmptyString()));
scoped_ptr<net::HostResolver> host_resolver(
net::HostResolver::CreateDefaultResolver(NULL));
@ -163,9 +164,9 @@ net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
content::BrowserThread::GetBlockingPool()->
GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
job_factory_->SetProtocolHandler(chrome::kDataScheme,
job_factory_->SetProtocolHandler(content::kDataScheme,
new net::DataProtocolHandler);
job_factory_->SetProtocolHandler(chrome::kFileScheme,
job_factory_->SetProtocolHandler(content::kFileScheme,
file_protocol_handler.release());
storage_->set_job_factory(job_factory_);
}

View file

@ -1,20 +0,0 @@
// Copyright (c) 2013 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/accelerator_util.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_gtk.h"
namespace accelerator_util {
void SetPlatformAccelerator(ui::Accelerator* accelerator) {
scoped_ptr<ui::PlatformAccelerator> platform_accelerator(
new ui::PlatformAcceleratorGtk(
GetGdkKeyCodeForAccelerator(*accelerator),
GetGdkModifierForAccelerator(*accelerator)));
accelerator->set_platform_accelerator(platform_accelerator.Pass());
}
} // namespace accelerator_util

View file

@ -131,7 +131,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
- (void)addItemToMenu:(NSMenu*)menu
atIndex:(NSInteger)index
fromModel:(ui::MenuModel*)model {
string16 label16 = model->GetLabelAt(index);
base::string16 label16 = model->GetLabelAt(index);
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
base::scoped_nsobject<NSMenuItem> item(
[[NSMenuItem alloc] initWithTitle:label

View file

@ -4,16 +4,47 @@
#include "atom/browser/ui/file_dialog.h"
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
// This conflicts with mate::Converter,
#undef True
#undef False
// and V8.
#undef None
#include "atom/browser/native_window.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "ui/base/gtk/gtk_signal.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
namespace file_dialog {
namespace {
const char kAuraTransientParent[] = "aura-transient-parent";
void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
if (!parent || !parent->GetHost())
return;
gtk_widget_realize(dialog);
GdkWindow* gdk_window = gtk_widget_get_window(dialog);
// TODO(erg): Check to make sure we're using X11 if wayland or some other
// display server ever happens. Otherwise, this will crash.
XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window),
GDK_WINDOW_XID(gdk_window),
parent->GetHost()->GetAcceleratedWidget());
// We also set the |parent| as a property of |dialog|, so that we can unlink
// the two later.
g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent);
}
class FileChooserDialog {
public:
FileChooserDialog(GtkFileChooserAction action,
@ -27,14 +58,17 @@ class FileChooserDialog {
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
confirm_text = GTK_STOCK_OPEN;
GtkWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
dialog_ = gtk_file_chooser_dialog_new(
title.c_str(),
window,
NULL,
action,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
confirm_text, GTK_RESPONSE_ACCEPT,
NULL);
if (parent_window) {
gfx::NativeWindow window = parent_window->GetNativeWindow();
SetGtkTransientForAura(dialog_, window);
}
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog_),
@ -42,10 +76,6 @@ class FileChooserDialog {
if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE);
// Set window-to-parent modality by adding the dialog to the same window
// group as the parent.
gtk_window_group_add_window(gtk_window_get_group(window),
GTK_WINDOW(dialog_));
gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
if (!default_path.empty()) {

View file

@ -9,7 +9,7 @@
#include <commdlg.h>
#include <shlobj.h>
#include "atom/browser/native_window.h"
#include "atom/browser/native_window_views.h"
#include "base/file_util.h"
#include "base/i18n/case_conversion.h"
#include "base/strings/string_util.h"
@ -25,8 +25,8 @@ namespace {
// Distinguish directories from regular files.
bool IsDirectory(const base::FilePath& path) {
base::PlatformFileInfo file_info;
return file_util::GetFileInfo(path, &file_info) ?
base::File::Info file_info;
return base::GetFileInfo(path, &file_info) ?
file_info.is_directory : path.EndsWithSeparator();
}
@ -105,7 +105,7 @@ void FormatFilterForExtensions(
// the we create a description "QQQ File (.qqq)").
include_all_files = true;
// TODO(zcbenz): should be localized.
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
desc = base::i18n::ToUpper(base::WideToUTF16(ext_name)) + L" File";
}
desc += L" (*." + ext_name + L")";
@ -157,14 +157,16 @@ class FileDialog {
filters.size()));
if (!title.empty())
GetPtr()->SetTitle(UTF8ToUTF16(title).c_str());
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
SetDefaultFolder(default_path);
}
bool Show(atom::NativeWindow* parent_window) {
atom::NativeWindow::DialogScope dialog_scope(parent_window);
HWND window = parent_window ? parent_window->GetNativeWindow() : NULL;
HWND window = parent_window ? static_cast<atom::NativeWindowViews*>(
parent_window)->GetAcceleratedWidget() :
NULL;
return dialog_->DoModal(window) == IDOK;
}

View file

@ -1,268 +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/gtk/app_indicator_icon.h"
#include <gtk/gtk.h>
#include <dlfcn.h>
#include "base/file_util.h"
#include "base/guid.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/ui/gtk/menu_gtk.h"
#include "content/public/browser/browser_thread.h"
#include "ui/gfx/image/image.h"
namespace {
typedef enum {
APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
APP_INDICATOR_CATEGORY_COMMUNICATIONS,
APP_INDICATOR_CATEGORY_SYSTEM_SERVICES,
APP_INDICATOR_CATEGORY_HARDWARE,
APP_INDICATOR_CATEGORY_OTHER
} AppIndicatorCategory;
typedef enum {
APP_INDICATOR_STATUS_PASSIVE,
APP_INDICATOR_STATUS_ACTIVE,
APP_INDICATOR_STATUS_ATTENTION
} AppIndicatorStatus;
typedef AppIndicator* (*app_indicator_new_func)(const gchar* id,
const gchar* icon_name,
AppIndicatorCategory category);
typedef AppIndicator* (*app_indicator_new_with_path_func)(
const gchar* id,
const gchar* icon_name,
AppIndicatorCategory category,
const gchar* icon_theme_path);
typedef void (*app_indicator_set_status_func)(AppIndicator* self,
AppIndicatorStatus status);
typedef void (*app_indicator_set_attention_icon_full_func)(
AppIndicator* self,
const gchar* icon_name,
const gchar* icon_desc);
typedef void (*app_indicator_set_menu_func)(AppIndicator* self, GtkMenu* menu);
typedef void (*app_indicator_set_icon_full_func)(AppIndicator* self,
const gchar* icon_name,
const gchar* icon_desc);
typedef void (*app_indicator_set_icon_theme_path_func)(
AppIndicator* self,
const gchar* icon_theme_path);
bool g_attempted_load = false;
bool g_opened = false;
// Retrieved functions from libappindicator.
app_indicator_new_func app_indicator_new = NULL;
app_indicator_new_with_path_func app_indicator_new_with_path = NULL;
app_indicator_set_status_func app_indicator_set_status = NULL;
app_indicator_set_attention_icon_full_func
app_indicator_set_attention_icon_full = NULL;
app_indicator_set_menu_func app_indicator_set_menu = NULL;
app_indicator_set_icon_full_func app_indicator_set_icon_full = NULL;
app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL;
void EnsureMethodsLoaded() {
if (g_attempted_load)
return;
g_attempted_load = true;
void* indicator_lib = dlopen("libappindicator.so", RTLD_LAZY);
if (!indicator_lib) {
indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY);
}
if (!indicator_lib) {
indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY);
}
if (!indicator_lib) {
return;
}
g_opened = true;
app_indicator_new = reinterpret_cast<app_indicator_new_func>(
dlsym(indicator_lib, "app_indicator_new"));
app_indicator_new_with_path =
reinterpret_cast<app_indicator_new_with_path_func>(
dlsym(indicator_lib, "app_indicator_new_with_path"));
app_indicator_set_status = reinterpret_cast<app_indicator_set_status_func>(
dlsym(indicator_lib, "app_indicator_set_status"));
app_indicator_set_attention_icon_full =
reinterpret_cast<app_indicator_set_attention_icon_full_func>(
dlsym(indicator_lib, "app_indicator_set_attention_icon_full"));
app_indicator_set_menu = reinterpret_cast<app_indicator_set_menu_func>(
dlsym(indicator_lib, "app_indicator_set_menu"));
app_indicator_set_icon_full =
reinterpret_cast<app_indicator_set_icon_full_func>(
dlsym(indicator_lib, "app_indicator_set_icon_full"));
app_indicator_set_icon_theme_path =
reinterpret_cast<app_indicator_set_icon_theme_path_func>(
dlsym(indicator_lib, "app_indicator_set_icon_theme_path"));
}
base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr,
int icon_change_count,
std::string id) {
scoped_ptr<gfx::ImageSkia> image(image_ptr);
scoped_refptr<base::RefCountedMemory> png_data =
gfx::Image(*image.get()).As1xPNGBytes();
if (png_data->size() == 0) {
// If the bitmap could not be encoded to PNG format, skip it.
LOG(WARNING) << "Could not encode icon";
return base::FilePath();
}
base::FilePath temp_dir;
base::FilePath new_file_path;
// Create a new temporary directory for each image since using a single
// temporary directory seems to have issues when changing icons in quick
// succession.
if (!file_util::CreateNewTempDirectory(base::FilePath::StringType(),
&temp_dir))
return base::FilePath();
new_file_path =
temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count));
int bytes_written =
file_util::WriteFile(
new_file_path,
reinterpret_cast<const char*>(png_data->front()),
png_data->size());
if (bytes_written != static_cast<int>(png_data->size()))
return base::FilePath();
return new_file_path;
}
void DeleteTempImagePath(const base::FilePath& icon_file_path) {
if (icon_file_path.empty())
return;
base::DeleteFile(icon_file_path, true);
}
} // namespace
namespace atom {
AppIndicatorIcon::AppIndicatorIcon()
: icon_(NULL),
id_(base::GenerateGUID()),
icon_change_count_(0),
weak_factory_(this) {
}
AppIndicatorIcon::~AppIndicatorIcon() {
if (icon_) {
app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
g_object_unref(icon_);
content::BrowserThread::GetBlockingPool()->PostTask(
FROM_HERE,
base::Bind(&DeleteTempImagePath, icon_file_path_.DirName()));
}
}
bool AppIndicatorIcon::CouldOpen() {
EnsureMethodsLoaded();
return g_opened;
}
void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) {
if (!g_opened)
return;
++icon_change_count_;
// We create a deep copy of the image since it may have been freed by the time
// it's accessed in the other thread.
scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy());
base::PostTaskAndReplyWithResult(
content::BrowserThread::GetBlockingPool()
->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
FROM_HERE,
base::Bind(&CreateTempImageFile,
safe_image.release(),
icon_change_count_,
id_),
base::Bind(&AppIndicatorIcon::SetImageFromFile,
weak_factory_.GetWeakPtr()));
}
void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
// Ignore pressed images, since the standard on Linux is to not highlight
// pressed status icons.
}
void AppIndicatorIcon::SetToolTip(const std::string& tool_tip) {
// App indicator doesn't have tooltips:
// https://bugs.launchpad.net/indicator-application/+bug/527458
}
void AppIndicatorIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
// The icon is created asynchronously, wait until the icon has been ready.
if (!icon_) {
content::BrowserThread::GetBlockingPool()
->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)->PostTask(
FROM_HERE,
base::Bind(&AppIndicatorIcon::SetContextMenu,
weak_factory_.GetWeakPtr(),
base::Unretained(menu_model)));
return;
}
menu_.reset(new MenuGtk(NULL, menu_model));
app_indicator_set_menu(icon_, GTK_MENU(menu_->widget()));
}
void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (icon_file_path.empty())
return;
base::FilePath old_path = icon_file_path_;
icon_file_path_ = icon_file_path;
std::string icon_name =
icon_file_path_.BaseName().RemoveExtension().value();
std::string icon_dir = icon_file_path_.DirName().value();
if (!icon_) {
icon_ =
app_indicator_new_with_path(id_.c_str(),
icon_name.c_str(),
APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
icon_dir.c_str());
app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE);
} else {
// Currently we are creating a new temp directory every time the icon is
// set. So we need to set the directory each time.
app_indicator_set_icon_theme_path(icon_, icon_dir.c_str());
app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon");
// Delete previous icon directory.
content::BrowserThread::GetBlockingPool()->PostTask(
FROM_HERE,
base::Bind(&DeleteTempImagePath, old_path.DirName()));
}
}
} // namespace atom

View file

@ -1,55 +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_UI_GTK_APP_INDICATOR_ICON_H_
#define ATOM_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_
#include <string>
#include "atom/browser/ui/tray_icon.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/gtk/gtk_signal.h"
typedef struct _AppIndicator AppIndicator;
typedef struct _GtkWidget GtkWidget;
class MenuGtk;
namespace atom {
class AppIndicatorIcon : public TrayIcon {
public:
AppIndicatorIcon();
virtual ~AppIndicatorIcon();
// Indicates whether libappindicator so could be opened.
static bool CouldOpen();
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
private:
void SetImageFromFile(const base::FilePath& icon_file_path);
// Gtk status icon wrapper
AppIndicator* icon_;
// The context menu for this icon (if any).
scoped_ptr<MenuGtk> menu_;
std::string id_;
base::FilePath icon_file_path_;
int icon_change_count_;
base::WeakPtrFactory<AppIndicatorIcon> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AppIndicatorIcon);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_

View file

@ -1,56 +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/gtk/status_icon.h"
#include "chrome/browser/ui/gtk/menu_gtk.h"
#include "ui/gfx/gtk_util.h"
namespace atom {
StatusIcon::StatusIcon() : icon_(gtk_status_icon_new()) {
gtk_status_icon_set_visible(icon_, TRUE);
g_signal_connect(icon_, "activate", G_CALLBACK(OnActivateThunk), this);
g_signal_connect(icon_, "popup-menu", G_CALLBACK(OnPopupMenuThunk), this);
}
StatusIcon::~StatusIcon() {
gtk_status_icon_set_visible(icon_, FALSE);
g_object_unref(icon_);
}
void StatusIcon::SetImage(const gfx::ImageSkia& image) {
if (image.isNull())
return;
GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(*image.bitmap());
gtk_status_icon_set_from_pixbuf(icon_, pixbuf);
g_object_unref(pixbuf);
}
void StatusIcon::SetPressedImage(const gfx::ImageSkia& image) {
// Ignore pressed images, since the standard on Linux is to not highlight
// pressed status icons.
}
void StatusIcon::SetToolTip(const std::string& tool_tip) {
gtk_status_icon_set_tooltip_text(icon_, tool_tip.c_str());
}
void StatusIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_.reset(new MenuGtk(NULL, menu_model));
}
void StatusIcon::OnPopupMenu(GtkWidget* widget, guint button, guint time) {
// If we have a menu - display it.
if (menu_.get())
menu_->PopupAsContextForStatusIcon(time, button, icon_);
}
void StatusIcon::OnActivate(GtkWidget* widget) {
NotifyClicked();
}
} // namespace atom

View file

@ -1,47 +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_UI_GTK_STATUS_ICON_H_
#define ATOM_BROWSER_UI_GTK_STATUS_ICON_H_
#include <gtk/gtk.h>
#include <string>
#include "atom/browser/ui/tray_icon.h"
#include "ui/base/gtk/gtk_signal.h"
class MenuGtk;
namespace atom {
class StatusIcon : public TrayIcon {
public:
StatusIcon();
virtual ~StatusIcon();
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
private:
// Callback invoked when user right-clicks on the status icon.
CHROMEGTK_CALLBACK_2(StatusIcon, void, OnPopupMenu, guint, guint);
// Callback invoked when the icon is clicked.
CHROMEGTK_CALLBACK_0(StatusIcon, void, OnActivate);
// The currently-displayed icon for the window.
GtkStatusIcon* icon_;
// The context menu for this icon (if any).
scoped_ptr<MenuGtk> menu_;
DISALLOW_COPY_AND_ASSIGN(StatusIcon);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_GTK_STATUS_ICON_H_

View file

@ -1,135 +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;
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,14 +9,18 @@
#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"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/shadow_types.h"
namespace atom {
@ -26,8 +30,9 @@ 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 MessageDialogClientView;
class MessageDialog : public views::WidgetDelegate,
public views::View,
public views::ButtonListener {
public:
@ -39,7 +44,8 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
const std::string& detail);
virtual ~MessageDialog();
void Show();
void Show(base::RunLoop* run_loop = NULL);
void Close();
int GetResult() const;
@ -49,17 +55,16 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
}
private:
// Overridden from MessageLoop::Dispatcher:
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
// Overridden from views::WidgetDelegate:
virtual string16 GetWindowTitle() const;
virtual void WindowClosing() OVERRIDE;
virtual base::string16 GetWindowTitle() const;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
virtual ui::ModalType GetModalType() const OVERRIDE;
virtual views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) OVERRIDE;
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
// Overridden from views::View:
virtual gfx::Size GetPreferredSize() OVERRIDE;
@ -70,19 +75,41 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
bool should_close_;
bool delete_on_close_;
int result_;
string16 title_;
views::Widget* widget_;
base::string16 title_;
NativeWindow* parent_;
scoped_ptr<views::Widget> widget_;
views::MessageBoxView* message_box_view_;
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
std::vector<views::LabelButton*> buttons_;
base::RunLoop* run_loop_;
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
MessageBoxCallback callback_;
DISALLOW_COPY_AND_ASSIGN(MessageDialog);
};
class MessageDialogClientView : public views::ClientView {
public:
MessageDialogClientView(MessageDialog* dialog, views::Widget* widget)
: views::ClientView(widget, dialog),
dialog_(dialog) {
}
// views::ClientView:
virtual bool CanClose() OVERRIDE {
dialog_->Close();
return false;
}
private:
MessageDialog* dialog_;
DISALLOW_COPY_AND_ASSIGN(MessageDialogClientView);
};
////////////////////////////////////////////////////////////////////////////////
// MessageDialog, public:
@ -92,27 +119,30 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
const std::string& title,
const std::string& message,
const std::string& detail)
: should_close_(false),
delete_on_close_(false),
: delete_on_close_(false),
result_(-1),
title_(UTF8ToUTF16(title)),
widget_(NULL),
title_(base::UTF8ToUTF16(title)),
parent_(parent_window),
message_box_view_(NULL),
run_loop_(NULL),
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
DCHECK_GT(buttons.size(), 0u);
set_owned_by_client();
views::MessageBoxView::InitParams params(UTF8ToUTF16(title));
params.message = UTF8ToUTF16(message + "\n" + detail);
message_box_view_ = new views::MessageBoxView(params);
if (!parent_)
set_background(views::Background::CreateStandardPanelBackground());
std::string content = message + "\n" + detail;
views::MessageBoxView::InitParams box_params(base::UTF8ToUTF16(content));
message_box_view_ = new views::MessageBoxView(box_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->SetGroup(kButtonGroup);
buttons_.push_back(button);
@ -123,29 +153,48 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
buttons_[0]->SetIsDefault(true);
buttons_[0]->AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
views::Widget::InitParams widget_params;
widget_params.delegate = this;
widget_params.top_level = true;
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);
views::Widget::InitParams params;
params.delegate = this;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.top_level = true;
if (parent_) {
params.parent = parent_->GetNativeWindow();
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
// Use bubble style for dialog has a parent.
params.remove_standard_frame = true;
}
#if defined(USE_X11)
// In X11 the window frame is drawn by the application.
params.remove_standard_frame = true;
#endif
widget_.reset(new views::Widget);
widget_->Init(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();
}
void MessageDialog::Close() {
dialog_scope_.reset();
if (delete_on_close_) {
callback_.Run(GetResult());
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
} else if (run_loop_) {
run_loop_->Quit();
}
}
int MessageDialog::GetResult() const {
// When the dialog is closed without choosing anything, we think the user
// chose 'Cancel', otherwise we think the default behavior is chosen.
@ -164,32 +213,16 @@ 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_;
}
void MessageDialog::WindowClosing() {
should_close_ = true;
dialog_scope_.reset();
if (delete_on_close_) {
callback_.Run(GetResult());
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
}
views::Widget* MessageDialog::GetWidget() {
return widget_;
return widget_.get();
}
const views::Widget* MessageDialog::GetWidget() const {
return widget_;
return widget_.get();
}
views::View* MessageDialog::GetContentsView() {
@ -204,7 +237,27 @@ views::View* MessageDialog::GetInitiallyFocusedView() {
}
ui::ModalType MessageDialog::GetModalType() const {
return ui::MODAL_TYPE_WINDOW;
return ui::MODAL_TYPE_SYSTEM;
}
views::NonClientFrameView* MessageDialog::CreateNonClientFrameView(
views::Widget* widget) {
if (!parent_)
return NULL;
// Create a bubble style frame like Chrome.
views::BubbleFrameView* frame = new views::BubbleFrameView(gfx::Insets());
const SkColor color = widget->GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DialogBackground);
scoped_ptr<views::BubbleBorder> border(new views::BubbleBorder(
views::BubbleBorder::FLOAT, views::BubbleBorder::SMALL_SHADOW, color));
frame->SetBubbleBorder(border.Pass());
wm::SetShadowType(widget->GetNativeWindow(), wm::SHADOW_TYPE_NONE);
return frame;
}
views::ClientView* MessageDialog::CreateClientView(views::Widget* widget) {
return new MessageDialogClientView(this, widget);
}
gfx::Size MessageDialog::GetPreferredSize() {
@ -269,11 +322,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

@ -2,17 +2,58 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/gtk/status_icon.h"
#include "atom/browser/ui/gtk/app_indicator_icon.h"
#include "atom/browser/ui/tray_icon_gtk.h"
#include "base/guid.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h"
namespace atom {
TrayIconGtk::TrayIconGtk() {
}
TrayIconGtk::~TrayIconGtk() {
}
void TrayIconGtk::SetImage(const gfx::ImageSkia& image) {
if (icon_) {
icon_->SetImage(image);
return;
}
base::string16 empty;
if (libgtk2ui::AppIndicatorIcon::CouldOpen())
icon_.reset(
new libgtk2ui::AppIndicatorIcon(base::GenerateGUID(), image, empty));
else
icon_.reset(new libgtk2ui::Gtk2StatusIcon(image, empty));
icon_->set_delegate(this);
}
void TrayIconGtk::SetPressedImage(const gfx::ImageSkia& image) {
icon_->SetPressedImage(image);
}
void TrayIconGtk::SetToolTip(const std::string& tool_tip) {
icon_->SetToolTip(base::UTF8ToUTF16(tool_tip));
}
void TrayIconGtk::SetContextMenu(ui::SimpleMenuModel* menu_model) {
icon_->UpdatePlatformContextMenu(menu_model);
}
void TrayIconGtk::OnClick() {
}
bool TrayIconGtk::HasClickAction() {
return false;
}
// static
TrayIcon* TrayIcon::Create() {
if (AppIndicatorIcon::CouldOpen())
return new AppIndicatorIcon;
else
return new StatusIcon;
return new TrayIconGtk;
}
} // namespace atom

View file

@ -0,0 +1,43 @@
// 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_UI_TRAY_ICON_GTK_H_
#define ATOM_BROWSER_UI_TRAY_ICON_GTK_H_
#include <string>
#include "atom/browser/ui/tray_icon.h"
#include "ui/views/linux_ui/status_icon_linux.h"
namespace views {
class StatusIconLinux;
}
namespace atom {
class TrayIconGtk : public TrayIcon,
public views::StatusIconLinux::Delegate {
public:
TrayIconGtk();
virtual ~TrayIconGtk();
// TrayIcon:
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
private:
// views::StatusIconLinux::Delegate:
virtual void OnClick() OVERRIDE;
virtual bool HasClickAction() OVERRIDE;
scoped_ptr<views::StatusIconLinux> icon_;
DISALLOW_COPY_AND_ASSIGN(TrayIconGtk);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_TRAY_ICON_GTK_H_

View file

@ -0,0 +1,115 @@
// 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/views/frameless_view.h"
#include "atom/browser/native_window_views.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace atom {
namespace {
const int kResizeInsideBoundsSize = 5;
const int kResizeAreaCornerSize = 16;
const char kViewClassName[] = "FramelessView";
} // namespace
FramelessView::FramelessView() : window_(NULL), frame_(NULL) {
}
FramelessView::~FramelessView() {
}
void FramelessView::Init(NativeWindowViews* window, views::Widget* frame) {
window_ = window;
frame_ = frame;
}
int FramelessView::ResizingBorderHitTest(const gfx::Point& point) {
// Check the frame first, as we allow a small area overlapping the contents
// to be used for resize handles.
bool can_ever_resize = frame_->widget_delegate() ?
frame_->widget_delegate()->CanResize() :
false;
// Don't allow overlapping resize handles when the window is maximized or
// fullscreen, as it can't be resized in those states.
int resize_border =
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
kResizeInsideBoundsSize;
return GetHTComponentForFrame(point, resize_border, resize_border,
kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize);
}
gfx::Rect FramelessView::GetBoundsForClientView() const {
return bounds();
}
gfx::Rect FramelessView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
gfx::Rect window_bounds = client_bounds;
// Enforce minimum size (1, 1) in case that client_bounds is passed with
// empty size. This could occur when the frameless window is being
// initialized.
if (window_bounds.IsEmpty()) {
window_bounds.set_width(1);
window_bounds.set_height(1);
}
return window_bounds;
}
int FramelessView::NonClientHitTest(const gfx::Point& cursor) {
if (frame_->IsFullscreen())
return HTCLIENT;
// Check for possible draggable region in the client area for the frameless
// window.
SkRegion* draggable_region = window_->draggable_region();
if (draggable_region && draggable_region->contains(cursor.x(), cursor.y()))
return HTCAPTION;
// Support resizing frameless window by dragging the border.
int frame_component = ResizingBorderHitTest(cursor);
if (frame_component != HTNOWHERE)
return frame_component;
return HTCLIENT;
}
void FramelessView::GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) {
}
void FramelessView::ResetWindowControls() {
}
void FramelessView::UpdateWindowIcon() {
}
void FramelessView::UpdateWindowTitle() {
}
gfx::Size FramelessView::GetPreferredSize() {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();
}
gfx::Size FramelessView::GetMinimumSize() {
return window_->GetMinimumSize();
}
gfx::Size FramelessView::GetMaximumSize() {
return window_->GetMaximumSize();
}
const char* FramelessView::GetClassName() const {
return kViewClassName;
}
} // namespace atom

View file

@ -0,0 +1,56 @@
// 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_UI_VIEWS_FRAMELESS_VIEW_H_
#define ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_
#include "ui/views/window/non_client_view.h"
namespace views {
class Widget;
}
namespace atom {
class NativeWindowViews;
class FramelessView : public views::NonClientFrameView {
public:
FramelessView();
virtual ~FramelessView();
virtual void Init(NativeWindowViews* window, views::Widget* frame);
// Returns whether the |point| is on frameless window's resizing border.
int ResizingBorderHitTest(const gfx::Point& point);
protected:
// views::NonClientFrameView:
virtual gfx::Rect GetBoundsForClientView() const OVERRIDE;
virtual gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const OVERRIDE;
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
virtual void GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) OVERRIDE;
virtual void ResetWindowControls() OVERRIDE;
virtual void UpdateWindowIcon() OVERRIDE;
virtual void UpdateWindowTitle() OVERRIDE;
// Overridden from View:
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual gfx::Size GetMinimumSize() OVERRIDE;
virtual gfx::Size GetMaximumSize() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// Not owned.
NativeWindowViews* window_;
views::Widget* frame_;
private:
DISALLOW_COPY_AND_ASSIGN(FramelessView);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_

View file

@ -0,0 +1,311 @@
// 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/views/global_menu_bar_x11.h"
#include <X11/Xlib.h>
// This conflicts with mate::Converter,
#undef True
#undef False
// and V8.
#undef None
#include <dlfcn.h>
#include <glib-object.h>
#include "atom/browser/native_window_views.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
#include "ui/base/models/menu_model.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
// libdbusmenu-glib types
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);
typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
typedef GList* (*dbusmenu_menuitem_get_children_func)(DbusmenuMenuitem* item);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
DbusmenuMenuitem* parent,
DbusmenuMenuitem* child);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
DbusmenuMenuitem* item,
const char* property,
const char* value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)(
DbusmenuMenuitem* item,
const char* property,
GVariant* value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)(
DbusmenuMenuitem* item,
const char* property,
bool value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)(
DbusmenuMenuitem* item,
const char* property,
int value);
typedef struct _DbusmenuServer DbusmenuServer;
typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object);
typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self,
DbusmenuMenuitem* root);
namespace atom {
namespace {
// Retrieved functions from libdbusmenu-glib.
// DbusmenuMenuItem methods:
dbusmenu_menuitem_new_func menuitem_new = NULL;
dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
dbusmenu_menuitem_get_children_func menuitem_get_children = NULL;
dbusmenu_menuitem_get_children_func menuitem_take_children = NULL;
dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
NULL;
dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL;
dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL;
// DbusmenuServer methods:
dbusmenu_server_new_func server_new = NULL;
dbusmenu_server_set_root_func server_set_root = NULL;
// Properties that we set on menu items:
const char kPropertyEnabled[] = "enabled";
const char kPropertyLabel[] = "label";
const char kPropertyShortcut[] = "shortcut";
const char kPropertyType[] = "type";
const char kPropertyToggleType[] = "toggle-type";
const char kPropertyToggleState[] = "toggle-state";
const char kPropertyVisible[] = "visible";
const char kPropertyChildrenDisplay[] = "children-display";
const char kToggleCheck[] = "checkmark";
const char kToggleRadio[] = "radio";
const char kTypeSeparator[] = "separator";
const char kDisplaySubmenu[] = "submenu";
void EnsureMethodsLoaded() {
static bool attempted_load = false;
if (attempted_load)
return;
attempted_load = true;
void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY);
if (!dbusmenu_lib)
dbusmenu_lib = dlopen("libdbusmenu-glib.so.4", RTLD_LAZY);
if (!dbusmenu_lib)
return;
// DbusmenuMenuItem methods.
menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
menuitem_get_children = reinterpret_cast<dbusmenu_menuitem_get_children_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children"));
menuitem_take_children =
reinterpret_cast<dbusmenu_menuitem_get_children_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_take_children"));
menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
menuitem_property_set_variant =
reinterpret_cast<dbusmenu_menuitem_property_set_variant_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant"));
menuitem_property_set_bool =
reinterpret_cast<dbusmenu_menuitem_property_set_bool_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool"));
menuitem_property_set_int =
reinterpret_cast<dbusmenu_menuitem_property_set_int_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int"));
// DbusmenuServer methods.
server_new = reinterpret_cast<dbusmenu_server_new_func>(
dlsym(dbusmenu_lib, "dbusmenu_server_new"));
server_set_root = reinterpret_cast<dbusmenu_server_set_root_func>(
dlsym(dbusmenu_lib, "dbusmenu_server_set_root"));
}
ui::MenuModel* ModelForMenuItem(DbusmenuMenuitem* item) {
return reinterpret_cast<ui::MenuModel*>(
g_object_get_data(G_OBJECT(item), "model"));
}
bool GetMenuItemID(DbusmenuMenuitem* item, int *id) {
gpointer id_ptr = g_object_get_data(G_OBJECT(item), "menu-id");
if (id_ptr != NULL) {
*id = GPOINTER_TO_INT(id_ptr) - 1;
return true;
}
return false;
}
void SetMenuItemID(DbusmenuMenuitem* item, int id) {
DCHECK_GE(id, 0);
// Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1));
}
} // namespace
GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window)
: window_(window),
xid_(window_->GetNativeWindow()->GetHost()->GetAcceleratedWidget()),
server_(NULL) {
EnsureMethodsLoaded();
if (server_new)
InitServer(xid_);
GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
}
GlobalMenuBarX11::~GlobalMenuBarX11() {
if (IsServerStarted())
g_object_unref(server_);
GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
}
// static
std::string GlobalMenuBarX11::GetPathForWindow(gfx::AcceleratedWidget xid) {
return base::StringPrintf("/com/canonical/menu/%lX", xid);
}
void GlobalMenuBarX11::SetMenu(ui::MenuModel* menu_model) {
if (!IsServerStarted())
return;
DbusmenuMenuitem* root_item = menuitem_new();
menuitem_property_set(root_item, kPropertyLabel, "Root");
menuitem_property_set_bool(root_item, kPropertyVisible, true);
BuildMenuFromModel(menu_model, root_item);
server_set_root(server_, root_item);
g_object_unref(root_item);
}
bool GlobalMenuBarX11::IsServerStarted() const {
return server_;
}
void GlobalMenuBarX11::InitServer(gfx::AcceleratedWidget xid) {
std::string path = GetPathForWindow(xid);
server_ = server_new(path.c_str());
}
void GlobalMenuBarX11::BuildMenuFromModel(ui::MenuModel* model,
DbusmenuMenuitem* parent) {
for (int i = 0; i < model->GetItemCount(); ++i) {
DbusmenuMenuitem* item = menuitem_new();
menuitem_property_set_bool(item, kPropertyVisible, model->IsVisibleAt(i));
ui::MenuModel::ItemType type = model->GetTypeAt(i);
if (type == ui::MenuModel::TYPE_SEPARATOR) {
menuitem_property_set(item, kPropertyType, kTypeSeparator);
} else {
std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
base::UTF16ToUTF8(model->GetLabelAt(i)));
menuitem_property_set(item, kPropertyLabel, label.c_str());
menuitem_property_set_bool(item, kPropertyEnabled, model->IsEnabledAt(i));
g_object_set_data(G_OBJECT(item), "model", model);
SetMenuItemID(item, i);
if (type == ui::MenuModel::TYPE_SUBMENU) {
menuitem_property_set(item, kPropertyChildrenDisplay, kDisplaySubmenu);
g_signal_connect(item, "about-to-show",
G_CALLBACK(OnSubMenuShowThunk), this);
} else {
ui::Accelerator accelerator;
if (model->GetAcceleratorAt(i, &accelerator))
RegisterAccelerator(item, accelerator);
g_signal_connect(item, "item-activated",
G_CALLBACK(OnItemActivatedThunk), this);
if (type == ui::MenuModel::TYPE_CHECK ||
type == ui::MenuModel::TYPE_RADIO) {
menuitem_property_set(item, kPropertyToggleType,
type == ui::MenuModel::TYPE_CHECK ? kToggleCheck : kToggleRadio);
menuitem_property_set_int(item, kPropertyToggleState,
model->IsItemCheckedAt(i));
}
}
}
menuitem_child_append(parent, item);
g_object_unref(item);
}
}
void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
const ui::Accelerator& accelerator) {
// A translation of libdbusmenu-gtk's menuitem_property_set_shortcut()
// translated from GDK types to ui::Accelerator types.
GVariantBuilder builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
if (accelerator.IsCtrlDown())
g_variant_builder_add(&builder, "s", "Control");
if (accelerator.IsAltDown())
g_variant_builder_add(&builder, "s", "Alt");
if (accelerator.IsShiftDown())
g_variant_builder_add(&builder, "s", "Shift");
char* name = XKeysymToString(XKeysymForWindowsKeyCode(
accelerator.key_code(), false));
if (!name) {
NOTIMPLEMENTED();
return;
}
g_variant_builder_add(&builder, "s", name);
GVariant* inside_array = g_variant_builder_end(&builder);
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
g_variant_builder_add_value(&builder, inside_array);
GVariant* outside_array = g_variant_builder_end(&builder);
menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
}
void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
unsigned int timestamp) {
int id;
ui::MenuModel* model = ModelForMenuItem(item);
if (model && GetMenuItemID(item, &id))
model->ActivatedAt(id, 0);
}
void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) {
int id;
ui::MenuModel* model = ModelForMenuItem(item);
if (!model || !GetMenuItemID(item, &id))
return;
// Clear children.
GList *children = menuitem_take_children(item);
g_list_foreach(children, reinterpret_cast<GFunc>(g_object_unref), NULL);
g_list_free(children);
// Build children.
BuildMenuFromModel(model->GetSubmenuModelAt(id), item);
}
} // namespace atom

View file

@ -0,0 +1,74 @@
// 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_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_
#define ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_
#include <string>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/gfx/native_widget_types.h"
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
typedef struct _DbusmenuServer DbusmenuServer;
namespace ui {
class Accelerator;
class MenuModel;
}
namespace atom {
class NativeWindowViews;
// Controls the Mac style menu bar on Unity.
//
// Unity has an Apple-like menu bar at the top of the screen that changes
// depending on the active window. In the GTK port, we had a hidden GtkMenuBar
// object in each GtkWindow which existed only to be scrapped by the
// libdbusmenu-gtk code. Since we don't have GtkWindows anymore, we need to
// interface directly with the lower level libdbusmenu-glib, which we
// opportunistically dlopen() since not everyone is running Ubuntu.
//
// This class is like the chrome's corresponding one, but it generates the menu
// from menu models instead, and it is also per-window specific.
class GlobalMenuBarX11 {
public:
explicit GlobalMenuBarX11(NativeWindowViews* window);
virtual ~GlobalMenuBarX11();
// Creates the object path for DbusemenuServer which is attached to |xid|.
static std::string GetPathForWindow(gfx::AcceleratedWidget xid);
void SetMenu(ui::MenuModel* menu_model);
bool IsServerStarted() const;
private:
// Creates a DbusmenuServer.
void InitServer(gfx::AcceleratedWidget xid);
// Create a menu from menu model.
void BuildMenuFromModel(ui::MenuModel* model, DbusmenuMenuitem* parent);
// Sets the accelerator for |item|.
void RegisterAccelerator(DbusmenuMenuitem* item,
const ui::Accelerator& accelerator);
CHROMEG_CALLBACK_1(GlobalMenuBarX11, void, OnItemActivated, DbusmenuMenuitem*,
unsigned int);
CHROMEG_CALLBACK_0(GlobalMenuBarX11, void, OnSubMenuShow, DbusmenuMenuitem*);
NativeWindowViews* window_;
gfx::AcceleratedWidget xid_;
DbusmenuServer* server_;
DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarX11);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_

View file

@ -0,0 +1,596 @@
// 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/views/linux_frame_view.h"
#include <algorithm>
#include "atom/browser/native_window_views.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/path.h"
#include "ui/views/color_constants.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/frame_background.h"
#include "ui/views/window/window_resources.h"
#include "ui/views/window/window_shape.h"
// Workaround for including grit headers.
#include "ui/ui_resources/grit/ui_resources.h"
#include "ui/ui_strings/grit/ui_strings.h"
namespace atom {
namespace {
// The frame border is only visible in restored mode and is hardcoded to 4 px on
// each side regardless of the system window border size.
const int kFrameBorderThickness = 4;
// In the window corners, the resize areas don't actually expand bigger, but the
// 16 px at the end of each edge triggers diagonal resizing.
const int kResizeAreaCornerSize = 16;
// The titlebar never shrinks too short to show the caption button plus some
// padding below it.
const int kCaptionButtonHeightWithPadding = 19;
// The titlebar has a 2 px 3D edge along the top and bottom.
const int kTitlebarTopAndBottomEdgeThickness = 2;
// The icon is inset 2 px from the left frame border.
const int kIconLeftSpacing = 2;
// The icon never shrinks below 16 px on a side.
const int kIconMinimumSize = 16;
// The space between the window icon and the title text.
const int kTitleIconOffsetX = 4;
// The space between the title text and the caption buttons.
const int kTitleCaptionSpacing = 5;
#if defined(OS_CHROMEOS)
// Chrome OS uses a dark gray.
const SkColor kDefaultColorFrame = SkColorSetRGB(109, 109, 109);
const SkColor kDefaultColorFrameInactive = SkColorSetRGB(176, 176, 176);
#else
// Windows and Linux use a blue.
const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201);
const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228);
#endif
const gfx::FontList& GetTitleFontList() {
static const gfx::FontList title_font_list =
views::NativeWidgetAura::GetWindowTitleFontList();
return title_font_list;
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
// LinuxFrameView, public:
LinuxFrameView::LinuxFrameView()
: window_icon_(NULL),
minimize_button_(NULL),
maximize_button_(NULL),
restore_button_(NULL),
close_button_(NULL),
should_show_maximize_button_(false),
frame_background_(new views::FrameBackground) {
}
LinuxFrameView::~LinuxFrameView() {
}
void LinuxFrameView::Init(NativeWindowViews* window, views::Widget* frame) {
FramelessView::Init(window, frame);
close_button_ = new views::ImageButton(this);
close_button_->SetAccessibleName(
l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
// Close button images will be set in LayoutWindowControls().
AddChildView(close_button_);
minimize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MINIMIZE,
IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P);
maximize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MAXIMIZE,
IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P);
restore_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_RESTORE,
IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P);
should_show_maximize_button_ = frame_->widget_delegate()->CanMaximize();
if (frame_->widget_delegate()->ShouldShowWindowIcon()) {
window_icon_ = new views::ImageButton(this);
AddChildView(window_icon_);
}
}
///////////////////////////////////////////////////////////////////////////////
// LinuxFrameView, NonClientFrameView implementation:
gfx::Rect LinuxFrameView::GetBoundsForClientView() const {
return client_view_bounds_;
}
gfx::Rect LinuxFrameView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
int top_height = NonClientTopBorderHeight();
int border_thickness = NonClientBorderThickness();
return gfx::Rect(client_bounds.x() - border_thickness,
client_bounds.y() - top_height,
client_bounds.width() + (2 * border_thickness),
client_bounds.height() + top_height + border_thickness);
}
int LinuxFrameView::NonClientHitTest(const gfx::Point& point) {
if (!window_->has_frame())
return FramelessView::NonClientHitTest(point);
// Sanity check.
if (!bounds().Contains(point))
return HTNOWHERE;
int frame_component = frame_->client_view()->NonClientHitTest(point);
// See if we're in the sysmenu region. (We check the ClientView first to be
// consistent with OpaqueBrowserFrameView; it's not really necessary here.)
gfx::Rect sysmenu_rect(IconBounds());
// In maximized mode we extend the rect to the screen corner to take advantage
// of Fitts' Law.
if (frame_->IsMaximized())
sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom());
sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect));
if (sysmenu_rect.Contains(point))
return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;
if (frame_component != HTNOWHERE)
return frame_component;
// Then see if the point is within any of the window controls.
if (close_button_->GetMirroredBounds().Contains(point))
return HTCLOSE;
if (restore_button_->GetMirroredBounds().Contains(point))
return HTMAXBUTTON;
if (maximize_button_->GetMirroredBounds().Contains(point))
return HTMAXBUTTON;
if (minimize_button_->GetMirroredBounds().Contains(point))
return HTMINBUTTON;
if (window_icon_ && window_icon_->GetMirroredBounds().Contains(point))
return HTSYSMENU;
int window_component = GetHTComponentForFrame(point, FrameBorderThickness(),
NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize,
frame_->widget_delegate()->CanResize());
// Fall back to the caption if no other component matches.
return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
}
void LinuxFrameView::GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) {
DCHECK(window_mask);
if (frame_->IsMaximized() || !ShouldShowTitleBarAndBorder())
return;
views::GetDefaultWindowMask(size, window_mask);
}
void LinuxFrameView::ResetWindowControls() {
restore_button_->SetState(views::CustomButton::STATE_NORMAL);
minimize_button_->SetState(views::CustomButton::STATE_NORMAL);
maximize_button_->SetState(views::CustomButton::STATE_NORMAL);
// The close button isn't affected by this constraint.
}
void LinuxFrameView::UpdateWindowIcon() {
if (window_icon_)
window_icon_->SchedulePaint();
}
void LinuxFrameView::UpdateWindowTitle() {
SchedulePaintInRect(title_bounds_);
}
///////////////////////////////////////////////////////////////////////////////
// LinuxFrameView, View overrides:
void LinuxFrameView::OnPaint(gfx::Canvas* canvas) {
if (!ShouldShowTitleBarAndBorder())
return;
if (frame_->IsMaximized())
PaintMaximizedFrameBorder(canvas);
else
PaintRestoredFrameBorder(canvas);
PaintTitleBar(canvas);
if (ShouldShowClientEdge())
PaintRestoredClientEdge(canvas);
}
void LinuxFrameView::Layout() {
if (ShouldShowTitleBarAndBorder()) {
LayoutWindowControls();
LayoutTitleBar();
}
LayoutClientView();
}
gfx::Size LinuxFrameView::GetPreferredSize() {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();
}
gfx::Size LinuxFrameView::GetMinimumSize() {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetMinimumSize())).size();
}
gfx::Size LinuxFrameView::GetMaximumSize() {
gfx::Size max_size = frame_->client_view()->GetMaximumSize();
gfx::Size converted_size =
frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(max_size)).size();
return gfx::Size(max_size.width() == 0 ? 0 : converted_size.width(),
max_size.height() == 0 ? 0 : converted_size.height());
}
///////////////////////////////////////////////////////////////////////////////
// LinuxFrameView, ButtonListener implementation:
void LinuxFrameView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == close_button_)
frame_->Close();
else if (sender == minimize_button_)
frame_->Minimize();
else if (sender == maximize_button_)
frame_->Maximize();
else if (sender == restore_button_)
frame_->Restore();
}
///////////////////////////////////////////////////////////////////////////////
// LinuxFrameView, private:
int LinuxFrameView::FrameBorderThickness() const {
return frame_->IsMaximized() ? 0 : kFrameBorderThickness;
}
int LinuxFrameView::NonClientBorderThickness() const {
// In maximized mode, we don't show a client edge.
return FrameBorderThickness() +
(ShouldShowClientEdge() ? kClientEdgeThickness : 0);
}
int LinuxFrameView::NonClientTopBorderHeight() const {
return std::max(FrameBorderThickness() + IconSize(),
CaptionButtonY() + kCaptionButtonHeightWithPadding) +
TitlebarBottomThickness();
}
int LinuxFrameView::CaptionButtonY() const {
// Maximized buttons start at window top so that even if their images aren't
// drawn flush with the screen edge, they still obey Fitts' Law.
return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness;
}
int LinuxFrameView::TitlebarBottomThickness() const {
return kTitlebarTopAndBottomEdgeThickness +
(ShouldShowClientEdge() ? kClientEdgeThickness : 0);
}
int LinuxFrameView::IconSize() const {
#if defined(OS_WIN)
// This metric scales up if either the titlebar height or the titlebar font
// size are increased.
return GetSystemMetrics(SM_CYSMICON);
#else
return std::max(GetTitleFontList().GetHeight(), kIconMinimumSize);
#endif
}
gfx::Rect LinuxFrameView::IconBounds() const {
int size = IconSize();
int frame_thickness = FrameBorderThickness();
// Our frame border has a different "3D look" than Windows'. Theirs has a
// more complex gradient on the top that they push their icon/title below;
// then the maximized window cuts this off and the icon/title are centered
// in the remaining space. Because the apparent shape of our border is
// simpler, using the same positioning makes things look slightly uncentered
// with restored windows, so when the window is restored, instead of
// calculating the remaining space from below the frame border, we calculate
// from below the 3D edge.
int unavailable_px_at_top = frame_->IsMaximized() ?
frame_thickness : kTitlebarTopAndBottomEdgeThickness;
// When the icon is shorter than the minimum space we reserve for the caption
// button, we vertically center it. We want to bias rounding to put extra
// space above the icon, since the 3D edge (+ client edge, for restored
// windows) below looks (to the eye) more like additional space than does the
// 3D edge (or nothing at all, for maximized windows) above; hence the +1.
int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
}
bool LinuxFrameView::ShouldShowTitleBarAndBorder() const {
if (!window_->has_frame())
return false;
if (frame_->IsFullscreen())
return false;
if (views::ViewsDelegate::views_delegate) {
return !views::ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar(
frame_->IsMaximized());
}
return true;
}
bool LinuxFrameView::ShouldShowClientEdge() const {
return !frame_->IsMaximized() && ShouldShowTitleBarAndBorder();
}
void LinuxFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
frame_background_->set_frame_color(GetFrameColor());
const gfx::ImageSkia* frame_image = GetFrameImage();
frame_background_->set_theme_image(frame_image);
frame_background_->set_top_area_height(frame_image->height());
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
frame_background_->SetCornerImages(
rb.GetImageNamed(IDR_WINDOW_TOP_LEFT_CORNER).ToImageSkia(),
rb.GetImageNamed(IDR_WINDOW_TOP_RIGHT_CORNER).ToImageSkia(),
rb.GetImageNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER).ToImageSkia(),
rb.GetImageNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER).ToImageSkia());
frame_background_->SetSideImages(
rb.GetImageNamed(IDR_WINDOW_LEFT_SIDE).ToImageSkia(),
rb.GetImageNamed(IDR_WINDOW_TOP_CENTER).ToImageSkia(),
rb.GetImageNamed(IDR_WINDOW_RIGHT_SIDE).ToImageSkia(),
rb.GetImageNamed(IDR_WINDOW_BOTTOM_CENTER).ToImageSkia());
frame_background_->PaintRestored(canvas, this);
}
void LinuxFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
const gfx::ImageSkia* frame_image = GetFrameImage();
frame_background_->set_theme_image(frame_image);
frame_background_->set_top_area_height(frame_image->height());
frame_background_->PaintMaximized(canvas, this);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
// TODO(jamescook): Migrate this into FrameBackground.
// The bottom of the titlebar actually comes from the top of the Client Edge
// graphic, with the actual client edge clipped off the bottom.
const gfx::ImageSkia* titlebar_bottom = rb.GetImageNamed(
IDR_APP_TOP_CENTER).ToImageSkia();
int edge_height = titlebar_bottom->height() -
(ShouldShowClientEdge() ? kClientEdgeThickness : 0);
canvas->TileImageInt(*titlebar_bottom, 0,
frame_->client_view()->y() - edge_height, width(), edge_height);
}
void LinuxFrameView::PaintTitleBar(gfx::Canvas* canvas) {
views::WidgetDelegate* delegate = frame_->widget_delegate();
// It seems like in some conditions we can be asked to paint after the window
// that contains us is WM_DESTROYed. At this point, our delegate is NULL. The
// correct long term fix may be to shut down the RootView in WM_DESTROY.
if (!delegate)
return;
gfx::Rect rect = title_bounds_;
rect.set_x(GetMirroredXForRect(title_bounds_));
canvas->DrawStringRect(delegate->GetWindowTitle(), GetTitleFontList(),
SK_ColorWHITE, rect);
}
void LinuxFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
gfx::Rect client_area_bounds = frame_->client_view()->bounds();
int client_area_top = client_area_bounds.y();
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
// Top: left, center, right sides.
const gfx::ImageSkia* top_left = rb.GetImageSkiaNamed(IDR_APP_TOP_LEFT);
const gfx::ImageSkia* top_center = rb.GetImageSkiaNamed(IDR_APP_TOP_CENTER);
const gfx::ImageSkia* top_right = rb.GetImageSkiaNamed(IDR_APP_TOP_RIGHT);
int top_edge_y = client_area_top - top_center->height();
canvas->DrawImageInt(*top_left,
client_area_bounds.x() - top_left->width(),
top_edge_y);
canvas->TileImageInt(*top_center,
client_area_bounds.x(),
top_edge_y,
client_area_bounds.width(),
top_center->height());
canvas->DrawImageInt(*top_right, client_area_bounds.right(), top_edge_y);
// Right side.
const gfx::ImageSkia* right = rb.GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
int client_area_bottom =
std::max(client_area_top, client_area_bounds.bottom());
int client_area_height = client_area_bottom - client_area_top;
canvas->TileImageInt(*right,
client_area_bounds.right(),
client_area_top,
right->width(),
client_area_height);
// Bottom: left, center, right sides.
const gfx::ImageSkia* bottom_left =
rb.GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
const gfx::ImageSkia* bottom_center =
rb.GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
const gfx::ImageSkia* bottom_right =
rb.GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER);
canvas->DrawImageInt(*bottom_left,
client_area_bounds.x() - bottom_left->width(),
client_area_bottom);
canvas->TileImageInt(*bottom_center,
client_area_bounds.x(),
client_area_bottom,
client_area_bounds.width(),
bottom_right->height());
canvas->DrawImageInt(*bottom_right,
client_area_bounds.right(),
client_area_bottom);
// Left side.
const gfx::ImageSkia* left = rb.GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE);
canvas->TileImageInt(*left,
client_area_bounds.x() - left->width(),
client_area_top,
left->width(),
client_area_height);
// Draw the color to fill in the edges.
canvas->FillRect(gfx::Rect(client_area_bounds.x() - 1,
client_area_top - 1,
client_area_bounds.width() + 1,
client_area_bottom - client_area_top + 1),
views::kClientEdgeColor);
}
SkColor LinuxFrameView::GetFrameColor() const {
return frame_->IsActive() ? kDefaultColorFrame : kDefaultColorFrameInactive;
}
const gfx::ImageSkia* LinuxFrameView::GetFrameImage() const {
return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
frame_->IsActive() ? IDR_FRAME : IDR_FRAME_INACTIVE).ToImageSkia();
}
void LinuxFrameView::LayoutWindowControls() {
close_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
views::ImageButton::ALIGN_BOTTOM);
int caption_y = CaptionButtonY();
bool is_maximized = frame_->IsMaximized();
// There should always be the same number of non-shadow pixels visible to the
// side of the caption buttons. In maximized mode we extend the rightmost
// button to the screen corner to obey Fitts' Law.
int right_extra_width = is_maximized ?
(kFrameBorderThickness - kFrameShadowThickness) : 0;
gfx::Size close_button_size = close_button_->GetPreferredSize();
close_button_->SetBounds(width() - FrameBorderThickness() -
right_extra_width - close_button_size.width(), caption_y,
close_button_size.width() + right_extra_width,
close_button_size.height());
// When the window is restored, we show a maximized button; otherwise, we show
// a restore button.
bool is_restored = !is_maximized && !frame_->IsMinimized();
views::ImageButton* invisible_button = is_restored ? restore_button_
: maximize_button_;
invisible_button->SetVisible(false);
views::ImageButton* visible_button = is_restored ? maximize_button_
: restore_button_;
views::FramePartImage normal_part, hot_part, pushed_part;
int next_button_x;
if (should_show_maximize_button_) {
visible_button->SetVisible(true);
visible_button->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
views::ImageButton::ALIGN_BOTTOM);
gfx::Size visible_button_size = visible_button->GetPreferredSize();
visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
caption_y, visible_button_size.width(),
visible_button_size.height());
next_button_x = visible_button->x();
} else {
visible_button->SetVisible(false);
next_button_x = close_button_->x();
}
minimize_button_->SetVisible(true);
minimize_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
views::ImageButton::ALIGN_BOTTOM);
gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
minimize_button_->SetBounds(
next_button_x - minimize_button_size.width(), caption_y,
minimize_button_size.width(),
minimize_button_size.height());
normal_part = IDR_CLOSE;
hot_part = IDR_CLOSE_H;
pushed_part = IDR_CLOSE_P;
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
close_button_->SetImage(views::CustomButton::STATE_NORMAL,
rb.GetImageNamed(normal_part).ToImageSkia());
close_button_->SetImage(views::CustomButton::STATE_HOVERED,
rb.GetImageNamed(hot_part).ToImageSkia());
close_button_->SetImage(views::CustomButton::STATE_PRESSED,
rb.GetImageNamed(pushed_part).ToImageSkia());
}
void LinuxFrameView::LayoutTitleBar() {
// The window title position is calculated based on the icon position, even
// when there is no icon.
gfx::Rect icon_bounds(IconBounds());
bool show_window_icon = window_icon_ != NULL;
if (show_window_icon)
window_icon_->SetBoundsRect(icon_bounds);
// The offset between the window left edge and the title text.
int title_x = show_window_icon ? icon_bounds.right() + kTitleIconOffsetX
: icon_bounds.x();
int title_height = GetTitleFontList().GetHeight();
// We bias the title position so that when the difference between the icon and
// title heights is odd, the extra pixel of the title is above the vertical
// midline rather than below. This compensates for how the icon is already
// biased downwards (see IconBounds()) and helps prevent descenders on the
// title from overlapping the 3D edge at the bottom of the titlebar.
title_bounds_.SetRect(title_x,
icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
std::max(0, minimize_button_->x() - kTitleCaptionSpacing -
title_x), title_height);
}
void LinuxFrameView::LayoutClientView() {
if (!ShouldShowTitleBarAndBorder()) {
client_view_bounds_ = bounds();
return;
}
int top_height = NonClientTopBorderHeight();
int border_thickness = NonClientBorderThickness();
client_view_bounds_.SetRect(border_thickness, top_height,
std::max(0, width() - (2 * border_thickness)),
std::max(0, height() - top_height - border_thickness));
}
views::ImageButton* LinuxFrameView::InitWindowCaptionButton(
int accessibility_string_id,
int normal_image_id,
int hot_image_id,
int pushed_image_id) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
views::ImageButton* button = new views::ImageButton(this);
button->SetAccessibleName(l10n_util::GetStringUTF16(accessibility_string_id));
button->SetImage(views::CustomButton::STATE_NORMAL,
rb.GetImageNamed(normal_image_id).ToImageSkia());
button->SetImage(views::CustomButton::STATE_HOVERED,
rb.GetImageNamed(hot_image_id).ToImageSkia());
button->SetImage(views::CustomButton::STATE_PRESSED,
rb.GetImageNamed(pushed_image_id).ToImageSkia());
AddChildView(button);
return button;
}
} // namespace atom

View file

@ -0,0 +1,138 @@
// 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_UI_VIEWS_LINUX_FRAME_VIEW_H_
#define ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_
#include "atom/browser/ui/views/frameless_view.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/window/frame_buttons.h"
namespace gfx {
class ImageSkia;
}
namespace views {
class FrameBackground;
class ImageButton;
}
namespace atom {
class LinuxFrameView : public FramelessView,
public views::ButtonListener {
public:
LinuxFrameView();
virtual ~LinuxFrameView();
void Init(NativeWindowViews* window, views::Widget* frame) OVERRIDE;
// Overridden from NonClientFrameView:
virtual gfx::Rect GetBoundsForClientView() const OVERRIDE;
virtual gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const OVERRIDE;
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
virtual void GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) OVERRIDE;
virtual void ResetWindowControls() OVERRIDE;
virtual void UpdateWindowIcon() OVERRIDE;
virtual void UpdateWindowTitle() OVERRIDE;
// Overridden from View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void Layout() OVERRIDE;
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual gfx::Size GetMinimumSize() OVERRIDE;
virtual gfx::Size GetMaximumSize() OVERRIDE;
// Overridden from ButtonListener:
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
private:
// Returns the thickness of the border that makes up the window frame edges.
// This does not include any client edge.
int FrameBorderThickness() const;
// Returns the thickness of the entire nonclient left, right, and bottom
// borders, including both the window frame and any client edge.
int NonClientBorderThickness() const;
// Returns the height of the entire nonclient top border, including the window
// frame, any title area, and any connected client edge.
int NonClientTopBorderHeight() const;
// Returns the y-coordinate of the caption buttons.
int CaptionButtonY() const;
// Returns the thickness of the nonclient portion of the 3D edge along the
// bottom of the titlebar.
int TitlebarBottomThickness() const;
// Returns the size of the titlebar icon. This is used even when the icon is
// not shown, e.g. to set the titlebar height.
int IconSize() const;
// Returns the bounds of the titlebar icon (or where the icon would be if
// there was one).
gfx::Rect IconBounds() const;
// Returns true if the title bar, caption buttons, and frame border should be
// drawn. If false, the client view occupies the full area of this view.
bool ShouldShowTitleBarAndBorder() const;
// Returns true if the client edge should be drawn. This is true if
// the window is not maximized.
bool ShouldShowClientEdge() const;
// Paint various sub-components of this view.
void PaintRestoredFrameBorder(gfx::Canvas* canvas);
void PaintMaximizedFrameBorder(gfx::Canvas* canvas);
void PaintTitleBar(gfx::Canvas* canvas);
void PaintRestoredClientEdge(gfx::Canvas* canvas);
// Compute aspects of the frame needed to paint the frame background.
SkColor GetFrameColor() const;
const gfx::ImageSkia* GetFrameImage() const;
// Layout various sub-components of this view.
void LayoutWindowControls();
void LayoutTitleBar();
void LayoutClientView();
// Creates, adds and returns a new window caption button (e.g, minimize,
// maximize, restore).
views::ImageButton* InitWindowCaptionButton(int accessibility_string_id,
int normal_image_id,
int hot_image_id,
int pushed_image_id);
// The bounds of the client view, in this view's coordinates.
gfx::Rect client_view_bounds_;
// The layout rect of the title, if visible.
gfx::Rect title_bounds_;
// The icon of this window. May be NULL.
views::ImageButton* window_icon_;
// Window caption buttons.
views::ImageButton* minimize_button_;
views::ImageButton* maximize_button_;
views::ImageButton* restore_button_;
views::ImageButton* close_button_;
// Should maximize button be shown?
bool should_show_maximize_button_;
// Background painter for the window frame.
scoped_ptr<views::FrameBackground> frame_background_;
DISALLOW_COPY_AND_ASSIGN(LinuxFrameView);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_

View file

@ -0,0 +1,95 @@
// 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/views/menu_bar.h"
#include "atom/browser/ui/views/menu_delegate.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/layout/box_layout.h"
namespace atom {
namespace {
const char kViewClassName[] = "AtomMenuBar";
// Default color of the menu bar.
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);
} // namespace
MenuBar::MenuBar()
: menu_model_(NULL) {
set_background(views::Background::CreateSolidBackground(kDefaultColor));
SetLayoutManager(new views::BoxLayout(
views::BoxLayout::kHorizontal, 0, 0, 0));
}
MenuBar::~MenuBar() {
}
void MenuBar::SetMenu(ui::MenuModel* model) {
menu_model_ = model;
RemoveAllChildViews(true);
for (int i = 0; i < model->GetItemCount(); ++i) {
views::MenuButton* button =
new views::MenuButton(this, model->GetLabelAt(i), this, false);
button->set_tag(i);
AddChildView(button);
}
}
int MenuBar::GetItemCount() const {
return menu_model_->GetItemCount();
}
bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
ui::MenuModel** menu_model,
views::MenuButton** button) {
gfx::Point location(point);
views::View::ConvertPointFromScreen(this, &location);
if (location.x() < 0 || location.x() >= width() || location.y() < 0 ||
location.y() >= height())
return false;
for (int i = 0; i < child_count(); ++i) {
views::View* view = child_at(i);
if (view->bounds().Contains(location) &&
(menu_model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) {
*menu_model = menu_model_->GetSubmenuModelAt(i);
*button = static_cast<views::MenuButton*>(view);
return true;
}
}
return false;
}
const char* MenuBar::GetClassName() const {
return kViewClassName;
}
void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) {
}
void MenuBar::OnMenuButtonClicked(views::View* source,
const gfx::Point& point) {
if (!menu_model_)
return;
views::MenuButton* button = static_cast<views::MenuButton*>(source);
int id = button->tag();
ui::MenuModel::ItemType type = menu_model_->GetTypeAt(id);
if (type != ui::MenuModel::TYPE_SUBMENU)
return;
menu_delegate_.reset(new MenuDelegate(this));
menu_delegate_->RunMenu(menu_model_->GetSubmenuModelAt(id), button);
}
} // namespace atom

View file

@ -0,0 +1,63 @@
// 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_UI_VIEWS_MENU_BAR_H_
#define ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/menu_button_listener.h"
#include "ui/views/view.h"
namespace ui {
class MenuModel;
}
namespace views {
class MenuButton;
}
namespace atom {
class MenuDelegate;
class MenuBar : public views::View,
public views::ButtonListener,
public views::MenuButtonListener {
public:
MenuBar();
virtual ~MenuBar();
// Replaces current menu with a new one.
void SetMenu(ui::MenuModel* menu_model);
// Returns there are how many items in the root menu.
int GetItemCount() const;
// Get the menu under specified screen point.
bool GetMenuButtonFromScreenPoint(const gfx::Point& point,
ui::MenuModel** menu_model,
views::MenuButton** button);
protected:
// views::View:
virtual const char* GetClassName() const OVERRIDE;
// views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
// views::MenuButtonListener:
virtual void OnMenuButtonClicked(views::View* source,
const gfx::Point& point) OVERRIDE;
private:
ui::MenuModel* menu_model_;
scoped_ptr<MenuDelegate> menu_delegate_;
DISALLOW_COPY_AND_ASSIGN(MenuBar);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_

View file

@ -0,0 +1,124 @@
// 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/views/menu_delegate.h"
#include "atom/browser/ui/views/menu_bar.h"
#include "base/stl_util.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/widget/widget.h"
namespace atom {
MenuDelegate::MenuDelegate(MenuBar* menu_bar)
: menu_bar_(menu_bar),
id_(-1),
items_(menu_bar_->GetItemCount()),
delegates_(menu_bar_->GetItemCount()) {
}
MenuDelegate::~MenuDelegate() {
STLDeleteElements(&delegates_);
}
void MenuDelegate::RunMenu(ui::MenuModel* model, views::MenuButton* button) {
gfx::Point screen_loc;
views::View::ConvertPointToScreen(button, &screen_loc);
// Subtract 1 from the height to make the popup flush with the button border.
gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(),
button->height() - 1);
id_ = button->tag();
views::MenuItemView* item = BuildMenu(model);
views::MenuRunner menu_runner(item);
ignore_result(menu_runner.RunMenuAt(
button->GetWidget()->GetTopLevelWidget(),
button,
bounds,
views::MenuItemView::TOPRIGHT,
ui::MENU_SOURCE_MOUSE,
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
}
views::MenuItemView* MenuDelegate::BuildMenu(ui::MenuModel* model) {
DCHECK_GE(id_, 0);
if (!items_[id_]) {
views::MenuModelAdapter* delegate = new views::MenuModelAdapter(model);
delegates_[id_] = delegate;
views::MenuItemView* item = new views::MenuItemView(this);
delegate->BuildMenu(item);
items_[id_] = item;
}
return items_[id_];
}
void MenuDelegate::ExecuteCommand(int id) {
delegate()->ExecuteCommand(id);
}
void MenuDelegate::ExecuteCommand(int id, int mouse_event_flags) {
delegate()->ExecuteCommand(id, mouse_event_flags);
}
bool MenuDelegate::IsTriggerableEvent(views::MenuItemView* source,
const ui::Event& e) {
return delegate()->IsTriggerableEvent(source, e);
}
bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) {
return delegate()->GetAccelerator(id, accelerator);
}
base::string16 MenuDelegate::GetLabel(int id) const {
return delegate()->GetLabel(id);
}
const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const {
return delegate()->GetLabelFontList(id);
}
bool MenuDelegate::IsCommandEnabled(int id) const {
return delegate()->IsCommandEnabled(id);
}
bool MenuDelegate::IsItemChecked(int id) const {
return delegate()->IsItemChecked(id);
}
void MenuDelegate::SelectionChanged(views::MenuItemView* menu) {
delegate()->SelectionChanged(menu);
}
void MenuDelegate::WillShowMenu(views::MenuItemView* menu) {
delegate()->WillShowMenu(menu);
}
void MenuDelegate::WillHideMenu(views::MenuItemView* menu) {
delegate()->WillHideMenu(menu);
}
views::MenuItemView* MenuDelegate::GetSiblingMenu(
views::MenuItemView* menu,
const gfx::Point& screen_point,
views::MenuItemView::AnchorPosition* anchor,
bool* has_mnemonics,
views::MenuButton** button) {
ui::MenuModel* model;
if (!menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, button))
return NULL;
*anchor = views::MenuItemView::TOPLEFT;
*has_mnemonics = true;
id_ = (*button)->tag();
return BuildMenu(model);
}
} // namespace atom

View file

@ -0,0 +1,74 @@
// 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_UI_VIEWS_MENU_DELEGATE_H_
#define ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_
#include <vector>
#include "ui/views/controls/menu/menu_delegate.h"
namespace views {
class MenuModelAdapter;
}
namespace ui {
class MenuModel;
}
namespace atom {
class MenuBar;
class MenuDelegate : public views::MenuDelegate {
public:
explicit MenuDelegate(MenuBar* menu_bar);
virtual ~MenuDelegate();
void RunMenu(ui::MenuModel* model, views::MenuButton* button);
protected:
// views::MenuDelegate:
virtual void ExecuteCommand(int id) OVERRIDE;
virtual void ExecuteCommand(int id, int mouse_event_flags) OVERRIDE;
virtual bool IsTriggerableEvent(views::MenuItemView* source,
const ui::Event& e) OVERRIDE;
virtual bool GetAccelerator(int id,
ui::Accelerator* accelerator) OVERRIDE;
virtual base::string16 GetLabel(int id) const OVERRIDE;
virtual const gfx::FontList* GetLabelFontList(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
virtual bool IsItemChecked(int id) const OVERRIDE;
virtual void SelectionChanged(views::MenuItemView* menu) OVERRIDE;
virtual void WillShowMenu(views::MenuItemView* menu) OVERRIDE;
virtual void WillHideMenu(views::MenuItemView* menu) OVERRIDE;
virtual views::MenuItemView* GetSiblingMenu(
views::MenuItemView* menu,
const gfx::Point& screen_point,
views::MenuItemView::AnchorPosition* anchor,
bool* has_mnemonics,
views::MenuButton** button);
private:
// Gets the cached menu item view from the model.
views::MenuItemView* BuildMenu(ui::MenuModel* model);
// Returns delegate for current item.
views::MenuDelegate* delegate() const { return delegates_[id_]; }
MenuBar* menu_bar_;
// Current item's id.
int id_;
// Cached menu items, managed by MenuRunner.
std::vector<views::MenuItemView*> items_;
// Cached menu delegates for each menu item, managed by us.
std::vector<views::MenuDelegate*> delegates_;
DISALLOW_COPY_AND_ASSIGN(MenuDelegate);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_

View file

@ -0,0 +1,54 @@
// 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/views/menu_layout.h"
namespace atom {
MenuLayout::MenuLayout(int menu_height)
: menu_height_(menu_height) {
}
MenuLayout::~MenuLayout() {
}
void MenuLayout::Layout(views::View* host) {
if (!HasMenu(host)) {
views::FillLayout::Layout(host);
return;
}
gfx::Size size = host->GetContentsBounds().size();
gfx::Rect menu_Bar_bounds = gfx::Rect(0, 0, size.width(), menu_height_);
gfx::Rect web_view_bounds = gfx::Rect(
0, menu_height_, size.width(), size.height() - menu_height_);
views::View* menu_bar = host->child_at(0);
views::View* web_view = host->child_at(1);
menu_bar->SetBoundsRect(menu_Bar_bounds);
web_view->SetBoundsRect(web_view_bounds);
}
gfx::Size MenuLayout::GetPreferredSize(views::View* host) {
gfx::Size size = views::FillLayout::GetPreferredSize(host);
if (!HasMenu(host))
return size;
size.set_height(size.height() + menu_height_);
return size;
}
int MenuLayout::GetPreferredHeightForWidth(views::View* host, int width) {
int height = views::FillLayout::GetPreferredHeightForWidth(host, width);
if (!HasMenu(host))
return height;
return height + menu_height_;
}
bool MenuLayout::HasMenu(const views::View* host) const {
return host->child_count() == 2;
}
} // namespace atom

View file

@ -0,0 +1,32 @@
// 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_UI_VIEWS_MENU_LAYOUT_H_
#define ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_
#include "ui/views/layout/fill_layout.h"
namespace atom {
class MenuLayout : public views::FillLayout {
public:
explicit MenuLayout(int menu_height);
virtual ~MenuLayout();
// views::LayoutManager:
virtual void Layout(views::View* host) OVERRIDE;
virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE;
virtual int GetPreferredHeightForWidth(views::View* host, int width) OVERRIDE;
private:
bool HasMenu(const views::View* host) const;
int menu_height_;
DISALLOW_COPY_AND_ASSIGN(MenuLayout);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_

View file

@ -0,0 +1,64 @@
// 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/views/win_frame_view.h"
#include "atom/browser/native_window_views.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/widget/widget.h"
#include "ui/views/win/hwnd_util.h"
namespace atom {
namespace {
const char kViewClassName[] = "WinFrameView";
} // namespace
WinFrameView::WinFrameView() {
}
WinFrameView::~WinFrameView() {
}
gfx::Rect WinFrameView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
gfx::Size size(client_bounds.size());
ClientAreaSizeToWindowSize(&size);
return gfx::Rect(client_bounds.origin(), size);
}
int WinFrameView::NonClientHitTest(const gfx::Point& point) {
if (window_->has_frame())
return frame_->client_view()->NonClientHitTest(point);
else
return FramelessView::NonClientHitTest(point);
}
gfx::Size WinFrameView::GetMinimumSize() {
gfx::Size size = FramelessView::GetMinimumSize();
return gfx::win::DIPToScreenSize(size);
}
gfx::Size WinFrameView::GetMaximumSize() {
gfx::Size size = FramelessView::GetMaximumSize();
return gfx::win::DIPToScreenSize(size);
}
const char* WinFrameView::GetClassName() const {
return kViewClassName;
}
void WinFrameView::ClientAreaSizeToWindowSize(gfx::Size* size) const {
// AdjustWindowRect seems to return a wrong window size.
gfx::Size window = frame_->GetWindowBoundsInScreen().size();
gfx::Size client = frame_->GetClientAreaBoundsInScreen().size();
size->set_width(size->width() + window.width() - client.width());
size->set_height(size->height() + window.height() - client.height());
}
} // namespace atom

View file

@ -0,0 +1,35 @@
// 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_UI_VIEWS_WIN_FRAME_VIEW_H_
#define ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_
#include "atom/browser/ui/views/frameless_view.h"
namespace atom {
class WinFrameView : public FramelessView {
public:
WinFrameView();
virtual ~WinFrameView();
// views::NonClientFrameView:
virtual gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const OVERRIDE;
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
// views::View:
virtual gfx::Size GetMinimumSize() OVERRIDE;
virtual gfx::Size GetMaximumSize() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
private:
void ClientAreaSizeToWindowSize(gfx::Size* size) const;
DISALLOW_COPY_AND_ASSIGN(WinFrameView);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_

View file

@ -1,65 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2012 The Chromium Authors. 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/win/menu_2.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/controls/menu/menu_listener.h"
// Really bad hack here, renaming all class names would be too much work.
using namespace views; // NOLINT
namespace atom {
Menu2::Menu2(ui::MenuModel* model, bool as_window_menu)
: model_(model),
wrapper_(new NativeMenuWin(model, NULL)) {
wrapper_->set_create_as_window_menu(as_window_menu);
Rebuild();
}
Menu2::~Menu2() {}
HMENU Menu2::GetNativeMenu() const {
return wrapper_->GetNativeMenu();
}
void Menu2::RunMenuAt(const gfx::Point& point, Alignment alignment) {
wrapper_->RunMenuAt(point, alignment);
}
void Menu2::RunContextMenuAt(const gfx::Point& point) {
RunMenuAt(point, ALIGN_TOPLEFT);
}
void Menu2::CancelMenu() {
wrapper_->CancelMenu();
}
void Menu2::Rebuild() {
wrapper_->Rebuild(NULL);
}
void Menu2::UpdateStates() {
wrapper_->UpdateStates();
}
NativeMenuWin::MenuAction Menu2::GetMenuAction() const {
return wrapper_->GetMenuAction();
}
void Menu2::AddMenuListener(MenuListener* listener) {
wrapper_->AddMenuListener(listener);
}
void Menu2::RemoveMenuListener(MenuListener* listener) {
wrapper_->RemoveMenuListener(listener);
}
void Menu2::SetMinimumWidth(int width) {
wrapper_->SetMinimumWidth(width);
}
} // namespace atom

View file

@ -1,96 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. 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_UI_WIN_MENU_2_H_
#define ATOM_BROWSER_UI_WIN_MENU_2_H_
#include "atom/browser/ui/win/native_menu_win.h"
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
class Point;
}
namespace ui {
class MenuModel;
}
namespace atom {
// A menu. Populated from a model, and relies on a delegate to execute commands.
//
// WARNING: do NOT create and use Menu2 on the stack. Menu2 notifies the model
// of selection AFTER a delay. This means that if use a Menu2 on the stack
// ActivatedAt is never invoked.
class Menu2 {
public:
// How the menu is aligned relative to the point it is shown at.
// The alignment is reversed by menu if text direction is right to left.
enum Alignment {
ALIGN_TOPLEFT,
ALIGN_TOPRIGHT
};
// Creates a new menu populated with the contents of |model|.
// WARNING: this populates the menu on construction by invoking methods on
// the model. As such, it is typically not safe to use this as the model
// from the constructor. EG:
// MyClass : menu_(this) {}
// is likely to have problems.
explicit Menu2(ui::MenuModel* model, bool as_window_menu = false);
virtual ~Menu2();
// Runs the menu at the specified point. This method blocks until done.
// RunContextMenuAt is the same, but the alignment is the default for a
// context menu.
void RunMenuAt(const gfx::Point& point, Alignment alignment);
void RunContextMenuAt(const gfx::Point& point);
// Cancels the active menu.
void CancelMenu();
// Called when the model supplying data to this menu has changed, and the menu
// must be rebuilt.
void Rebuild();
// Called when the states of the menu items in the menu should be refreshed
// from the model.
void UpdateStates();
// For submenus.
HMENU GetNativeMenu() const;
// Get the result of the last call to RunMenuAt to determine whether an
// item was selected, the user navigated to a next or previous menu, or
// nothing.
NativeMenuWin::MenuAction GetMenuAction() const;
// Add a listener to receive a callback when the menu opens.
void AddMenuListener(views::MenuListener* listener);
// Remove a menu listener.
void RemoveMenuListener(views::MenuListener* listener);
// Accessors.
ui::MenuModel* model() const { return model_; }
NativeMenuWin* wrapper() const { return wrapper_.get(); }
// Sets the minimum width of the menu.
void SetMinimumWidth(int width);
private:
ui::MenuModel* model_;
// The object that actually implements the menu.
scoped_ptr<NativeMenuWin> wrapper_;
DISALLOW_COPY_AND_ASSIGN(Menu2);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_MENU_2_H_

View file

@ -1,765 +0,0 @@
// Copyright (c) 2012 The Chromium Authors. 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/win/native_menu_win.h"
#include <Windowsx.h>
#include "atom/browser/ui/win/menu_2.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/win/wrapped_window_proc.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_win.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_insertion_delegate_win.h"
#include "ui/views/controls/menu/menu_listener.h"
using ui::NativeTheme;
// Really bad hack here, renaming all class names would be too much work.
using namespace views; // NOLINT
namespace atom {
// The width of an icon, including the pixels between the icon and
// the item label.
static const int kIconWidth = 23;
// Margins between the top of the item and the label.
static const int kItemTopMargin = 3;
// Margins between the bottom of the item and the label.
static const int kItemBottomMargin = 4;
// Margins between the left of the item and the icon.
static const int kItemLeftMargin = 4;
// Margins between the right of the item and the label.
static const int kItemRightMargin = 10;
// The width for displaying the sub-menu arrow.
static const int kArrowWidth = 10;
struct NativeMenuWin::ItemData {
// The Windows API requires that whoever creates the menus must own the
// strings used for labels, and keep them around for the lifetime of the
// created menu. So be it.
string16 label;
// Someone needs to own submenus, it may as well be us.
scoped_ptr<Menu2> submenu;
// We need a pointer back to the containing menu in various circumstances.
NativeMenuWin* native_menu_win;
// The index of the item within the menu's model.
int model_index;
};
// Returns the NativeMenuWin for a particular HMENU.
static NativeMenuWin* GetNativeMenuWinFromHMENU(HMENU hmenu) {
MENUINFO mi = {0};
mi.cbSize = sizeof(mi);
mi.fMask = MIM_MENUDATA | MIM_STYLE;
GetMenuInfo(hmenu, &mi);
return reinterpret_cast<NativeMenuWin*>(mi.dwMenuData);
}
// A window that receives messages from Windows relevant to the native menu
// structure we have constructed in NativeMenuWin.
class NativeMenuWin::MenuHostWindow {
public:
explicit MenuHostWindow(NativeMenuWin* parent) : parent_(parent) {
RegisterClass();
hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
gfx::CheckWindowCreated(hwnd_);
gfx::SetWindowUserData(hwnd_, this);
}
~MenuHostWindow() {
DestroyWindow(hwnd_);
}
// Called when the user selects a specific item.
void OnMenuCommand(int position, HMENU menu) {
NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
ui::MenuModel* model = menu_win->model_;
NativeMenuWin* root_menu = menu_win;
while (root_menu->parent_)
root_menu = root_menu->parent_;
// Only notify the model if it didn't already send out notification.
// See comment in MenuMessageHook for details.
if (root_menu->menu_action_ == MENU_ACTION_NONE)
model->ActivatedAt(position);
}
HWND hwnd() const { return hwnd_; }
private:
static const wchar_t* kWindowClassName;
void RegisterClass() {
static bool registered = false;
if (registered)
return;
WNDCLASSEX window_class;
base::win::InitializeWindowClass(
kWindowClassName,
&base::win::WrappedWindowProc<MenuHostWindowProc>,
CS_DBLCLKS,
0,
0,
NULL,
reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
NULL,
NULL,
NULL,
&window_class);
ATOM clazz = RegisterClassEx(&window_class);
CHECK(clazz);
registered = true;
}
// Converts the WPARAM value passed to WM_MENUSELECT into an index
// corresponding to the menu item that was selected.
int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const {
int count = GetMenuItemCount(menu);
// For normal command menu items, Windows passes a command id as the LOWORD
// of WPARAM for WM_MENUSELECT. We need to walk forward through the menu
// items to find an item with a matching ID. Ugh!
for (int i = 0; i < count; ++i) {
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID;
GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii);
if (mii.wID == w_param)
return i;
}
// If we didn't find a matching command ID, this means a submenu has been
// selected instead, and rather than passing a command ID in
// LOWORD(w_param), Windows has actually passed us a position, so we just
// return it.
return w_param;
}
NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) {
return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
}
// Called as the user moves their mouse or arrows through the contents of the
// menu.
void OnMenuSelect(WPARAM w_param, HMENU menu) {
if (!menu)
return; // menu is null when closing on XP.
int position = GetMenuItemIndexFromWPARAM(menu, w_param);
if (position >= 0)
GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
}
// Called by Windows to measure the size of an owner-drawn menu item.
void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
if (data) {
gfx::Font font;
measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
kIconWidth + kItemLeftMargin + kItemRightMargin -
GetSystemMetrics(SM_CXMENUCHECK);
if (data->submenu.get())
measure_item_struct->itemWidth += kArrowWidth;
// If the label contains an accelerator, make room for tab.
if (data->label.find(L'\t') != string16::npos)
measure_item_struct->itemWidth += font.GetStringWidth(L" ");
measure_item_struct->itemHeight =
font.GetHeight() + kItemBottomMargin + kItemTopMargin;
} else {
// Measure separator size.
measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
measure_item_struct->itemWidth = 0;
}
}
// Called by Windows to paint an owner-drawn menu item.
void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
HDC dc = draw_item_struct->hDC;
COLORREF prev_bg_color, prev_text_color;
// Set background color and text color
if (draw_item_struct->itemState & ODS_SELECTED) {
prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
} else {
prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
if (draw_item_struct->itemState & ODS_DISABLED)
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
else
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
}
if (draw_item_struct->itemData) {
NativeMenuWin::ItemData* data = GetItemData(draw_item_struct->itemData);
// Draw the background.
HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
FillRect(dc, &draw_item_struct->rcItem, hbr);
DeleteObject(hbr);
// Draw the label.
RECT rect = draw_item_struct->rcItem;
rect.top += kItemTopMargin;
// Should we add kIconWidth only when icon.width() != 0 ?
rect.left += kItemLeftMargin + kIconWidth;
rect.right -= kItemRightMargin;
UINT format = DT_TOP | DT_SINGLELINE;
// Check whether the mnemonics should be underlined.
BOOL underline_mnemonics;
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
if (!underline_mnemonics)
format |= DT_HIDEPREFIX;
gfx::Font font;
HGDIOBJ old_font =
static_cast<HFONT>(SelectObject(dc, font.GetNativeFont()));
// If an accelerator is specified (with a tab delimiting the rest of the
// label from the accelerator), we have to justify the fist part on the
// left and the accelerator on the right.
// TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
// window system UI font and will not hit here.
string16 label = data->label;
string16 accel;
string16::size_type tab_pos = label.find(L'\t');
if (tab_pos != string16::npos) {
accel = label.substr(tab_pos);
label = label.substr(0, tab_pos);
}
DrawTextEx(dc, const_cast<wchar_t*>(label.data()),
static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
if (!accel.empty())
DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
static_cast<int>(accel.size()), &rect,
format | DT_RIGHT, NULL);
SelectObject(dc, old_font);
ui::MenuModel::ItemType type =
data->native_menu_win->model_->GetTypeAt(data->model_index);
// Draw the icon after the label, otherwise it would be covered
// by the label.
gfx::Image icon;
if (data->native_menu_win->model_->GetIconAt(data->model_index, &icon)) {
// We currently don't support items with both icons and checkboxes.
const gfx::ImageSkia* skia_icon = icon.ToImageSkia();
DCHECK(type != ui::MenuModel::TYPE_CHECK);
gfx::Canvas canvas(
skia_icon->GetRepresentation(ui::SCALE_FACTOR_100P),
false);
skia::DrawToNativeContext(
canvas.sk_canvas(), dc,
draw_item_struct->rcItem.left + kItemLeftMargin,
draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
draw_item_struct->rcItem.top - skia_icon->height()) / 2, NULL);
} else if (type == ui::MenuModel::TYPE_CHECK &&
data->native_menu_win->model_->IsItemCheckedAt(
data->model_index)) {
// Manually render a checkbox.
ui::NativeThemeWin* native_theme = ui::NativeThemeWin::instance();
const MenuConfig& config = MenuConfig::instance(native_theme);
NativeTheme::State state;
if (draw_item_struct->itemState & ODS_DISABLED) {
state = NativeTheme::kDisabled;
} else {
state = draw_item_struct->itemState & ODS_SELECTED ?
NativeTheme::kHovered : NativeTheme::kNormal;
}
int height =
draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top;
int icon_y = kItemTopMargin +
(height - kItemTopMargin - kItemBottomMargin -
config.check_height) / 2;
gfx::Canvas canvas(gfx::Size(config.check_width, config.check_height),
ui::SCALE_FACTOR_100P,
false);
NativeTheme::ExtraParams extra;
extra.menu_check.is_radio = false;
gfx::Rect bounds(0, 0, config.check_width, config.check_height);
// Draw the background and the check.
native_theme->Paint(
canvas.sk_canvas(), NativeTheme::kMenuCheckBackground,
state, bounds, extra);
native_theme->Paint(
canvas.sk_canvas(), NativeTheme::kMenuCheck, state, bounds, extra);
// Draw checkbox to menu.
skia::DrawToNativeContext(canvas.sk_canvas(), dc,
draw_item_struct->rcItem.left + kItemLeftMargin,
draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
draw_item_struct->rcItem.top - config.check_height) / 2, NULL);
}
} else {
// Draw the separator
draw_item_struct->rcItem.top +=
(draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
}
SetBkColor(dc, prev_bg_color);
SetTextColor(dc, prev_text_color);
}
bool ProcessWindowMessage(HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param,
LRESULT* l_result) {
switch (message) {
case WM_MENUCOMMAND:
OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
*l_result = 0;
return true;
case WM_MENUSELECT:
OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
*l_result = 0;
return true;
case WM_MEASUREITEM:
OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param));
*l_result = 0;
return true;
case WM_DRAWITEM:
OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param));
*l_result = 0;
return true;
// TODO(beng): bring over owner draw from old menu system.
}
return false;
}
static LRESULT CALLBACK MenuHostWindowProc(HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param) {
MenuHostWindow* host =
reinterpret_cast<MenuHostWindow*>(gfx::GetWindowUserData(window));
// host is null during initial construction.
LRESULT l_result = 0;
if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param,
&l_result)) {
return DefWindowProc(window, message, w_param, l_param);
}
return l_result;
}
HWND hwnd_;
NativeMenuWin* parent_;
DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
};
struct NativeMenuWin::HighlightedMenuItemInfo {
HighlightedMenuItemInfo()
: has_parent(false),
has_submenu(false),
menu(NULL),
position(-1) {
}
bool has_parent;
bool has_submenu;
// The menu and position. These are only set for non-disabled menu items.
NativeMenuWin* menu;
int position;
};
// static
const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName =
L"ViewsMenuHostWindow";
////////////////////////////////////////////////////////////////////////////////
// NativeMenuWin, public:
NativeMenuWin::NativeMenuWin(ui::MenuModel* model, HWND system_menu_for)
: model_(model),
menu_(NULL),
owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL) &&
!system_menu_for),
system_menu_for_(system_menu_for),
first_item_index_(0),
menu_action_(MENU_ACTION_NONE),
menu_to_select_(NULL),
position_to_select_(-1),
menu_to_select_factory_(this),
parent_(NULL),
destroyed_flag_(NULL),
create_as_window_menu_(false) {
}
NativeMenuWin::~NativeMenuWin() {
if (destroyed_flag_)
*destroyed_flag_ = true;
STLDeleteContainerPointers(items_.begin(), items_.end());
DestroyMenu(menu_);
}
////////////////////////////////////////////////////////////////////////////////
// NativeMenuWin, MenuWrapper implementation:
void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
CreateHostWindow();
UpdateStates();
UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RECURSE;
flags |= GetAlignmentFlags(alignment);
menu_action_ = MENU_ACTION_NONE;
// Set a hook function so we can listen for keyboard events while the
// menu is open, and store a pointer to this object in a static
// variable so the hook has access to it (ugly, but it's the
// only way).
open_native_menu_win_ = this;
HHOOK hhook = SetWindowsHookEx(WH_MSGFILTER, MenuMessageHook,
GetModuleHandle(NULL), ::GetCurrentThreadId());
// Mark that any registered listeners have not been called for this particular
// opening of the menu.
listeners_called_ = false;
// Command dispatch is done through WM_MENUCOMMAND, handled by the host
// window.
HWND hwnd = host_window_->hwnd();
menu_to_select_ = NULL;
position_to_select_ = -1;
menu_to_select_factory_.InvalidateWeakPtrs();
bool destroyed = false;
destroyed_flag_ = &destroyed;
model_->MenuWillShow();
TrackPopupMenu(menu_, flags, point.x(), point.y(), 0, host_window_->hwnd(),
NULL);
UnhookWindowsHookEx(hhook);
open_native_menu_win_ = NULL;
if (destroyed)
return;
destroyed_flag_ = NULL;
if (menu_to_select_) {
// Folks aren't too happy if we notify immediately. In particular, notifying
// the delegate can cause destruction leaving the stack in a weird
// state. Instead post a task, then notify. This mirrors what WM_MENUCOMMAND
// does.
menu_to_select_factory_.InvalidateWeakPtrs();
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&NativeMenuWin::DelayedSelect,
menu_to_select_factory_.GetWeakPtr()));
menu_action_ = MENU_ACTION_SELECTED;
}
// Send MenuClosed after we schedule the select, otherwise MenuClosed is
// processed after the select (MenuClosed posts a delayed task too).
model_->MenuClosed();
}
void NativeMenuWin::CancelMenu() {
EndMenu();
}
void NativeMenuWin::Rebuild(MenuInsertionDelegateWin* delegate) {
ResetNativeMenu();
items_.clear();
owner_draw_ = model_->HasIcons() || owner_draw_;
first_item_index_ = delegate ? delegate->GetInsertionIndex(menu_) : 0;
for (int menu_index = first_item_index_;
menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) {
int model_index = menu_index - first_item_index_;
if (model_->GetTypeAt(model_index) == ui::MenuModel::TYPE_SEPARATOR)
AddSeparatorItemAt(menu_index, model_index);
else
AddMenuItemAt(menu_index, model_index);
}
}
void NativeMenuWin::UpdateStates() {
// A depth-first walk of the menu items, updating states.
int model_index = 0;
std::vector<ItemData*>::const_iterator it;
for (it = items_.begin(); it != items_.end(); ++it, ++model_index) {
int menu_index = model_index + first_item_index_;
SetMenuItemState(menu_index, model_->IsEnabledAt(model_index),
model_->IsItemCheckedAt(model_index), false);
if (model_->IsItemDynamicAt(model_index)) {
// TODO(atwilson): Update the icon as well (http://crbug.com/66508).
SetMenuItemLabel(menu_index, model_index,
model_->GetLabelAt(model_index));
}
Menu2* submenu = (*it)->submenu.get();
if (submenu)
submenu->UpdateStates();
}
}
HMENU NativeMenuWin::GetNativeMenu() const {
return menu_;
}
NativeMenuWin::MenuAction NativeMenuWin::GetMenuAction() const {
return menu_action_;
}
void NativeMenuWin::AddMenuListener(MenuListener* listener) {
listeners_.AddObserver(listener);
}
void NativeMenuWin::RemoveMenuListener(MenuListener* listener) {
listeners_.RemoveObserver(listener);
}
void NativeMenuWin::SetMinimumWidth(int width) {
NOTIMPLEMENTED();
}
void NativeMenuWin::OnMenuCommand(int position, HMENU menu) {
host_window_->OnMenuCommand(position, menu);
}
////////////////////////////////////////////////////////////////////////////////
// NativeMenuWin, private:
// static
NativeMenuWin* NativeMenuWin::open_native_menu_win_ = NULL;
void NativeMenuWin::DelayedSelect() {
if (menu_to_select_)
menu_to_select_->model_->ActivatedAt(position_to_select_);
}
// static
bool NativeMenuWin::GetHighlightedMenuItemInfo(
HMENU menu,
HighlightedMenuItemInfo* info) {
for (int i = 0; i < ::GetMenuItemCount(menu); i++) {
UINT state = ::GetMenuState(menu, i, MF_BYPOSITION);
if (state & MF_HILITE) {
if (state & MF_POPUP) {
HMENU submenu = GetSubMenu(menu, i);
if (GetHighlightedMenuItemInfo(submenu, info))
info->has_parent = true;
else
info->has_submenu = true;
} else if (!(state & MF_SEPARATOR) && !(state & MF_DISABLED)) {
info->menu = GetNativeMenuWinFromHMENU(menu);
info->position = i;
}
return true;
}
}
return false;
}
// static
LRESULT CALLBACK NativeMenuWin::MenuMessageHook(
int n_code, WPARAM w_param, LPARAM l_param) {
LRESULT result = CallNextHookEx(NULL, n_code, w_param, l_param);
NativeMenuWin* this_ptr = open_native_menu_win_;
if (!this_ptr)
return result;
// The first time this hook is called, that means the menu has successfully
// opened, so call the callback function on all of our listeners.
if (!this_ptr->listeners_called_) {
FOR_EACH_OBSERVER(MenuListener, this_ptr->listeners_, OnMenuOpened());
this_ptr->listeners_called_ = true;
}
MSG* msg = reinterpret_cast<MSG*>(l_param);
if (msg->message == WM_LBUTTONUP || msg->message == WM_RBUTTONUP) {
HighlightedMenuItemInfo info;
if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info) && info.menu) {
// It appears that when running a menu by way of TrackPopupMenu(Ex) win32
// gets confused if the underlying window paints itself. As its very easy
// for the underlying window to repaint itself (especially since some menu
// items trigger painting of the tabstrip on mouse over) we have this
// workaround. When the mouse is released on a menu item we remember the
// menu item and end the menu. When the nested message loop returns we
// schedule a task to notify the model. It's still possible to get a
// WM_MENUCOMMAND, so we have to be careful that we don't notify the model
// twice.
this_ptr->menu_to_select_ = info.menu;
this_ptr->position_to_select_ = info.position;
EndMenu();
}
} else if (msg->message == WM_KEYDOWN) {
HighlightedMenuItemInfo info;
if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info)) {
if (msg->wParam == VK_LEFT && !info.has_parent) {
this_ptr->menu_action_ = MENU_ACTION_PREVIOUS;
::EndMenu();
} else if (msg->wParam == VK_RIGHT && !info.has_parent &&
!info.has_submenu) {
this_ptr->menu_action_ = MENU_ACTION_NEXT;
::EndMenu();
}
}
}
return result;
}
bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_FTYPE;
GetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
return !!(mii.fType & MF_SEPARATOR);
}
void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA;
if (!owner_draw_)
mii.fType = MFT_STRING;
else
mii.fType = MFT_OWNERDRAW;
ItemData* item_data = new ItemData;
item_data->label = string16();
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
if (type == ui::MenuModel::TYPE_SUBMENU) {
item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
mii.fMask |= MIIM_SUBMENU;
mii.hSubMenu = item_data->submenu->GetNativeMenu();
GetNativeMenuWinFromHMENU(mii.hSubMenu)->parent_ = this;
} else {
if (type == ui::MenuModel::TYPE_RADIO)
mii.fType |= MFT_RADIOCHECK;
mii.wID = model_->GetCommandIdAt(model_index);
}
item_data->native_menu_win = this;
item_data->model_index = model_index;
items_.insert(items_.begin() + model_index, item_data);
mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data);
UpdateMenuItemInfoForString(&mii, model_index,
model_->GetLabelAt(model_index));
InsertMenuItem(menu_, menu_index, TRUE, &mii);
}
void NativeMenuWin::AddSeparatorItemAt(int menu_index, int model_index) {
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_FTYPE;
mii.fType = MFT_SEPARATOR;
// Insert a dummy entry into our label list so we can index directly into it
// using item indices if need be.
items_.insert(items_.begin() + model_index, new ItemData);
InsertMenuItem(menu_, menu_index, TRUE, &mii);
}
void NativeMenuWin::SetMenuItemState(int menu_index, bool enabled, bool checked,
bool is_default) {
if (IsSeparatorItemAt(menu_index))
return;
UINT state = enabled ? MFS_ENABLED : MFS_DISABLED;
if (checked)
state |= MFS_CHECKED;
if (is_default)
state |= MFS_DEFAULT;
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE;
mii.fState = state;
SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
}
void NativeMenuWin::SetMenuItemLabel(int menu_index,
int model_index,
const string16& label) {
if (IsSeparatorItemAt(menu_index))
return;
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
UpdateMenuItemInfoForString(&mii, model_index, label);
SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
}
void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
int model_index,
const string16& label) {
string16 formatted = label;
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
// Strip out any tabs, otherwise they get interpreted as accelerators and can
// lead to weird behavior.
ReplaceSubstringsAfterOffset(&formatted, 0, L"\t", L" ");
if (type != ui::MenuModel::TYPE_SUBMENU) {
// Add accelerator details to the label if provided.
ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE);
if (model_->GetAcceleratorAt(model_index, &accelerator)) {
formatted += L"\t";
formatted += accelerator.GetShortcutText();
}
}
// Update the owned string, since Windows will want us to keep this new
// version around.
items_[model_index]->label = formatted;
// Give Windows a pointer to the label string.
mii->fMask |= MIIM_STRING;
mii->dwTypeData =
const_cast<wchar_t*>(items_[model_index]->label.c_str());
}
UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
UINT alignment_flags = TPM_TOPALIGN;
if (alignment == Menu2::ALIGN_TOPLEFT)
alignment_flags |= TPM_LEFTALIGN;
else if (alignment == Menu2::ALIGN_TOPRIGHT)
alignment_flags |= TPM_RIGHTALIGN;
return alignment_flags;
}
void NativeMenuWin::ResetNativeMenu() {
if (IsWindow(system_menu_for_)) {
if (menu_)
GetSystemMenu(system_menu_for_, TRUE);
menu_ = GetSystemMenu(system_menu_for_, FALSE);
} else {
if (menu_)
DestroyMenu(menu_);
menu_ = create_as_window_menu_ ? CreateMenu() : CreatePopupMenu();
// Rather than relying on the return value of TrackPopupMenuEx, which is
// always a command identifier, instead we tell the menu to notify us via
// our host window and the WM_MENUCOMMAND message.
MENUINFO mi = {0};
mi.cbSize = sizeof(mi);
mi.fMask = MIM_STYLE | MIM_MENUDATA;
mi.dwStyle = MNS_NOTIFYBYPOS;
mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this);
SetMenuInfo(menu_, &mi);
}
}
void NativeMenuWin::CreateHostWindow() {
// This only gets called from RunMenuAt, and as such there is only ever one
// host window per menu hierarchy, no matter how many NativeMenuWin objects
// exist wrapping submenus.
if (!host_window_.get())
host_window_.reset(new MenuHostWindow(this));
}
} // namespace atom

View file

@ -1,192 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2012 The Chromium Authors. 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_UI_WIN_NATIVE_MENU_WIN_H_
#define ATOM_BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
#include <vector>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
namespace gfx {
class Point;
}
namespace ui {
class MenuModel;
}
namespace views {
class MenuInsertionDelegateWin;
class MenuListener;
}
namespace atom {
class NativeMenuWin {
public:
// All of the possible actions that can result from RunMenuAt.
enum MenuAction {
MENU_ACTION_NONE, // Menu cancelled, or never opened.
MENU_ACTION_SELECTED, // An item was selected.
MENU_ACTION_PREVIOUS, // User wants to navigate to the previous menu.
MENU_ACTION_NEXT, // User wants to navigate to the next menu.
};
// Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
// is non-NULL, the NativeMenuWin wraps the system menu for that window.
// The caller owns the model and the delegate.
NativeMenuWin(ui::MenuModel* model, HWND system_menu_for);
virtual ~NativeMenuWin();
void RunMenuAt(const gfx::Point& point, int alignment);
void CancelMenu();
void Rebuild(views::MenuInsertionDelegateWin* delegate);
void UpdateStates();
HMENU GetNativeMenu() const;
MenuAction GetMenuAction() const;
void AddMenuListener(views::MenuListener* listener);
void RemoveMenuListener(views::MenuListener* listener);
void SetMinimumWidth(int width);
// Called by user to generate a menu command event.
void OnMenuCommand(int position, HMENU menu);
// Flag to create a window menu instead of popup menu.
void set_create_as_window_menu(bool flag) { create_as_window_menu_ = flag; }
bool create_as_window_menu() const { return create_as_window_menu_; }
private:
// IMPORTANT: Note about indices.
// Functions in this class deal in two index spaces:
// 1. menu_index - the index of an item within the actual Windows
// native menu.
// 2. model_index - the index of the item within our model.
// These two are most often but not always the same value! The
// notable exception is when this object is used to wrap the
// Windows System Menu. In this instance, the model indices start
// at 0, but the insertion index into the existing menu is not.
// It is important to take this into consideration when editing the
// code in the functions in this class.
struct HighlightedMenuItemInfo;
// Returns true if the item at the specified index is a separator.
bool IsSeparatorItemAt(int menu_index) const;
// Add items. See note above about indices.
void AddMenuItemAt(int menu_index, int model_index);
void AddSeparatorItemAt(int menu_index, int model_index);
// Sets the state of the item at the specified index.
void SetMenuItemState(int menu_index,
bool enabled,
bool checked,
bool is_default);
// Sets the label of the item at the specified index.
void SetMenuItemLabel(int menu_index,
int model_index,
const string16& label);
// Updates the local data structure with the correctly formatted version of
// |label| at the specified model_index, and adds string data to |mii| if
// the menu is not owner-draw. That's a mouthful. This function exists because
// of the peculiarities of the Windows menu API.
void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
int model_index,
const string16& label);
// Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
// supplied alignment and the UI text direction.
UINT GetAlignmentFlags(int alignment) const;
// Resets the native menu stored in |menu_| by destroying any old menu then
// creating a new empty one.
void ResetNativeMenu();
// Creates the host window that receives notifications from the menu.
void CreateHostWindow();
// Callback from task to notify menu it was selected.
void DelayedSelect();
// Given a menu that's currently popped-up, find the currently highlighted
// item. Returns true if a highlighted item was found.
static bool GetHighlightedMenuItemInfo(HMENU menu,
HighlightedMenuItemInfo* info);
// Hook to receive keyboard events while the menu is open.
static LRESULT CALLBACK MenuMessageHook(
int n_code, WPARAM w_param, LPARAM l_param);
// Our attached model and delegate.
ui::MenuModel* model_;
HMENU menu_;
// True if the contents of menu items in this menu are drawn by the menu host
// window, rather than Windows.
bool owner_draw_;
// An object that collects all of the data associated with an individual menu
// item.
struct ItemData;
std::vector<ItemData*> items_;
// The window that receives notifications from the menu.
class MenuHostWindow;
friend MenuHostWindow;
scoped_ptr<MenuHostWindow> host_window_;
// The HWND this menu is the system menu for, or NULL if the menu is not a
// system menu.
HWND system_menu_for_;
// The index of the first item in the model in the menu.
int first_item_index_;
// The action that took place during the call to RunMenuAt.
MenuAction menu_action_;
// A list of listeners to call when the menu opens.
ObserverList<views::MenuListener> listeners_;
// Keep track of whether the listeners have already been called at least
// once.
bool listeners_called_;
// See comment in MenuMessageHook for details on these.
NativeMenuWin* menu_to_select_;
int position_to_select_;
base::WeakPtrFactory<NativeMenuWin> menu_to_select_factory_;
// If we're a submenu, this is our parent.
NativeMenuWin* parent_;
// If non-null the destructor sets this to true. This is set to non-null while
// the menu is showing. It is used to detect if the menu was deleted while
// running.
bool* destroyed_flag_;
// Ugly: a static pointer to the instance of this class that currently
// has a menu open, because our hook function that receives keyboard
// events doesn't have a mechanism to get a user data pointer.
static NativeMenuWin* open_native_menu_win_;
// Create as window menu.
bool create_as_window_menu_;
DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_NATIVE_MENU_WIN_H_

View file

@ -5,7 +5,6 @@
#include "atom/browser/ui/win/notify_icon.h"
#include "atom/browser/ui/win/notify_icon_host.h"
#include "atom/browser/ui/win/menu_2.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
@ -13,6 +12,7 @@
#include "ui/gfx/icon_util.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/views/controls/menu/menu_runner.h"
namespace atom {
@ -60,8 +60,16 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
if (!SetForegroundWindow(window_))
return;
menu_.reset(new Menu2(menu_model_));
menu_->RunContextMenuAt(cursor_pos);
menu_runner_.reset(new views::MenuRunner(menu_model_));
views::MenuRunner::RunResult result = menu_runner_->RunMenuAt(
NULL,
NULL,
gfx::Rect(cursor_pos, gfx::Size()),
views::MenuItemView::TOPLEFT,
ui::MENU_SOURCE_MOUSE,
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU);
if (result == views::MenuRunner::MENU_DELETED)
LOG(ERROR) << "Menu deleted when running";
}
void NotifyIcon::ResetIcon() {
@ -107,7 +115,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags = NIF_TIP;
wcscpy_s(icon_data.szTip, UTF8ToUTF16(tool_tip).c_str());
wcscpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str());
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result)
LOG(WARNING) << "Unable to set tooltip for status tray icon";

View file

@ -20,9 +20,12 @@ namespace gfx {
class Point;
}
namespace views {
class MenuRunner;
}
namespace atom {
class Menu2;
class NotifyIconHost;
class NotifyIcon : public TrayIcon {
@ -69,7 +72,7 @@ class NotifyIcon : public TrayIcon {
// The context menu.
ui::SimpleMenuModel* menu_model_;
scoped_ptr<atom::Menu2> menu_;
scoped_ptr<views::MenuRunner> menu_runner_;
DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
};

View file

@ -21,17 +21,17 @@ IPC_STRUCT_TRAITS_BEGIN(atom::DraggableRegion)
IPC_STRUCT_TRAITS_END()
IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message,
string16 /* channel */,
ListValue /* arguments */)
base::string16 /* channel */,
base::ListValue /* arguments */)
IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync,
string16 /* channel */,
ListValue /* arguments */,
string16 /* result (in JSON) */)
base::string16 /* channel */,
base::ListValue /* arguments */,
base::string16 /* result (in JSON) */)
IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
string16 /* channel */,
ListValue /* arguments */)
base::string16 /* channel */,
base::ListValue /* arguments */)
// Sent by the renderer when the draggable regions are updated.
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,

View file

@ -8,24 +8,25 @@
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/dictionary.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "atom/common/node_includes.h"
namespace mate {
template<>
struct Converter<ui::Clipboard::Buffer> {
struct Converter<ui::ClipboardType> {
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
ui::Clipboard::Buffer* out) {
ui::ClipboardType* out) {
std::string type;
if (!Converter<std::string>::FromV8(isolate, val, &type))
return false;
if (type == "selection")
*out = ui::Clipboard::BUFFER_SELECTION;
*out = ui::CLIPBOARD_TYPE_SELECTION;
else
*out = ui::Clipboard::BUFFER_STANDARD;
*out = ui::CLIPBOARD_TYPE_COPY_PASTE;
return true;
}
};
@ -34,14 +35,14 @@ struct Converter<ui::Clipboard::Buffer> {
namespace {
bool Has(const std::string& format_string, ui::Clipboard::Buffer buffer) {
bool Has(const std::string& format_string, ui::ClipboardType type) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string));
return clipboard->IsFormatAvailable(format, buffer);
return clipboard->IsFormatAvailable(format, type);
}
std::string Read(const std::string& format_string,
ui::Clipboard::Buffer buffer) {
ui::ClipboardType type) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string));
@ -50,27 +51,25 @@ std::string Read(const std::string& format_string,
return data;
}
string16 ReadText(ui::Clipboard::Buffer buffer) {
string16 data;
ui::Clipboard::GetForCurrentThread()->ReadText(buffer, &data);
base::string16 ReadText(ui::ClipboardType type) {
base::string16 data;
ui::Clipboard::GetForCurrentThread()->ReadText(type, &data);
return data;
}
void WriteText(const std::string text, ui::Clipboard::Buffer buffer) {
ui::Clipboard::ObjectMap object_map;
object_map[ui::Clipboard::CBF_TEXT].push_back(
std::vector<char>(text.begin(), text.end()));
void WriteText(const base::string16& text, ui::ClipboardType type) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
clipboard->WriteObjects(buffer, object_map);
ui::ScopedClipboardWriter writer(clipboard, type);
writer.WriteText(text);
}
void Clear(ui::Clipboard::Buffer buffer) {
ui::Clipboard::GetForCurrentThread()->Clear(buffer);
void Clear(ui::ClipboardType type) {
ui::Clipboard::GetForCurrentThread()->Clear(type);
}
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("_has", &Has);
dict.SetMethod("_read", &Read);
dict.SetMethod("_readText", &ReadText);
@ -80,4 +79,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_common_clipboard, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_clipboard, Initialize)

View file

@ -35,9 +35,10 @@ struct Converter<std::map<std::string, std::string> > {
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
using crash_reporter::CrashReporter;
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("start",
base::Bind(&CrashReporter::Start,
base::Unretained(CrashReporter::GetInstance())));
@ -45,4 +46,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_common_crash_reporter, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_crash_reporter, Initialize)

View file

@ -29,14 +29,14 @@ int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Handle<v8::Object> object) {
mate::Converter<int32_t>::ToV8(isolate, key));
map_[key] = new mate::RefCountedPersistent<v8::Object>(object);
map_[key]->MakeWeak(this, WeakCallback);
map_[key]->SetWeak(this, WeakCallback);
return key;
}
v8::Handle<v8::Value> IDWeakMap::Get(int32_t key) {
v8::Handle<v8::Value> IDWeakMap::Get(v8::Isolate* isolate, int32_t key) {
if (!Has(key)) {
node::ThrowError("Invalid key");
return v8::Undefined();
return v8::Undefined(isolate);
}
return map_[key]->NewHandle();
@ -77,14 +77,11 @@ void IDWeakMap::BuildPrototype(v8::Isolate* isolate,
}
// static
void IDWeakMap::WeakCallback(v8::Isolate* isolate,
v8::Persistent<v8::Object>* value,
IDWeakMap* self) {
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> object = v8::Local<v8::Object>::New(isolate, *value);
int32_t key = object->GetHiddenValue(
mate::StringToV8(isolate, "IDWeakMapKey"))->Int32Value();
self->Remove(key);
void IDWeakMap::WeakCallback(
const v8::WeakCallbackData<v8::Object, IDWeakMap>& data) {
int32_t key = data.GetValue()->GetHiddenValue(
mate::StringToV8(data.GetIsolate(), "IDWeakMapKey"))->Int32Value();
data.GetParameter()->Remove(key);
}
} // namespace api
@ -94,10 +91,10 @@ void IDWeakMap::WeakCallback(v8::Isolate* isolate,
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
using atom::api::IDWeakMap;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<IDWeakMap>(
isolate,
"IDWeakMap",
@ -107,4 +104,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_common_id_weak_map, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize)

View file

@ -29,15 +29,14 @@ class IDWeakMap : public mate::Wrappable {
virtual ~IDWeakMap();
int32_t Add(v8::Isolate* isolate, v8::Handle<v8::Object> object);
v8::Handle<v8::Value> Get(int32_t key);
v8::Handle<v8::Value> Get(v8::Isolate* isolate, int32_t key);
bool Has(int32_t key) const;
std::vector<int32_t> Keys() const;
void Remove(int32_t key);
int GetNextID();
static void WeakCallback(v8::Isolate* isolate,
v8::Persistent<v8::Object>* value,
IDWeakMap* self);
static void WeakCallback(
const v8::WeakCallbackData<v8::Object, IDWeakMap>& data);
int32_t next_id_;

View file

@ -7,34 +7,8 @@
#include "atom/common/node_includes.h"
#if defined(TOOLKIT_GTK)
#include "base/command_line.h"
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "ui/gfx/gtk_util.h"
#endif
namespace mate {
namespace {
gfx::Display AdaptToWindowManager(const gfx::Display& display) {
gfx::Display changed(display);
#if defined(TOOLKIT_GTK)
scoped_ptr<base::Environment> env(base::Environment::Create());
base::nix::DesktopEnvironment de(base::nix::GetDesktopEnvironment(env.get()));
if (de == base::nix::DESKTOP_ENVIRONMENT_UNITY) {
// Unity's 24px global menu bar should not be included in the work area.
gfx::Rect rect(changed.work_area());
rect.set_height(rect.height() - 24);
changed.set_work_area(rect);
}
#endif
return changed;
}
} // namespace
template<>
struct Converter<gfx::Point> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
@ -70,8 +44,7 @@ struct Converter<gfx::Rect> {
template<>
struct Converter<gfx::Display> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
const gfx::Display& val) {
gfx::Display display(AdaptToWindowManager(val));
const gfx::Display& display) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("bounds", display.bounds())
.SetValue("workArea", display.work_area())
@ -86,13 +59,10 @@ struct Converter<gfx::Display> {
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
#if defined(TOOLKIT_GTK)
gfx::GdkInitFromCommandLine(*CommandLine::ForCurrentProcess());
#endif
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("getCursorScreenPoint",
base::Bind(&gfx::Screen::GetCursorScreenPoint,
base::Unretained(screen)));
@ -103,4 +73,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_common_screen, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_screen, Initialize)

View file

@ -13,8 +13,9 @@
namespace {
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder);
dict.SetMethod("openItem", &platform_util::OpenItem);
dict.SetMethod("openExternal", &platform_util::OpenExternal);
@ -24,4 +25,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_common_shell, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_shell, Initialize)

View file

@ -10,8 +10,9 @@
namespace {
v8::Handle<v8::Object> CreateObjectWithName(v8::Handle<v8::String> name) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
v8::Handle<v8::Object> CreateObjectWithName(v8::Isolate* isolate,
v8::Handle<v8::String> name) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
t->SetClassName(name);
return t->GetFunction()->NewInstance();
}
@ -31,18 +32,20 @@ int32_t GetObjectHash(v8::Handle<v8::Object> object) {
return object->GetIdentityHash();
}
void SetDestructor(v8::Handle<v8::Object> object,
void SetDestructor(v8::Isolate* isolate,
v8::Handle<v8::Object> object,
v8::Handle<v8::Function> callback) {
atom::ObjectLifeMonitor::BindTo(object, callback);
atom::ObjectLifeMonitor::BindTo(isolate, object, callback);
}
void TakeHeapSnapshot() {
node::node_isolate->GetHeapProfiler()->TakeHeapSnapshot(
v8::String::New("test"));
void TakeHeapSnapshot(v8::Isolate* isolate) {
isolate->GetHeapProfiler()->TakeHeapSnapshot(
mate::StringToV8(isolate, "test"));
}
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("createObjectWithName", &CreateObjectWithName);
dict.SetMethod("getHiddenValue", &GetHiddenValue);
dict.SetMethod("setHiddenValue", &SetHiddenValue);
@ -53,4 +56,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
} // namespace
NODE_MODULE(atom_common_v8_util, Initialize)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_v8_util, Initialize)

View file

@ -17,9 +17,6 @@
namespace atom {
// Defined in atom_extensions.cc.
node::node_module_struct* GetBuiltinModule(const char *name, bool is_browser);
namespace {
// Async handle to wake up uv loop.
@ -35,8 +32,9 @@ base::Closure g_v8_callback;
struct DummyClass { bool crash; };
// Async handler to call next process.nextTick callbacks.
void UvCallNextTick(uv_async_t* handle, int status) {
node::Environment* env = node::Environment::GetCurrent(node_isolate);
void UvCallNextTick(uv_async_t* handle) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
node::Environment* env = node::Environment::GetCurrent(isolate);
node::Environment::TickInfo* tick_info = env->tick_info();
if (tick_info->in_tick())
@ -53,7 +51,7 @@ void UvCallNextTick(uv_async_t* handle, int status) {
}
// Async handler to execute the stored v8 callback.
void UvOnCallback(uv_async_t* handle, int status) {
void UvOnCallback(uv_async_t* handle) {
g_v8_callback.Run();
}
@ -72,45 +70,6 @@ v8::Handle<v8::Value> DumpStackFrame(v8::Isolate* isolate,
return mate::ConvertToV8(isolate, frame_dict);;
}
v8::Handle<v8::Value> Binding(v8::Handle<v8::String> module) {
v8::String::Utf8Value module_v(module);
node::node_module_struct* modp;
v8::Local<v8::Object> process = v8::Context::GetCurrent()->Global()->
Get(v8::String::New("process"))->ToObject();
DCHECK(!process.IsEmpty());
// is_browser = process.type == 'browser'.
bool is_browser = std::string("browser") == *v8::String::Utf8Value(
process->Get(v8::String::New("type")));
// Cached in process.__atom_binding_cache.
v8::Local<v8::Object> binding_cache;
v8::Local<v8::String> bc_name = v8::String::New("__atomBindingCache");
if (process->Has(bc_name)) {
binding_cache = process->Get(bc_name)->ToObject();
DCHECK(!binding_cache.IsEmpty());
} else {
binding_cache = v8::Object::New();
process->Set(bc_name, binding_cache);
}
if (binding_cache->Has(module))
return binding_cache->Get(module)->ToObject();
if ((modp = GetBuiltinModule(*module_v, is_browser)) != NULL) {
v8::Local<v8::Object> exports = v8::Object::New();
// Internal bindings don't have a "module" object,
// only exports.
modp->register_func(exports, v8::Undefined());
binding_cache->Set(module, exports);
return exports;
}
node::ThrowError("No such module");
return v8::Undefined();
}
void Crash() {
static_cast<DummyClass*>(NULL)->crash = true;
}
@ -119,17 +78,17 @@ void ActivateUVLoop() {
uv_async_send(&g_next_tick_uv_handle);
}
void Log(const string16& message) {
void Log(const base::string16& message) {
logging::LogMessage("CONSOLE", 0, 0).stream() << message;
}
v8::Handle<v8::Value> GetCurrentStackTrace(v8::Isolate* isolate,
int stack_limit) {
v8::Local<v8::StackTrace> stack_trace = v8::StackTrace::CurrentStackTrace(
stack_limit, v8::StackTrace::kDetailed);
isolate, stack_limit, v8::StackTrace::kDetailed);
int frame_count = stack_trace->GetFrameCount();
v8::Local<v8::Array> result = v8::Array::New(frame_count);
v8::Local<v8::Array> result = v8::Array::New(isolate, frame_count);
for (int i = 0; i < frame_count; ++i)
result->Set(i, DumpStackFrame(isolate, stack_trace->GetFrame(i)));
@ -153,10 +112,9 @@ AtomBindings::AtomBindings() {
AtomBindings::~AtomBindings() {
}
void AtomBindings::BindTo(v8::Handle<v8::Object> process) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
void AtomBindings::BindTo(v8::Isolate* isolate,
v8::Handle<v8::Object> process) {
mate::Dictionary dict(isolate, process);
dict.SetMethod("atomBinding", &Binding);
dict.SetMethod("crash", &Crash);
dict.SetMethod("activateUvLoop", &ActivateUVLoop);
dict.SetMethod("log", &Log);

View file

@ -17,9 +17,9 @@ class AtomBindings {
AtomBindings();
virtual ~AtomBindings();
// Add process.atom_binding function, which behaves like process.binding but
// Add process.atomBinding function, which behaves like process.binding but
// load native code from atom-shell instead.
virtual void BindTo(v8::Handle<v8::Object> process);
virtual void BindTo(v8::Isolate* isolate, v8::Handle<v8::Object> process);
private:
DISALLOW_COPY_AND_ASSIGN(AtomBindings);

View file

@ -1,56 +0,0 @@
// Copyright (c) 2013 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 <string.h>
#include <stdio.h>
#include "base/strings/string_util.h"
#include "vendor/node/src/node_version.h"
#include "atom/common/node_includes.h"
namespace atom {
#undef NODE_EXT_LIST_START
#undef NODE_EXT_LIST_ITEM
#undef NODE_EXT_LIST_END
#define NODE_EXT_LIST_START
#define NODE_EXT_LIST_ITEM NODE_MODULE_DECL
#define NODE_EXT_LIST_END
#include "atom/common/api/atom_extensions.h"
#undef NODE_EXT_LIST_START
#undef NODE_EXT_LIST_ITEM
#undef NODE_EXT_LIST_END
#define NODE_EXT_STRING(x) &x ## _module,
#define NODE_EXT_LIST_START node::node_module_struct *node_module_list[] = {
#define NODE_EXT_LIST_ITEM NODE_EXT_STRING
#define NODE_EXT_LIST_END NULL};
#include "atom/common/api/atom_extensions.h" // NOLINT
node::node_module_struct* GetBuiltinModule(const char *name, bool is_browser) {
char common[128];
char spec[128];
node::node_module_struct *cur = NULL;
base::snprintf(common, sizeof(common), "atom_common_%s", name);
base::snprintf(spec, sizeof(spec),
(is_browser ? "atom_browser_%s": "atom_renderer_%s"),
name);
/* TODO: you could look these up in a hash, but there are only
* a few, and once loaded they are cached. */
for (int i = 0; node_module_list[i] != NULL; i++) {
cur = node_module_list[i];
if (strcmp(cur->modname, common) == 0 || strcmp(cur->modname, spec) == 0) {
return cur;
}
}
return NULL;
}
} // namespace atom

View file

@ -1,35 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Multiply-included file, no traditional include guard.
// Used by atom_extensions.cc to declare a list of built-in modules of Atom.
NODE_EXT_LIST_START
// Module names start with `atom_browser_` can only be used by browser process.
NODE_EXT_LIST_ITEM(atom_browser_app)
NODE_EXT_LIST_ITEM(atom_browser_auto_updater)
NODE_EXT_LIST_ITEM(atom_browser_dialog)
NODE_EXT_LIST_ITEM(atom_browser_menu)
NODE_EXT_LIST_ITEM(atom_browser_power_monitor)
NODE_EXT_LIST_ITEM(atom_browser_protocol)
NODE_EXT_LIST_ITEM(atom_browser_tray)
NODE_EXT_LIST_ITEM(atom_browser_window)
// Module names start with `atom_renderer_` can only be used by renderer
// process.
NODE_EXT_LIST_ITEM(atom_renderer_ipc)
NODE_EXT_LIST_ITEM(atom_renderer_web_view)
// Module names start with `atom_common_` can be used by both browser and
// renderer processes.
NODE_EXT_LIST_ITEM(atom_common_clipboard)
NODE_EXT_LIST_ITEM(atom_common_crash_reporter)
NODE_EXT_LIST_ITEM(atom_common_id_weak_map)
NODE_EXT_LIST_ITEM(atom_common_screen)
NODE_EXT_LIST_ITEM(atom_common_shell)
NODE_EXT_LIST_ITEM(atom_common_v8_util)
NODE_EXT_LIST_END

View file

@ -1 +1,6 @@
module.exports = process.atomBinding 'screen'
module.exports =
if process.platform in ['linux', 'win32'] and process.type is 'renderer'
# On Linux we could not access screen in renderer process.
require('remote').require 'screen'
else
process.atomBinding 'screen'

View file

@ -5,34 +5,32 @@
#include "atom/common/api/object_life_monitor.h"
#include "native_mate/compat.h"
namespace atom {
// static
void ObjectLifeMonitor::BindTo(v8::Handle<v8::Object> target,
void ObjectLifeMonitor::BindTo(v8::Isolate* isolate,
v8::Handle<v8::Object> target,
v8::Handle<v8::Value> destructor) {
target->SetHiddenValue(v8::String::New("destructor"), destructor);
target->SetHiddenValue(MATE_STRING_NEW(isolate, "destructor"), destructor);
ObjectLifeMonitor* olm = new ObjectLifeMonitor();
olm->handle_.reset(target);
olm->handle_.MakeWeak(olm, WeakCallback);
olm->handle_.SetWeak(olm, WeakCallback);
}
ObjectLifeMonitor::ObjectLifeMonitor() {
}
// static
void ObjectLifeMonitor::WeakCallback(v8::Isolate* isolate,
v8::Persistent<v8::Object>* value,
ObjectLifeMonitor* self) {
void ObjectLifeMonitor::WeakCallback(
const v8::WeakCallbackData<v8::Object, ObjectLifeMonitor>& data) {
// destructor.call(object, object);
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> obj = self->handle_.NewHandle();
v8::Local<v8::Function>::Cast(obj->GetHiddenValue(
v8::String::New("destructor")))->Call(obj, 0, NULL);
}
delete self;
v8::Local<v8::Object> obj = data.GetValue();
v8::Local<v8::Function>::Cast(obj->GetHiddenValue(
MATE_STRING_NEW(data.GetIsolate(), "destructor")))->Call(obj, 0, NULL);
delete data.GetParameter();
}
} // namespace atom

View file

@ -12,15 +12,15 @@ namespace atom {
class ObjectLifeMonitor {
public:
static void BindTo(v8::Handle<v8::Object> target,
static void BindTo(v8::Isolate* isolate,
v8::Handle<v8::Object> target,
v8::Handle<v8::Value> destructor);
private:
ObjectLifeMonitor();
static void WeakCallback(v8::Isolate* isolate,
v8::Persistent<v8::Object>* value,
ObjectLifeMonitor* self);
static void WeakCallback(
const v8::WeakCallbackData<v8::Object, ObjectLifeMonitor>& data);
mate::ScopedPersistent<v8::Object> handle_;

View file

@ -1,14 +1,14 @@
// 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.
// This file is generated by script/bootstrap.py, you should never modify it
// by hand.
#ifndef ATOM_COMMON_CHROME_VERSION_H_
#define ATOM_COMMON_CHROME_VERSION_H_
#define CHROME_VERSION_STRING "31.0.1650.57"
#define CHROME_VERSION "v" CHROME_VERSION_STRING
#endif // ATOM_COMMON_CHROME_VERSION_H_
// 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.
// This file is generated by script/bootstrap.py, you should never modify it
// by hand.
#ifndef ATOM_COMMON_CHROME_VERSION_H_
#define ATOM_COMMON_CHROME_VERSION_H_
#define CHROME_VERSION_STRING "35.0.1916.153"
#define CHROME_VERSION "v" CHROME_VERSION_STRING
#endif // ATOM_COMMON_CHROME_VERSION_H_

View file

@ -40,14 +40,13 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
skip_system_crash_handler_ = skip_system_crash_handler;
base::FilePath temp_dir;
if (!file_util::GetTempDir(&temp_dir)) {
if (!base::GetTempDir(&temp_dir)) {
LOG(ERROR) << "Cannot get temp directory";
return;
}
string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat,
UTF8ToUTF16(product_name),
NULL);
base::string16 pipe_name = ReplaceStringPlaceholders(
kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
// Wait until the crash service is started.
HANDLE waiting_event =
@ -104,13 +103,13 @@ google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
L"prod", L"Atom-Shell"));
custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
L"ver", UTF8ToWide(version).c_str()));
L"ver", base::UTF8ToWide(version).c_str()));
for (StringMap::const_iterator iter = upload_parameters_.begin();
iter != upload_parameters_.end(); ++iter) {
custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
UTF8ToWide(iter->first).c_str(),
UTF8ToWide(iter->second).c_str()));
base::UTF8ToWide(iter->first).c_str(),
base::UTF8ToWide(iter->second).c_str()));
}
custom_info_.entries = &custom_info_entries_.front();

View file

@ -347,7 +347,7 @@ void CrashService::OnClientDumpRequest(void* context,
CrashMap::const_iterator it = map.find(L"breakpad-dump-location");
if (it != map.end()) {
base::FilePath alternate_dump_location = base::FilePath(it->second);
file_util::CreateDirectoryW(alternate_dump_location);
base::CreateDirectoryW(alternate_dump_location);
alternate_dump_location = alternate_dump_location.Append(
dump_location.BaseName());
base::Move(dump_location, alternate_dump_location);

View file

@ -23,11 +23,11 @@ const wchar_t kStandardLogFile[] = L"operation_log.txt";
bool GetCrashServiceDirectory(const std::wstring& application_name,
base::FilePath* dir) {
base::FilePath temp_dir;
if (!file_util::GetTempDir(&temp_dir))
if (!base::GetTempDir(&temp_dir))
return false;
temp_dir = temp_dir.Append(application_name + L" Crashes");
if (!base::PathExists(temp_dir)) {
if (!file_util::CreateDirectory(temp_dir))
if (!base::CreateDirectory(temp_dir))
return false;
}
*dir = temp_dir;
@ -68,7 +68,7 @@ int Main(const wchar_t* cmd) {
VLOG(1) << "Session start. cmdline is [" << cmd << "]";
// Setting the crash reporter.
string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat,
base::string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat,
application_name,
NULL);
cmd_line.AppendSwitch("no-window");

View file

@ -2,6 +2,12 @@ path = require 'path'
timers = require 'timers'
Module = require 'module'
process.atomBinding = (name) ->
try
process.binding "atom_#{process.type}_#{name}"
catch e
process.binding "atom_common_#{name}" if e.message is 'No such module'
# Add common/api/lib to module search paths.
globalPaths = Module.globalPaths
globalPaths.push path.join(process.resourcesPath, 'atom', 'common', 'api', 'lib')

View file

@ -12,6 +12,7 @@
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/base/layout.h"
namespace mate {

View file

@ -11,17 +11,20 @@
namespace mate {
template<>
struct Converter<string16> {
struct Converter<base::string16> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
const string16& val) {
return v8::String::New(reinterpret_cast<const uint16_t*>(val.data()),
val.size());
const base::string16& val) {
return MATE_STRING_NEW_FROM_UTF16(
isolate, reinterpret_cast<const uint16_t*>(val.data()), val.size());
}
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
string16* out) {
base::string16* out) {
if (!val->IsString())
return false;
v8::String::Value s(val);
out->assign(reinterpret_cast<const char16*>(*s), s.length());
out->assign(reinterpret_cast<const base::char16*>(*s), s.length());
return true;
}
};

Some files were not shown because too many files have changed in this diff Show more