diff --git a/atom.gyp b/atom.gyp index fff917131448..90f7286af250 100644 --- a/atom.gyp +++ b/atom.gyp @@ -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', diff --git a/atom/app/atom_library_main.cc b/atom/app/atom_library_main.cc index cf2b8cf1ee1b..734f9790c1cd 100644 --- a/atom/app/atom_library_main.cc +++ b/atom/app/atom_library_main.cc @@ -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 diff --git a/atom/app/atom_main.cc b/atom/app/atom_main.cc index d63d39bfe008..35ed4d4a5bed 100644 --- a/atom/app/atom_main.cc +++ b/atom/app/atom_main.cc @@ -16,10 +16,12 @@ #include #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(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) diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index bbee2527ff4c..e77814b06c48 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -6,14 +6,13 @@ #include +#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(); diff --git a/atom/app/atom_main_delegate.h b/atom/app/atom_main_delegate.h index a8e3df9b0c95..72bc0f745af8 100644 --- a/atom/app/atom_main_delegate.h +++ b/atom/app/atom_main_delegate.h @@ -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 browser_client_; scoped_ptr renderer_client_; diff --git a/atom/app/atom_main_delegate_mac.mm b/atom/app/atom_main_delegate_mac.mm index e8a45585ee85..0e3e50203ad5 100644 --- a/atom/app/atom_main_delegate_mac.mm +++ b/atom/app/atom_main_delegate_mac.mm @@ -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")); diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 8966d3ea1815..6ea5464d6f32 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -109,8 +109,9 @@ int DockBounce(const std::string& type) { } #endif -void Initialize(v8::Handle exports) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_browser_app, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_app, Initialize) diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 74995a9860c5..b76b1ef76290 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -85,12 +85,13 @@ mate::Handle AutoUpdater::Create(v8::Isolate* isolate) { namespace { -void Initialize(v8::Handle exports) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 3417742eb4ac..ffc016033936 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -27,7 +27,7 @@ void ShowMessageBox(int type, mate::Arguments* args) { v8::Handle peek = args->PeekNext(); atom::MessageBoxCallback callback; - if (mate::Converter::FromV8(node_isolate, + if (mate::Converter::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 peek = args->PeekNext(); file_dialog::OpenDialogCallback callback; - if (mate::Converter::FromV8(node_isolate, + if (mate::Converter::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 peek = args->PeekNext(); file_dialog::SaveDialogCallback callback; - if (mate::Converter::FromV8(node_isolate, + if (mate::Converter::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 exports) { - mate::Dictionary dict(v8::Isolate::GetCurrent(), exports); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_browser_dialog, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_dialog, Initialize) diff --git a/atom/browser/api/atom_api_menu.cc b/atom/browser/api/atom_api_menu.cc index a76d77b0f3e4..0a4847668147 100644 --- a/atom/browser/api/atom_api_menu.cc +++ b/atom/browser/api/atom_api_menu.cc @@ -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 CallDelegate(v8::Handle default_value, +v8::Handle CallDelegate(v8::Isolate* isolate, + v8::Handle default_value, v8::Handle menu, const char* method, int command_id) { - v8::Locker locker(node_isolate); - v8::HandleScope handle_scope(node_isolate); - - v8::Handle delegate = menu->Get(v8::String::New("delegate")); + v8::Handle delegate = menu->Get( + MATE_STRING_NEW(isolate, "delegate")); if (!delegate->IsObject()) return default_value; v8::Handle function = v8::Handle::Cast( - delegate->ToObject()->Get(v8::String::New(method))); + delegate->ToObject()->Get(MATE_STRING_NEW(isolate, method))); if (!function->IsFunction()) return default_value; - v8::Handle argv = v8::Integer::New(command_id); - - return handle_scope.Close( - function->Call(v8::Context::GetCurrent()->Global(), 1, &argv)); + v8::Handle 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(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(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(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(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(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(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 shortcut = CallDelegate(v8::Undefined(), - GetWrapper(node_isolate), + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + v8::Handle 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(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(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 result = CallDelegate( - v8::False(), - const_cast(this)->GetWrapper(node_isolate), + isolate, + MATE_FALSE(isolate), + const_cast(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 result = CallDelegate( - v8::False(), - const_cast(this)->GetWrapper(node_isolate), + isolate, + MATE_FALSE(isolate), + const_cast(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 exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle context, void* priv) { using atom::api::Menu; + v8::Isolate* isolate = context->GetIsolate(); v8::Local constructor = mate::CreateConstructor( - 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>(constructor)); #if defined(OS_MACOSX) dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu); @@ -263,4 +278,4 @@ void Initialize(v8::Handle exports) { } // namespace -NODE_MODULE(atom_browser_menu, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_menu, Initialize) diff --git a/atom/browser/api/atom_api_menu.h b/atom/browser/api/atom_api_menu.h index 2a212d0145a1..d8c01e84db20 100644 --- a/atom/browser/api/atom_api_menu.h +++ b/atom/browser/api/atom_api_menu.h @@ -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 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); }; diff --git a/atom/browser/api/atom_api_menu_gtk.cc b/atom/browser/api/atom_api_menu_gtk.cc deleted file mode 100644 index acaca4b2f8e8..000000000000 --- a/atom/browser/api/atom_api_menu_gtk.cc +++ /dev/null @@ -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(window->window())->SetMenu(model_.get()); -} - -// static -mate::Wrappable* Menu::Create() { - return new MenuGtk(); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_menu_gtk.h b/atom/browser/api/atom_api_menu_gtk.h deleted file mode 100644 index eb6c94c9932b..000000000000 --- a/atom/browser/api/atom_api_menu_gtk.h +++ /dev/null @@ -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_ diff --git a/atom/browser/api/atom_api_menu_views.cc b/atom/browser/api/atom_api_menu_views.cc new file mode 100644 index 000000000000..a8d50eeaa8f5 --- /dev/null +++ b/atom/browser/api/atom_api_menu_views.cc @@ -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(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 diff --git a/atom/browser/api/atom_api_menu_views.h b/atom/browser/api/atom_api_menu_views.h new file mode 100644 index 000000000000..dd62df60fe4c --- /dev/null +++ b/atom/browser/api/atom_api_menu_views.h @@ -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_ diff --git a/atom/browser/api/atom_api_menu_win.cc b/atom/browser/api/atom_api_menu_win.cc deleted file mode 100644 index 6bf515c7bdd5..000000000000 --- a/atom/browser/api/atom_api_menu_win.cc +++ /dev/null @@ -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(top->parent_); - if (top->menu_) - top->menu_->UpdateStates(); -} - -void MenuWin::AttachToWindow(Window* window) { - NativeWindowWin* nw = static_cast(window->window()); - nw->SetMenu(model_.get()); - menu_ = nw->menu(); -} - -// static -mate::Wrappable* Menu::Create() { - return new MenuWin(); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_menu_win.h b/atom/browser/api/atom_api_menu_win.h deleted file mode 100644 index 1dd66c488ee8..000000000000 --- a/atom/browser/api/atom_api_menu_win.h +++ /dev/null @@ -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 popup_menu_; - - DISALLOW_COPY_AND_ASSIGN(MenuWin); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_ diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc index 88e49db492f0..ecfb3fdfc334 100644 --- a/atom/browser/api/atom_api_power_monitor.cc +++ b/atom/browser/api/atom_api_power_monitor.cc @@ -49,13 +49,14 @@ mate::Handle PowerMonitor::Create(v8::Isolate* isolate) { namespace { -void Initialize(v8::Handle exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 power_monitor = PowerMonitor::Create(isolate); mate::Dictionary dict(isolate, exports); dict.Set("powerMonitor", power_monitor); @@ -63,4 +64,4 @@ void Initialize(v8::Handle exports) { } // namespace -NODE_MODULE(atom_browser_power_monitor, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_monitor, Initialize) diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index ccc87db2d5c5..29ec8507c542 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -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 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::Create(v8::Isolate* isolate) { namespace { -void Initialize(v8::Handle exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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) diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index 49d954024437..86e6cb299532 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -69,9 +69,10 @@ void Tray::BuildPrototype(v8::Isolate* isolate, namespace { -void Initialize(v8::Handle exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle context, void* priv) { using atom::api::Tray; - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = context->GetIsolate(); v8::Handle constructor = mate::CreateConstructor( isolate, "Tray", base::Bind(&Tray::New)); mate::Dictionary dict(isolate, exports); @@ -80,4 +81,4 @@ void Initialize(v8::Handle exports) { } // namespace -NODE_MODULE(atom_browser_tray, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_tray, Initialize) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 84e695ffddec..14fc69c31753 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -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 diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 1c42f5256d1e..36c91434d5ee 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -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); diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 02961f95f669..c6b28af5585c 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -46,10 +46,11 @@ namespace api { namespace { void OnCapturePageDone( + v8::Isolate* isolate, const base::Callback)>& callback, const std::vector& data) { - v8::Locker locker(node_isolate); - v8::HandleScope handle_scope(node_isolate); + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); v8::Local buffer = node::Buffer::New( reinterpret_cast(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 exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle context, void* priv) { using atom::api::Window; + v8::Isolate* isolate = context->GetIsolate(); v8::Local constructor = mate::CreateConstructor( - 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>(constructor)); } } // namespace -NODE_MODULE(atom_browser_window, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_window, Initialize) diff --git a/atom/browser/api/event.cc b/atom/browser/api/event.cc index 4bf5b920c5b6..579fa3a41dcf 100644 --- a/atom/browser/api/event.cc +++ b/atom/browser/api/event.cc @@ -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; diff --git a/atom/browser/api/event.h b/atom/browser/api/event.h index 3090586c3615..b1713a4e68c9 100644 --- a/atom/browser/api/event.h +++ b/atom/browser/api/event.h @@ -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_; } diff --git a/atom/browser/api/event_emitter.cc b/atom/browser/api/event_emitter.cc index b3957dd1cd33..071bd8e1a97b 100644 --- a/atom/browser/api/event_emitter.cc +++ b/atom/browser/api/event_emitter.cc @@ -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 context = v8::Context::GetCurrent(); + v8::Handle context = isolate->GetCurrentContext(); scoped_ptr converter(new atom::V8ValueConverter); - mate::Handle event = mate::Event::Create(node_isolate); + mate::Handle event = mate::Event::Create(isolate); if (sender && message) event->SetSenderAndMessage(sender, message); // v8_args = [name, event, args...]; std::vector> 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(); } diff --git a/atom/browser/api/lib/menu-item.coffee b/atom/browser/api/lib/menu-item.coffee index bbac726acce6..30560e4b7ebd 100644 --- a/atom/browser/api/lib/menu-item.coffee +++ b/atom/browser/api/lib/menu-item.coffee @@ -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, diff --git a/atom/browser/api/lib/menu.coffee b/atom/browser/api/lib/menu.coffee index 8a4f15380e35..722c56eb609a 100644 --- a/atom/browser/api/lib/menu.coffee +++ b/atom/browser/api/lib/menu.coffee @@ -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() diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 74b38d6b3090..b62bc37b4b4e 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -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(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; } diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index 10ae1b0c7dc0..b4b4a08b55ed 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -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: diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index c55b589c5328..c141b265fd75 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -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::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 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::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 diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index de95a0f2e9ea..d9b94e8d8310 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -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_; scoped_ptr node_bindings_; + // The V8 environment of browser process. + v8::Isolate* isolate_; + v8::Locker locker_; + v8::HandleScope handle_scope_; + v8::UniquePersistent context_; + v8::Context::Scope context_scope_; + static AtomBrowserMainParts* self_; DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts); diff --git a/atom/browser/atom_javascript_dialog_manager.cc b/atom/browser/atom_javascript_dialog_manager.cc index 9d83cddb2927..b65e4eabb6dd 100644 --- a/atom/browser/atom_javascript_dialog_manager.cc +++ b/atom/browser/atom_javascript_dialog_manager.cc @@ -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); } diff --git a/atom/browser/atom_javascript_dialog_manager.h b/atom/browser/atom_javascript_dialog_manager.h index fe65f2c9d967..b71dccc332f7 100644 --- a/atom/browser/atom_javascript_dialog_manager.h +++ b/atom/browser/atom_javascript_dialog_manager.h @@ -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( diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index cf4b9eac5686..8f2fe8002e24 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -44,7 +44,7 @@ std::string Browser::GetExecutableFileVersion() const { if (PathService::Get(base::FILE_EXE, &path)) { scoped_ptr 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 version_info( FileVersionInfo::CreateFileVersionInfo(path)); - return UTF16ToUTF8(version_info->product_name()); + return base::UTF16ToUTF8(version_info->product_name()); } return "Atom-Shell"; diff --git a/atom/browser/default_app/index.html b/atom/browser/default_app/index.html index 2b85bd7b37d9..df6001242836 100644 --- a/atom/browser/default_app/index.html +++ b/atom/browser/default_app/index.html @@ -78,7 +78,7 @@ }; -

Welcome to Atom Shell

+

Welcome to Atom Shell

To run your app with atom-shell, execute the following command under your diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 4f89038366a7..f99f783f1605 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -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 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 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 diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index f13b9d866e11..fdb7fa676f8a 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -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 web_preferences_; + mate::ScopedPersistent web_preferences_; // Page's default zoom factor. double zoom_factor_; diff --git a/atom/browser/native_window_gtk.cc b/atom/browser/native_window_gtk.cc deleted file mode 100644 index 3b1f6f8d3484..000000000000 --- a/atom/browser/native_window_gtk.cc +++ /dev/null @@ -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 -#include - -#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 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& 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::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(event.os_event); - ui::Accelerator accelerator = ui::AcceleratorForGdkKeyCodeAndModifier( - os_event->keyval, static_cast(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(event->x), - static_cast(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(event->x_root - win_x), - static_cast(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(event->x_root), - static_cast(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 diff --git a/atom/browser/native_window_gtk.h b/atom/browser/native_window_gtk.h deleted file mode 100644 index 63cbc7e35351..000000000000 --- a/atom/browser/native_window_gtk.h +++ /dev/null @@ -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 - -#include -#include - -#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& 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 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 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_ diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 154319845f13..794f4a8af13c 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -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 layer([[CALayer alloc] init]); + [layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; + [view setLayer:layer]; + [view setWantsLayer:YES]; + [view setFrame:[[window_ contentView] bounds]]; [[window_ contentView] addSubview:view]; } else { diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc new file mode 100644 index 000000000000..73b691edb134 --- /dev/null +++ b/atom/browser/native_window_views.cc @@ -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 +#endif + +#include +#include + +#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(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 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& 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::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( + 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 diff --git a/atom/browser/native_window_win.h b/atom/browser/native_window_views.h similarity index 58% rename from atom/browser/native_window_win.h rename to atom/browser/native_window_views.h index d38d28bdafc7..57a92534b108 100644 --- a/atom/browser/native_window_win.h +++ b/atom/browser/native_window_views.h @@ -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 #include #include -#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( - 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& 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 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 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 menu_; +#if defined(USE_X11) + scoped_ptr global_menu_bar_; +#endif + + // Handles unhandled keyboard messages coming back from the renderer process. + scoped_ptr keyboard_event_handler_; // Map from accelerator to menu item's command id. accelerator_util::AcceleratorTable accelerator_table_; - scoped_ptr 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 draggable_region_; + + DISALLOW_COPY_AND_ASSIGN(NativeWindowViews); }; } // namespace atom -#endif // ATOM_BROWSER_NATIVE_WINDOW_WIN_H_ +#endif // ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_ diff --git a/atom/browser/native_window_win.cc b/atom/browser/native_window_win.cc deleted file mode 100644 index 61464c9af9c3..000000000000 --- a/atom/browser/native_window_win.cc +++ /dev/null @@ -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 - -#include -#include - -#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(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(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 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& 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::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(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 diff --git a/atom/browser/net/atom_url_request_context_getter.cc b/atom/browser/net/atom_url_request_context_getter.cc index d5be00b983b8..346a05da77bf 100644 --- a/atom/browser/net/atom_url_request_context_getter.cc +++ b/atom/browser/net/atom_url_request_context_getter.cc @@ -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 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_); } diff --git a/atom/browser/ui/accelerator_util_gtk.cc b/atom/browser/ui/accelerator_util_gtk.cc deleted file mode 100644 index 259d4aef49b3..000000000000 --- a/atom/browser/ui/accelerator_util_gtk.cc +++ /dev/null @@ -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 platform_accelerator( - new ui::PlatformAcceleratorGtk( - GetGdkKeyCodeForAccelerator(*accelerator), - GetGdkModifierForAccelerator(*accelerator))); - accelerator->set_platform_accelerator(platform_accelerator.Pass()); -} - -} // namespace accelerator_util diff --git a/atom/browser/ui/accelerator_util_win.cc b/atom/browser/ui/accelerator_util_views.cc similarity index 100% rename from atom/browser/ui/accelerator_util_win.cc rename to atom/browser/ui/accelerator_util_views.cc diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm index 249eecc8bc27..05e4b4cc41d7 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ b/atom/browser/ui/cocoa/atom_menu_controller.mm @@ -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 item( [[NSMenuItem alloc] initWithTitle:label diff --git a/atom/browser/ui/file_dialog_gtk.cc b/atom/browser/ui/file_dialog_gtk.cc index 618ec31b63df..21cd14166500 100644 --- a/atom/browser/ui/file_dialog_gtk.cc +++ b/atom/browser/ui/file_dialog_gtk.cc @@ -4,16 +4,47 @@ #include "atom/browser/ui/file_dialog.h" +#include +#include +#include + +// 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()) { diff --git a/atom/browser/ui/file_dialog_win.cc b/atom/browser/ui/file_dialog_win.cc index fa1c7650232f..e0436d96c07a 100644 --- a/atom/browser/ui/file_dialog_win.cc +++ b/atom/browser/ui/file_dialog_win.cc @@ -9,7 +9,7 @@ #include #include -#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( + parent_window)->GetAcceleratedWidget() : + NULL; return dialog_->DoModal(window) == IDOK; } diff --git a/atom/browser/ui/gtk/app_indicator_icon.cc b/atom/browser/ui/gtk/app_indicator_icon.cc deleted file mode 100644 index 1c88b29065b8..000000000000 --- a/atom/browser/ui/gtk/app_indicator_icon.cc +++ /dev/null @@ -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 -#include - -#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( - dlsym(indicator_lib, "app_indicator_new")); - - app_indicator_new_with_path = - reinterpret_cast( - dlsym(indicator_lib, "app_indicator_new_with_path")); - - app_indicator_set_status = reinterpret_cast( - dlsym(indicator_lib, "app_indicator_set_status")); - - app_indicator_set_attention_icon_full = - reinterpret_cast( - dlsym(indicator_lib, "app_indicator_set_attention_icon_full")); - - app_indicator_set_menu = reinterpret_cast( - dlsym(indicator_lib, "app_indicator_set_menu")); - - app_indicator_set_icon_full = - reinterpret_cast( - dlsym(indicator_lib, "app_indicator_set_icon_full")); - - app_indicator_set_icon_theme_path = - reinterpret_cast( - 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 image(image_ptr); - - scoped_refptr 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(png_data->front()), - png_data->size()); - - if (bytes_written != static_cast(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 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 diff --git a/atom/browser/ui/gtk/app_indicator_icon.h b/atom/browser/ui/gtk/app_indicator_icon.h deleted file mode 100644 index 1799dc1b38ed..000000000000 --- a/atom/browser/ui/gtk/app_indicator_icon.h +++ /dev/null @@ -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 - -#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 menu_; - - std::string id_; - base::FilePath icon_file_path_; - int icon_change_count_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(AppIndicatorIcon); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_ diff --git a/atom/browser/ui/gtk/status_icon.cc b/atom/browser/ui/gtk/status_icon.cc deleted file mode 100644 index 433e4af13e5c..000000000000 --- a/atom/browser/ui/gtk/status_icon.cc +++ /dev/null @@ -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 diff --git a/atom/browser/ui/gtk/status_icon.h b/atom/browser/ui/gtk/status_icon.h deleted file mode 100644 index 9c8aa1f5abf2..000000000000 --- a/atom/browser/ui/gtk/status_icon.h +++ /dev/null @@ -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 - -#include - -#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 menu_; - - DISALLOW_COPY_AND_ASSIGN(StatusIcon); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_GTK_STATUS_ICON_H_ diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc deleted file mode 100644 index 4915d099588f..000000000000 --- a/atom/browser/ui/message_box_gtk.cc +++ /dev/null @@ -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& 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(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 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& 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& 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 diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_views.cc similarity index 69% rename from atom/browser/ui/message_box_win.cc rename to atom/browser/ui/message_box_views.cc index 66b2eb6792a9..de736216df7c 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_views.cc @@ -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 widget_; views::MessageBoxView* message_box_view_; - scoped_ptr dialog_scope_; std::vector buttons_; + + base::RunLoop* run_loop_; + scoped_ptr 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 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(); } diff --git a/atom/browser/ui/tray_icon_gtk.cc b/atom/browser/ui/tray_icon_gtk.cc index fa9e82859ccb..2492cb14d607 100644 --- a/atom/browser/ui/tray_icon_gtk.cc +++ b/atom/browser/ui/tray_icon_gtk.cc @@ -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 diff --git a/atom/browser/ui/tray_icon_gtk.h b/atom/browser/ui/tray_icon_gtk.h new file mode 100644 index 000000000000..61687b3afdab --- /dev/null +++ b/atom/browser/ui/tray_icon_gtk.h @@ -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 + +#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 icon_; + + DISALLOW_COPY_AND_ASSIGN(TrayIconGtk); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_TRAY_ICON_GTK_H_ diff --git a/atom/browser/ui/views/frameless_view.cc b/atom/browser/ui/views/frameless_view.cc new file mode 100644 index 000000000000..a7c5f3c1765e --- /dev/null +++ b/atom/browser/ui/views/frameless_view.cc @@ -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 diff --git a/atom/browser/ui/views/frameless_view.h b/atom/browser/ui/views/frameless_view.h new file mode 100644 index 000000000000..93b86f73774a --- /dev/null +++ b/atom/browser/ui/views/frameless_view.h @@ -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_ diff --git a/atom/browser/ui/views/global_menu_bar_x11.cc b/atom/browser/ui/views/global_menu_bar_x11.cc new file mode 100644 index 000000000000..fd6f80cdec28 --- /dev/null +++ b/atom/browser/ui/views/global_menu_bar_x11.cc @@ -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 + +// This conflicts with mate::Converter, +#undef True +#undef False +// and V8. +#undef None + +#include +#include + +#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( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_new")); + menuitem_new_with_id = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id")); + menuitem_get_id = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id")); + menuitem_get_children = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children")); + menuitem_take_children = + reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_take_children")); + menuitem_child_append = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append")); + menuitem_property_set = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set")); + menuitem_property_set_variant = + reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant")); + menuitem_property_set_bool = + reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool")); + menuitem_property_set_int = + reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int")); + + // DbusmenuServer methods. + server_new = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_server_new")); + server_set_root = reinterpret_cast( + dlsym(dbusmenu_lib, "dbusmenu_server_set_root")); +} + +ui::MenuModel* ModelForMenuItem(DbusmenuMenuitem* item) { + return reinterpret_cast( + 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(g_object_unref), NULL); + g_list_free(children); + + // Build children. + BuildMenuFromModel(model->GetSubmenuModelAt(id), item); +} + +} // namespace atom diff --git a/atom/browser/ui/views/global_menu_bar_x11.h b/atom/browser/ui/views/global_menu_bar_x11.h new file mode 100644 index 000000000000..09d2eb6d1342 --- /dev/null +++ b/atom/browser/ui/views/global_menu_bar_x11.h @@ -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 + +#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_ diff --git a/atom/browser/ui/views/linux_frame_view.cc b/atom/browser/ui/views/linux_frame_view.cc new file mode 100644 index 000000000000..c68a2e933246 --- /dev/null +++ b/atom/browser/ui/views/linux_frame_view.cc @@ -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 + +#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 diff --git a/atom/browser/ui/views/linux_frame_view.h b/atom/browser/ui/views/linux_frame_view.h new file mode 100644 index 000000000000..2f6793fe7a40 --- /dev/null +++ b/atom/browser/ui/views/linux_frame_view.h @@ -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 frame_background_; + + DISALLOW_COPY_AND_ASSIGN(LinuxFrameView); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_ diff --git a/atom/browser/ui/views/menu_bar.cc b/atom/browser/ui/views/menu_bar.cc new file mode 100644 index 000000000000..ef9277181de3 --- /dev/null +++ b/atom/browser/ui/views/menu_bar.cc @@ -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(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(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 diff --git a/atom/browser/ui/views/menu_bar.h b/atom/browser/ui/views/menu_bar.h new file mode 100644 index 000000000000..dbc3520e2abd --- /dev/null +++ b/atom/browser/ui/views/menu_bar.h @@ -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 menu_delegate_; + + DISALLOW_COPY_AND_ASSIGN(MenuBar); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_ diff --git a/atom/browser/ui/views/menu_delegate.cc b/atom/browser/ui/views/menu_delegate.cc new file mode 100644 index 000000000000..88bba2808dfc --- /dev/null +++ b/atom/browser/ui/views/menu_delegate.cc @@ -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 diff --git a/atom/browser/ui/views/menu_delegate.h b/atom/browser/ui/views/menu_delegate.h new file mode 100644 index 000000000000..1d409e171035 --- /dev/null +++ b/atom/browser/ui/views/menu_delegate.h @@ -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 + +#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 items_; + // Cached menu delegates for each menu item, managed by us. + std::vector delegates_; + + DISALLOW_COPY_AND_ASSIGN(MenuDelegate); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_ diff --git a/atom/browser/ui/views/menu_layout.cc b/atom/browser/ui/views/menu_layout.cc new file mode 100644 index 000000000000..cb92e98f4ebd --- /dev/null +++ b/atom/browser/ui/views/menu_layout.cc @@ -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 diff --git a/atom/browser/ui/views/menu_layout.h b/atom/browser/ui/views/menu_layout.h new file mode 100644 index 000000000000..1b3d78e28d96 --- /dev/null +++ b/atom/browser/ui/views/menu_layout.h @@ -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_ diff --git a/atom/browser/ui/views/win_frame_view.cc b/atom/browser/ui/views/win_frame_view.cc new file mode 100644 index 000000000000..4a7e90ce5bf3 --- /dev/null +++ b/atom/browser/ui/views/win_frame_view.cc @@ -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 diff --git a/atom/browser/ui/views/win_frame_view.h b/atom/browser/ui/views/win_frame_view.h new file mode 100644 index 000000000000..6cc65c937026 --- /dev/null +++ b/atom/browser/ui/views/win_frame_view.h @@ -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_ diff --git a/atom/browser/ui/win/menu_2.cc b/atom/browser/ui/win/menu_2.cc deleted file mode 100644 index 81c40baddfda..000000000000 --- a/atom/browser/ui/win/menu_2.cc +++ /dev/null @@ -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 diff --git a/atom/browser/ui/win/menu_2.h b/atom/browser/ui/win/menu_2.h deleted file mode 100644 index f5691d7279a4..000000000000 --- a/atom/browser/ui/win/menu_2.h +++ /dev/null @@ -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 wrapper_; - - DISALLOW_COPY_AND_ASSIGN(Menu2); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_WIN_MENU_2_H_ diff --git a/atom/browser/ui/win/native_menu_win.cc b/atom/browser/ui/win/native_menu_win.cc deleted file mode 100644 index f82a0f04043d..000000000000 --- a/atom/browser/ui/win/native_menu_win.cc +++ /dev/null @@ -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 - -#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 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(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, - CS_DBLCLKS, - 0, - 0, - NULL, - reinterpret_cast(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(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(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(label.data()), - static_cast(label.size()), &rect, format | DT_LEFT, NULL); - if (!accel.empty()) - DrawTextEx(dc, const_cast(accel.data()), - static_cast(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(l_param)); - *l_result = 0; - return true; - case WM_MENUSELECT: - OnMenuSelect(LOWORD(w_param), reinterpret_cast(l_param)); - *l_result = 0; - return true; - case WM_MEASUREITEM: - OnMeasureItem(w_param, reinterpret_cast(l_param)); - *l_result = 0; - return true; - case WM_DRAWITEM: - OnDrawItem(w_param, reinterpret_cast(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(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::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(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(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(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(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 diff --git a/atom/browser/ui/win/native_menu_win.h b/atom/browser/ui/win/native_menu_win.h deleted file mode 100644 index 121cb2ddb2d1..000000000000 --- a/atom/browser/ui/win/native_menu_win.h +++ /dev/null @@ -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 - -#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 items_; - - // The window that receives notifications from the menu. - class MenuHostWindow; - friend MenuHostWindow; - scoped_ptr 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 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 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_ diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc index fddee1cea406..c94ce3183b33 100644 --- a/atom/browser/ui/win/notify_icon.cc +++ b/atom/browser/ui/win/notify_icon.cc @@ -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"; diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h index 51e854b802e2..b7cdbe229e1a 100644 --- a/atom/browser/ui/win/notify_icon.h +++ b/atom/browser/ui/win/notify_icon.h @@ -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 menu_; + scoped_ptr menu_runner_; DISALLOW_COPY_AND_ASSIGN(NotifyIcon); }; diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index 641e99157529..045bceb719af 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -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, diff --git a/atom/common/api/atom_api_clipboard.cc b/atom/common/api/atom_api_clipboard.cc index 4275dabf412f..e5cc30905b51 100644 --- a/atom/common/api/atom_api_clipboard.cc +++ b/atom/common/api/atom_api_clipboard.cc @@ -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 { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, - ui::Clipboard::Buffer* out) { + ui::ClipboardType* out) { std::string type; if (!Converter::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 { 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(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 exports) { - mate::Dictionary dict(v8::Isolate::GetCurrent(), exports); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_common_clipboard, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_clipboard, Initialize) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc index ddf869a217de..06ce7fadbab6 100644 --- a/atom/common/api/atom_api_crash_reporter.cc +++ b/atom/common/api/atom_api_crash_reporter.cc @@ -35,9 +35,10 @@ struct Converter > { namespace { -void Initialize(v8::Handle exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_common_crash_reporter, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_crash_reporter, Initialize) diff --git a/atom/common/api/atom_api_id_weak_map.cc b/atom/common/api/atom_api_id_weak_map.cc index 8b451ab51e07..652e8f75ccbc 100644 --- a/atom/common/api/atom_api_id_weak_map.cc +++ b/atom/common/api/atom_api_id_weak_map.cc @@ -29,14 +29,14 @@ int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Handle object) { mate::Converter::ToV8(isolate, key)); map_[key] = new mate::RefCountedPersistent(object); - map_[key]->MakeWeak(this, WeakCallback); + map_[key]->SetWeak(this, WeakCallback); return key; } -v8::Handle IDWeakMap::Get(int32_t key) { +v8::Handle 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* value, - IDWeakMap* self) { - v8::HandleScope handle_scope(isolate); - v8::Local object = v8::Local::New(isolate, *value); - int32_t key = object->GetHiddenValue( - mate::StringToV8(isolate, "IDWeakMapKey"))->Int32Value(); - self->Remove(key); +void IDWeakMap::WeakCallback( + const v8::WeakCallbackData& 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 exports) { +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle context, void* priv) { using atom::api::IDWeakMap; - - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = context->GetIsolate(); v8::Local constructor = mate::CreateConstructor( isolate, "IDWeakMap", @@ -107,4 +104,4 @@ void Initialize(v8::Handle exports) { } // namespace -NODE_MODULE(atom_common_id_weak_map, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize) diff --git a/atom/common/api/atom_api_id_weak_map.h b/atom/common/api/atom_api_id_weak_map.h index 092d3f90985c..acadebf2e199 100644 --- a/atom/common/api/atom_api_id_weak_map.h +++ b/atom/common/api/atom_api_id_weak_map.h @@ -29,15 +29,14 @@ class IDWeakMap : public mate::Wrappable { virtual ~IDWeakMap(); int32_t Add(v8::Isolate* isolate, v8::Handle object); - v8::Handle Get(int32_t key); + v8::Handle Get(v8::Isolate* isolate, int32_t key); bool Has(int32_t key) const; std::vector Keys() const; void Remove(int32_t key); int GetNextID(); - static void WeakCallback(v8::Isolate* isolate, - v8::Persistent* value, - IDWeakMap* self); + static void WeakCallback( + const v8::WeakCallbackData& data); int32_t next_id_; diff --git a/atom/common/api/atom_api_screen.cc b/atom/common/api/atom_api_screen.cc index 3d71040d9a06..2a10390a63b7 100644 --- a/atom/common/api/atom_api_screen.cc +++ b/atom/common/api/atom_api_screen.cc @@ -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 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 { static v8::Handle ToV8(v8::Isolate* isolate, @@ -70,8 +44,7 @@ struct Converter { template<> struct Converter { static v8::Handle 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 { namespace { -void Initialize(v8::Handle exports) { -#if defined(TOOLKIT_GTK) - gfx::GdkInitFromCommandLine(*CommandLine::ForCurrentProcess()); -#endif - +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_common_screen, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_screen, Initialize) diff --git a/atom/common/api/atom_api_shell.cc b/atom/common/api/atom_api_shell.cc index 39ff09a43a7b..876e448240e4 100644 --- a/atom/common/api/atom_api_shell.cc +++ b/atom/common/api/atom_api_shell.cc @@ -13,8 +13,9 @@ namespace { -void Initialize(v8::Handle exports) { - mate::Dictionary dict(v8::Isolate::GetCurrent(), exports); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_common_shell, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_shell, Initialize) diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index d68e7f8d2fee..4332d029c22c 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -10,8 +10,9 @@ namespace { -v8::Handle CreateObjectWithName(v8::Handle name) { - v8::Local t = v8::FunctionTemplate::New(); +v8::Handle CreateObjectWithName(v8::Isolate* isolate, + v8::Handle name) { + v8::Local t = v8::FunctionTemplate::New(isolate); t->SetClassName(name); return t->GetFunction()->NewInstance(); } @@ -31,18 +32,20 @@ int32_t GetObjectHash(v8::Handle object) { return object->GetIdentityHash(); } -void SetDestructor(v8::Handle object, +void SetDestructor(v8::Isolate* isolate, + v8::Handle object, v8::Handle 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 exports) { - mate::Dictionary dict(v8::Isolate::GetCurrent(), exports); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle 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 exports) { } // namespace -NODE_MODULE(atom_common_v8_util, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_v8_util, Initialize) diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index 29ec5eca724f..13191b461830 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -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 DumpStackFrame(v8::Isolate* isolate, return mate::ConvertToV8(isolate, frame_dict);; } -v8::Handle Binding(v8::Handle module) { - v8::String::Utf8Value module_v(module); - node::node_module_struct* modp; - - v8::Local 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 binding_cache; - v8::Local 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 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(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 GetCurrentStackTrace(v8::Isolate* isolate, int stack_limit) { v8::Local stack_trace = v8::StackTrace::CurrentStackTrace( - stack_limit, v8::StackTrace::kDetailed); + isolate, stack_limit, v8::StackTrace::kDetailed); int frame_count = stack_trace->GetFrameCount(); - v8::Local result = v8::Array::New(frame_count); + v8::Local 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 process) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); +void AtomBindings::BindTo(v8::Isolate* isolate, + v8::Handle process) { mate::Dictionary dict(isolate, process); - dict.SetMethod("atomBinding", &Binding); dict.SetMethod("crash", &Crash); dict.SetMethod("activateUvLoop", &ActivateUVLoop); dict.SetMethod("log", &Log); diff --git a/atom/common/api/atom_bindings.h b/atom/common/api/atom_bindings.h index 4b5f314b11f3..067a035024bb 100644 --- a/atom/common/api/atom_bindings.h +++ b/atom/common/api/atom_bindings.h @@ -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 process); + virtual void BindTo(v8::Isolate* isolate, v8::Handle process); private: DISALLOW_COPY_AND_ASSIGN(AtomBindings); diff --git a/atom/common/api/atom_extensions.cc b/atom/common/api/atom_extensions.cc deleted file mode 100644 index a9943aea6a18..000000000000 --- a/atom/common/api/atom_extensions.cc +++ /dev/null @@ -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 -#include - -#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 diff --git a/atom/common/api/atom_extensions.h b/atom/common/api/atom_extensions.h deleted file mode 100644 index e8fefac78433..000000000000 --- a/atom/common/api/atom_extensions.h +++ /dev/null @@ -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 diff --git a/atom/common/api/lib/screen.coffee b/atom/common/api/lib/screen.coffee index 1f4989fccd95..da7701e55a4e 100644 --- a/atom/common/api/lib/screen.coffee +++ b/atom/common/api/lib/screen.coffee @@ -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' diff --git a/atom/common/api/object_life_monitor.cc b/atom/common/api/object_life_monitor.cc index f4ca8c49104b..8d51e3d48895 100644 --- a/atom/common/api/object_life_monitor.cc +++ b/atom/common/api/object_life_monitor.cc @@ -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 target, +void ObjectLifeMonitor::BindTo(v8::Isolate* isolate, + v8::Handle target, v8::Handle 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* value, - ObjectLifeMonitor* self) { +void ObjectLifeMonitor::WeakCallback( + const v8::WeakCallbackData& data) { // destructor.call(object, object); - { - v8::HandleScope handle_scope(isolate); - v8::Local obj = self->handle_.NewHandle(); - v8::Local::Cast(obj->GetHiddenValue( - v8::String::New("destructor")))->Call(obj, 0, NULL); - } - - delete self; + v8::Local obj = data.GetValue(); + v8::Local::Cast(obj->GetHiddenValue( + MATE_STRING_NEW(data.GetIsolate(), "destructor")))->Call(obj, 0, NULL); + delete data.GetParameter(); } } // namespace atom diff --git a/atom/common/api/object_life_monitor.h b/atom/common/api/object_life_monitor.h index 46b5b4b7b5b3..3caaa91aaa70 100644 --- a/atom/common/api/object_life_monitor.h +++ b/atom/common/api/object_life_monitor.h @@ -12,15 +12,15 @@ namespace atom { class ObjectLifeMonitor { public: - static void BindTo(v8::Handle target, + static void BindTo(v8::Isolate* isolate, + v8::Handle target, v8::Handle destructor); private: ObjectLifeMonitor(); - static void WeakCallback(v8::Isolate* isolate, - v8::Persistent* value, - ObjectLifeMonitor* self); + static void WeakCallback( + const v8::WeakCallbackData& data); mate::ScopedPersistent handle_; diff --git a/atom/common/chrome_version.h b/atom/common/chrome_version.h index d0ebcb54aa3b..f6b1b8febed3 100644 --- a/atom/common/chrome_version.h +++ b/atom/common/chrome_version.h @@ -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_ diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index cff97e202ac7..6a581cc9710b 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -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(); diff --git a/atom/common/crash_reporter/win/crash_service.cc b/atom/common/crash_reporter/win/crash_service.cc index 4ee0770d6e40..5cb6f9835138 100644 --- a/atom/common/crash_reporter/win/crash_service.cc +++ b/atom/common/crash_reporter/win/crash_service.cc @@ -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); diff --git a/atom/common/crash_reporter/win/crash_service_main.cc b/atom/common/crash_reporter/win/crash_service_main.cc index 85b376ab61b5..314fc4d9fbcf 100644 --- a/atom/common/crash_reporter/win/crash_service_main.cc +++ b/atom/common/crash_reporter/win/crash_service_main.cc @@ -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"); diff --git a/atom/common/lib/init.coffee b/atom/common/lib/init.coffee index 5e2602ac1805..5da02744275b 100644 --- a/atom/common/lib/init.coffee +++ b/atom/common/lib/init.coffee @@ -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') diff --git a/atom/common/native_mate_converters/image_converter.cc b/atom/common/native_mate_converters/image_converter.cc index ca676c8d0091..f3292297405d 100644 --- a/atom/common/native_mate_converters/image_converter.cc +++ b/atom/common/native_mate_converters/image_converter.cc @@ -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 { diff --git a/atom/common/native_mate_converters/string16_converter.h b/atom/common/native_mate_converters/string16_converter.h index 172bed74a37b..baa833a09d2b 100644 --- a/atom/common/native_mate_converters/string16_converter.h +++ b/atom/common/native_mate_converters/string16_converter.h @@ -11,17 +11,20 @@ namespace mate { template<> -struct Converter { +struct Converter { static v8::Handle ToV8(v8::Isolate* isolate, - const string16& val) { - return v8::String::New(reinterpret_cast(val.data()), - val.size()); + const base::string16& val) { + return MATE_STRING_NEW_FROM_UTF16( + isolate, reinterpret_cast(val.data()), val.size()); } static bool FromV8(v8::Isolate* isolate, v8::Handle val, - string16* out) { + base::string16* out) { + if (!val->IsString()) + return false; + v8::String::Value s(val); - out->assign(reinterpret_cast(*s), s.length()); + out->assign(reinterpret_cast(*s), s.length()); return true; } }; diff --git a/atom/common/native_mate_converters/v8_value_converter.cc b/atom/common/native_mate_converters/v8_value_converter.cc index ca0af6f825b9..fc1284345268 100644 --- a/atom/common/native_mate_converters/v8_value_converter.cc +++ b/atom/common/native_mate_converters/v8_value_converter.cc @@ -36,74 +36,76 @@ void V8ValueConverter::SetStripNullFromObjects(bool val) { strip_null_from_objects_ = val; } -v8::Handle V8ValueConverter::ToV8Value( - const base::Value* value, v8::Handle context) const { +v8::Local V8ValueConverter::ToV8Value( + const base::Value* value, v8::Local context) const { v8::Context::Scope context_scope(context); - v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); - return handle_scope.Close(ToV8ValueImpl(value)); + v8::EscapableHandleScope handle_scope(context->GetIsolate()); + return handle_scope.Escape(ToV8ValueImpl(context->GetIsolate(), value)); } -Value* V8ValueConverter::FromV8Value( - v8::Handle val, - v8::Handle context) const { +base::Value* V8ValueConverter::FromV8Value( + v8::Local val, + v8::Local context) const { v8::Context::Scope context_scope(context); - v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); + v8::HandleScope handle_scope(context->GetIsolate()); HashToHandleMap unique_map; return FromV8ValueImpl(val, &unique_map); } -v8::Handle V8ValueConverter::ToV8ValueImpl( - const base::Value* value) const { +v8::Local V8ValueConverter::ToV8ValueImpl( + v8::Isolate* isolate, const base::Value* value) const { CHECK(value); switch (value->GetType()) { case base::Value::TYPE_NULL: - return v8::Null(); + return v8::Null(isolate); case base::Value::TYPE_BOOLEAN: { bool val = false; CHECK(value->GetAsBoolean(&val)); - return v8::Boolean::New(val); + return v8::Boolean::New(isolate, val); } case base::Value::TYPE_INTEGER: { int val = 0; CHECK(value->GetAsInteger(&val)); - return v8::Integer::New(val); + return v8::Integer::New(isolate, val); } case base::Value::TYPE_DOUBLE: { double val = 0.0; CHECK(value->GetAsDouble(&val)); - return v8::Number::New(val); + return v8::Number::New(isolate, val); } case base::Value::TYPE_STRING: { std::string val; CHECK(value->GetAsString(&val)); - return v8::String::New(val.c_str(), val.length()); + return v8::String::NewFromUtf8( + isolate, val.c_str(), v8::String::kNormalString, val.length()); } case base::Value::TYPE_LIST: - return ToV8Array(static_cast(value)); + return ToV8Array(isolate, static_cast(value)); case base::Value::TYPE_DICTIONARY: - return ToV8Object(static_cast(value)); + return ToV8Object(isolate, + static_cast(value)); default: LOG(ERROR) << "Unexpected value type: " << value->GetType(); - return v8::Null(); + return v8::Null(isolate); } } -v8::Handle V8ValueConverter::ToV8Array( - const base::ListValue* val) const { - v8::Handle result(v8::Array::New(val->GetSize())); +v8::Local V8ValueConverter::ToV8Array( + v8::Isolate* isolate, const base::ListValue* val) const { + v8::Local result(v8::Array::New(isolate, val->GetSize())); for (size_t i = 0; i < val->GetSize(); ++i) { const base::Value* child = NULL; CHECK(val->Get(i, &child)); - v8::Handle child_v8 = ToV8ValueImpl(child); + v8::Local child_v8 = ToV8ValueImpl(isolate, child); CHECK(!child_v8.IsEmpty()); v8::TryCatch try_catch; @@ -115,18 +117,21 @@ v8::Handle V8ValueConverter::ToV8Array( return result; } -v8::Handle V8ValueConverter::ToV8Object( - const base::DictionaryValue* val) const { - v8::Handle result(v8::Object::New()); +v8::Local V8ValueConverter::ToV8Object( + v8::Isolate* isolate, const base::DictionaryValue* val) const { + v8::Local result(v8::Object::New(isolate)); for (base::DictionaryValue::Iterator iter(*val); !iter.IsAtEnd(); iter.Advance()) { const std::string& key = iter.key(); - v8::Handle child_v8 = ToV8ValueImpl(&iter.value()); + v8::Local child_v8 = ToV8ValueImpl(isolate, &iter.value()); CHECK(!child_v8.IsEmpty()); v8::TryCatch try_catch; - result->Set(v8::String::New(key.c_str(), key.length()), child_v8); + result->Set( + v8::String::NewFromUtf8(isolate, key.c_str(), v8::String::kNormalString, + key.length()), + child_v8); if (try_catch.HasCaught()) { LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " << "exception."; @@ -136,7 +141,7 @@ v8::Handle V8ValueConverter::ToV8Object( return result; } -Value* V8ValueConverter::FromV8ValueImpl(v8::Handle val, +base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local val, HashToHandleMap* unique_map) const { CHECK(!val.IsEmpty()); @@ -196,16 +201,17 @@ Value* V8ValueConverter::FromV8ValueImpl(v8::Handle val, return NULL; } -Value* V8ValueConverter::FromV8Array(v8::Handle val, +base::Value* V8ValueConverter::FromV8Array(v8::Local val, HashToHandleMap* unique_map) const { if (!UpdateAndCheckUniqueness(unique_map, val)) return base::Value::CreateNullValue(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); scoped_ptr scope; // If val was created in a different context than our current one, change to // that context, but change back after val is converted. if (!val->CreationContext().IsEmpty() && - val->CreationContext() != v8::Context::GetCurrent()) + val->CreationContext() != isolate->GetCurrentContext()) scope.reset(new v8::Context::Scope(val->CreationContext())); base::ListValue* result = new base::ListValue(); @@ -213,10 +219,10 @@ Value* V8ValueConverter::FromV8Array(v8::Handle val, // Only fields with integer keys are carried over to the ListValue. for (uint32 i = 0; i < val->Length(); ++i) { v8::TryCatch try_catch; - v8::Handle child_v8 = val->Get(i); + v8::Local child_v8 = val->Get(i); if (try_catch.HasCaught()) { LOG(ERROR) << "Getter for index " << i << " threw an exception."; - child_v8 = v8::Null(); + child_v8 = v8::Null(isolate); } if (!val->HasRealIndexedProperty(i)) @@ -233,28 +239,29 @@ Value* V8ValueConverter::FromV8Array(v8::Handle val, return result; } -Value* V8ValueConverter::FromV8Object( - v8::Handle val, +base::Value* V8ValueConverter::FromV8Object( + v8::Local val, HashToHandleMap* unique_map) const { if (!UpdateAndCheckUniqueness(unique_map, val)) return base::Value::CreateNullValue(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); scoped_ptr scope; // If val was created in a different context than our current one, change to // that context, but change back after val is converted. if (!val->CreationContext().IsEmpty() && - val->CreationContext() != v8::Context::GetCurrent()) + val->CreationContext() != isolate->GetCurrentContext()) scope.reset(new v8::Context::Scope(val->CreationContext())); scoped_ptr result(new base::DictionaryValue()); - v8::Handle property_names(val->GetOwnPropertyNames()); + v8::Local property_names(val->GetOwnPropertyNames()); for (uint32 i = 0; i < property_names->Length(); ++i) { - v8::Handle key(property_names->Get(i)); + v8::Local key(property_names->Get(i)); // Extend this test to cover more types as necessary and if sensible. if (!key->IsString() && !key->IsNumber()) { - NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" " + NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " "is neither a string nor a number"; continue; } @@ -266,12 +273,12 @@ Value* V8ValueConverter::FromV8Object( v8::String::Utf8Value name_utf8(key->ToString()); v8::TryCatch try_catch; - v8::Handle child_v8 = val->Get(key); + v8::Local child_v8 = val->Get(key); if (try_catch.HasCaught()) { LOG(ERROR) << "Getter for property " << *name_utf8 << " threw an exception."; - child_v8 = v8::Null(); + child_v8 = v8::Null(isolate); } scoped_ptr child(FromV8ValueImpl(child_v8, unique_map)); @@ -300,7 +307,7 @@ Value* V8ValueConverter::FromV8Object( // there *is* a "windowId" property, but since it should be an int, code // on the browser which doesn't additionally check for null will fail. // We can avoid all bugs related to this by stripping null. - if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) + if (strip_null_from_objects_ && child->IsType(base::Value::TYPE_NULL)) continue; result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), @@ -312,7 +319,7 @@ Value* V8ValueConverter::FromV8Object( bool V8ValueConverter::UpdateAndCheckUniqueness( HashToHandleMap* map, - v8::Handle handle) const { + v8::Local handle) const { typedef HashToHandleMap::const_iterator Iterator; int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash(); @@ -326,7 +333,7 @@ bool V8ValueConverter::UpdateAndCheckUniqueness( return false; } - map->insert(std::pair >(hash, handle)); + map->insert(std::pair >(hash, handle)); return true; } diff --git a/atom/common/native_mate_converters/v8_value_converter.h b/atom/common/native_mate_converters/v8_value_converter.h index 5c7e6182acb9..40688978bbd5 100644 --- a/atom/common/native_mate_converters/v8_value_converter.h +++ b/atom/common/native_mate_converters/v8_value_converter.h @@ -28,25 +28,28 @@ class V8ValueConverter { void SetRegExpAllowed(bool val); void SetFunctionAllowed(bool val); void SetStripNullFromObjects(bool val); - v8::Handle ToV8Value(const base::Value* value, - v8::Handle context) const; - base::Value* FromV8Value(v8::Handle value, - v8::Handle context) const; + v8::Local ToV8Value(const base::Value* value, + v8::Local context) const; + base::Value* FromV8Value(v8::Local value, + v8::Local context) const; private: - typedef std::multimap > HashToHandleMap; + typedef std::multimap > HashToHandleMap; - v8::Handle ToV8ValueImpl(const base::Value* value) const; - v8::Handle ToV8Array(const base::ListValue* list) const; - v8::Handle ToV8Object( + v8::Local ToV8ValueImpl(v8::Isolate* isolate, + const base::Value* value) const; + v8::Local ToV8Array(v8::Isolate* isolate, + const base::ListValue* list) const; + v8::Local ToV8Object( + v8::Isolate* isolate, const base::DictionaryValue* dictionary) const; - base::Value* FromV8ValueImpl(v8::Handle value, + base::Value* FromV8ValueImpl(v8::Local value, HashToHandleMap* unique_map) const; - base::Value* FromV8Array(v8::Handle array, + base::Value* FromV8Array(v8::Local array, HashToHandleMap* unique_map) const; - base::Value* FromV8Object(v8::Handle object, + base::Value* FromV8Object(v8::Local object, HashToHandleMap* unique_map) const; // If |handle| is not in |map|, then add it to |map| and return true. @@ -55,7 +58,7 @@ class V8ValueConverter { // be unique even if there already is another handle with the same identity // hash (key) in the map, because two objects can have the same hash. bool UpdateAndCheckUniqueness(HashToHandleMap* map, - v8::Handle handle) const; + v8::Local handle) const; // If true, we will convert Date JavaScript objects to doubles. bool date_allowed_; diff --git a/atom/common/native_mate_converters/value_converter.cc b/atom/common/native_mate_converters/value_converter.cc index 79848b28bf44..e56100b15042 100644 --- a/atom/common/native_mate_converters/value_converter.cc +++ b/atom/common/native_mate_converters/value_converter.cc @@ -14,9 +14,9 @@ bool Converter::FromV8(v8::Isolate* isolate, base::DictionaryValue* out) { scoped_ptr converter(new atom::V8ValueConverter); scoped_ptr value(converter->FromV8Value( - val, v8::Context::GetCurrent())); + val, isolate->GetCurrentContext())); if (value && value->IsType(base::Value::TYPE_DICTIONARY)) { - out->Swap(static_cast(value.get())); + out->Swap(static_cast(value.get())); return true; } else { return false; @@ -28,9 +28,9 @@ bool Converter::FromV8(v8::Isolate* isolate, base::ListValue* out) { scoped_ptr converter(new atom::V8ValueConverter); scoped_ptr value(converter->FromV8Value( - val, v8::Context::GetCurrent())); + val, isolate->GetCurrentContext())); if (value->IsType(base::Value::TYPE_LIST)) { - out->Swap(static_cast(value.get())); + out->Swap(static_cast(value.get())); return true; } else { return false; diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 4d78cea6b224..2d5d8364bc08 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -31,12 +31,58 @@ void SetupProcessObject(Environment*, int, const char* const*, int, const char* const*); } +// Force all builtin modules to be referenced so they can actually run their +// DSO constructors, see http://git.io/DRIqCg. +#define REFERENCE_MODULE(name) \ + extern "C" void _register_ ## name(void); \ + void (*fp_register_ ## name)(void) = _register_ ## name +// Node's builtin modules. +REFERENCE_MODULE(cares_wrap); +REFERENCE_MODULE(fs_event_wrap); +REFERENCE_MODULE(buffer); +REFERENCE_MODULE(contextify); +REFERENCE_MODULE(crypto); +REFERENCE_MODULE(fs); +REFERENCE_MODULE(http_parser); +REFERENCE_MODULE(os); +REFERENCE_MODULE(v8); +REFERENCE_MODULE(zlib); +REFERENCE_MODULE(pipe_wrap); +REFERENCE_MODULE(process_wrap); +REFERENCE_MODULE(signal_wrap); +REFERENCE_MODULE(smalloc); +REFERENCE_MODULE(spawn_sync); +REFERENCE_MODULE(tcp_wrap); +REFERENCE_MODULE(timer_wrap); +REFERENCE_MODULE(tls_wrap); +REFERENCE_MODULE(tty_wrap); +REFERENCE_MODULE(udp_wrap); +REFERENCE_MODULE(uv); +// Atom Shell's builtin modules. +REFERENCE_MODULE(atom_browser_app); +REFERENCE_MODULE(atom_browser_auto_updater); +REFERENCE_MODULE(atom_browser_dialog); +REFERENCE_MODULE(atom_browser_menu); +REFERENCE_MODULE(atom_browser_power_monitor); +REFERENCE_MODULE(atom_browser_protocol); +REFERENCE_MODULE(atom_browser_tray); +REFERENCE_MODULE(atom_browser_window); +REFERENCE_MODULE(atom_common_clipboard); +REFERENCE_MODULE(atom_common_crash_reporter); +REFERENCE_MODULE(atom_common_id_weak_map); +REFERENCE_MODULE(atom_common_screen); +REFERENCE_MODULE(atom_common_shell); +REFERENCE_MODULE(atom_common_v8_util); +REFERENCE_MODULE(atom_renderer_ipc); +REFERENCE_MODULE(atom_renderer_web_view); +#undef REFERENCE_MODULE + namespace atom { namespace { // Empty callback for async handle. -void UvNoOp(uv_async_t* handle, int status) { +void UvNoOp(uv_async_t* handle) { } // Convert the given vector to an array of C-strings. The strings in the @@ -52,11 +98,11 @@ scoped_ptr StringVectorToArgArray( #if defined(OS_WIN) std::vector String16VectorToStringVector( - const std::vector& vector) { + const std::vector& vector) { std::vector utf8_vector; utf8_vector.reserve(vector.size()); for (size_t i = 0; i < vector.size(); ++i) - utf8_vector.push_back(UTF16ToUTF8(vector[i])); + utf8_vector.push_back(base::UTF16ToUTF8(vector[i])); return utf8_vector; } #endif @@ -85,16 +131,9 @@ NodeBindings::~NodeBindings() { // Clear uv. uv_sem_destroy(&embed_sem_); - uv_timer_stop(&idle_timer_); } void NodeBindings::Initialize() { - // Init idle GC for browser. - if (is_browser_) { - uv_timer_init(uv_default_loop(), &idle_timer_); - uv_timer_start(&idle_timer_, IdleCallback, 5000, 5000); - } - // Open node's error reporting system for browser process. node::g_standalone_mode = is_browser_; node::g_upstream_node_mode = false; @@ -162,7 +201,7 @@ node::Environment* NodeBindings::CreateEnvironment( uv_unref(reinterpret_cast(env->idle_prepare_handle())); uv_unref(reinterpret_cast(env->idle_check_handle())); - Local process_template = FunctionTemplate::New(); + Local process_template = FunctionTemplate::New(isolate); process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process")); Local process_object = process_template->GetFunction()->NewInstance(); @@ -199,15 +238,16 @@ void NodeBindings::RunMessageLoop() { void NodeBindings::UvRunOnce() { DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Use Locker in browser process. - BrowserV8Locker locker(node_isolate); - - v8::HandleScope handle_scope(node_isolate); - - // Enter node context while dealing with uv events, by default the global - // env would be used unless user specified another one (this happens for - // renderer process, which wraps the uv loop with web page context). + // By default the global env would be used unless user specified another one + // (this happens for renderer process, which wraps the uv loop with web page + // context). node::Environment* env = uv_env() ? uv_env() : global_env; + + // Use Locker in browser process. + BrowserV8Locker locker(env->isolate()); + v8::HandleScope handle_scope(env->isolate()); + + // Enter node context while dealing with uv events. v8::Context::Scope context_scope(env->context()); // Deal with uv events. @@ -253,9 +293,4 @@ void NodeBindings::EmbedThreadRunner(void *arg) { } } -// static -void NodeBindings::IdleCallback(uv_timer_t*, int) { - v8::V8::IdleNotification(); -} - } // namespace atom diff --git a/atom/common/node_bindings.h b/atom/common/node_bindings.h index a011a032ae29..6d9c4f754347 100644 --- a/atom/common/node_bindings.h +++ b/atom/common/node_bindings.h @@ -70,18 +70,12 @@ class NodeBindings { // Thread to poll uv events. static void EmbedThreadRunner(void *arg); - // Do idle GC. - static void IdleCallback(uv_timer_t*, int); - // Whether the libuv loop has ended. bool embed_closed_; // Dummy handle to make uv's loop not quit. uv_async_t dummy_uv_handle_; - // Timer to do idle GC. - uv_timer_t idle_timer_; - // Thread for polling events. uv_thread_t embed_thread_; diff --git a/atom/common/node_includes.h b/atom/common/node_includes.h index 9f544a124e84..680a211f0391 100644 --- a/atom/common/node_includes.h +++ b/atom/common/node_includes.h @@ -10,13 +10,17 @@ #undef CHECK #undef CHECK_EQ #undef CHECK_NE +#undef CHECK_GE +#undef CHECK_GT +#undef CHECK_LE +#undef CHECK_LT #undef DISALLOW_COPY_AND_ASSIGN +#undef debug_string // This is defined in OS X 10.9 SDK in AssertMacros.h. #include "vendor/node/src/env.h" #include "vendor/node/src/env-inl.h" #include "vendor/node/src/node.h" #include "vendor/node/src/node_buffer.h" #include "vendor/node/src/node_internals.h" -using node::node_isolate; namespace atom { // Defined in node_bindings.cc. diff --git a/atom/common/platform_util_win.cc b/atom/common/platform_util_win.cc index 52e87accef77..23576be6a363 100644 --- a/atom/common/platform_util_win.cc +++ b/atom/common/platform_util_win.cc @@ -29,7 +29,7 @@ namespace { // is empty. This function tells if it is. bool ValidateShellCommandForScheme(const std::string& scheme) { base::win::RegKey key; - std::wstring registry_path = ASCIIToWide(scheme) + + std::wstring registry_path = base::ASCIIToWide(scheme) + L"\\shell\\open\\command"; key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ); if (!key.Valid()) diff --git a/atom/renderer/api/atom_api_renderer_ipc.cc b/atom/renderer/api/atom_api_renderer_ipc.cc index 13c73add873e..678a0c7e1fc6 100644 --- a/atom/renderer/api/atom_api_renderer_ipc.cc +++ b/atom/renderer/api/atom_api_renderer_ipc.cc @@ -13,8 +13,8 @@ #include "atom/common/node_includes.h" using content::RenderView; -using WebKit::WebFrame; -using WebKit::WebView; +using blink::WebFrame; +using blink::WebView; namespace { @@ -30,7 +30,7 @@ RenderView* GetCurrentRenderView() { return RenderView::FromWebView(view); } -void Send(const string16& channel, const base::ListValue& arguments) { +void Send(const base::string16& channel, const base::ListValue& arguments) { RenderView* render_view = GetCurrentRenderView(); if (render_view == NULL) return; @@ -42,8 +42,9 @@ void Send(const string16& channel, const base::ListValue& arguments) { node::ThrowError("Unable to send AtomViewHostMsg_Message"); } -string16 SendSync(const string16& channel, const base::ListValue& arguments) { - string16 json; +base::string16 SendSync(const base::string16& channel, + const base::ListValue& arguments) { + base::string16 json; RenderView* render_view = GetCurrentRenderView(); if (render_view == NULL) @@ -61,12 +62,13 @@ string16 SendSync(const string16& channel, const base::ListValue& arguments) { return json; } -void Initialize(v8::Handle exports) { - mate::Dictionary dict(v8::Isolate::GetCurrent(), exports); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle context, void* priv) { + mate::Dictionary dict(context->GetIsolate(), exports); dict.SetMethod("send", &Send); dict.SetMethod("sendSync", &SendSync); } } // namespace -NODE_MODULE(atom_renderer_ipc, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_renderer_ipc, Initialize) diff --git a/atom/renderer/api/atom_api_web_view.cc b/atom/renderer/api/atom_api_web_view.cc index 4cbb2953bca2..1f983cdf96a8 100644 --- a/atom/renderer/api/atom_api_web_view.cc +++ b/atom/renderer/api/atom_api_web_view.cc @@ -17,8 +17,8 @@ namespace api { namespace { -WebKit::WebView* GetCurrentWebView() { - WebKit::WebFrame* frame = WebKit::WebFrame::frameForCurrentContext(); +blink::WebView* GetCurrentWebView() { + blink::WebFrame* frame = blink::WebFrame::frameForCurrentContext(); if (!frame) return NULL; return frame->view(); @@ -41,12 +41,12 @@ double WebView::GetZoomLevel() const { } double WebView::SetZoomFactor(double factor) { - return WebKit::WebView::zoomLevelToZoomFactor(SetZoomLevel( - WebKit::WebView::zoomFactorToZoomLevel(factor))); + return blink::WebView::zoomLevelToZoomFactor(SetZoomLevel( + blink::WebView::zoomFactorToZoomLevel(factor))); } double WebView::GetZoomFactor() const { - return WebKit::WebView::zoomLevelToZoomFactor(GetZoomLevel()); + return blink::WebView::zoomLevelToZoomFactor(GetZoomLevel()); } mate::ObjectTemplateBuilder WebView::GetObjectTemplateBuilder( @@ -69,12 +69,13 @@ mate::Handle WebView::Create(v8::Isolate* isolate) { namespace { -void Initialize(v8::Handle exports) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); +void Initialize(v8::Handle exports, v8::Handle unused, + v8::Handle context, void* priv) { + v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); dict.Set("webView", atom::api::WebView::Create(isolate)); } } // namespace -NODE_MODULE(atom_renderer_web_view, Initialize) +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_renderer_web_view, Initialize) diff --git a/atom/renderer/api/atom_api_web_view.h b/atom/renderer/api/atom_api_web_view.h index c8c289b959c1..be6012e84ddf 100644 --- a/atom/renderer/api/atom_api_web_view.h +++ b/atom/renderer/api/atom_api_web_view.h @@ -8,7 +8,7 @@ #include "native_mate/handle.h" #include "native_mate/wrappable.h" -namespace WebKit { +namespace blink { class WebView; } @@ -33,7 +33,7 @@ class WebView : public mate::Wrappable { virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate); - WebKit::WebView* web_view_; + blink::WebView* web_view_; DISALLOW_COPY_AND_ASSIGN(WebView); }; diff --git a/atom/renderer/api/atom_renderer_bindings.cc b/atom/renderer/api/atom_renderer_bindings.cc index d21f0a655f25..50acaf1cb198 100644 --- a/atom/renderer/api/atom_renderer_bindings.cc +++ b/atom/renderer/api/atom_renderer_bindings.cc @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "base/values.h" #include "content/public/renderer/render_view.h" +#include "native_mate/converter.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebView.h" @@ -21,8 +22,8 @@ namespace atom { namespace { v8::Handle GetProcessObject(v8::Handle context) { - v8::Handle process = - context->Global()->Get(v8::String::New("process"))->ToObject(); + v8::Handle process = context->Global()->Get( + mate::StringToV8(context->GetIsolate(), "process"))->ToObject(); DCHECK(!process.IsEmpty()); return process; @@ -36,24 +37,26 @@ AtomRendererBindings::AtomRendererBindings() { AtomRendererBindings::~AtomRendererBindings() { } -void AtomRendererBindings::BindToFrame(WebKit::WebFrame* frame) { - v8::HandleScope handle_scope(node_isolate); +void AtomRendererBindings::BindToFrame(blink::WebFrame* frame) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); v8::Handle context = frame->mainWorldScriptContext(); if (context.IsEmpty()) return; v8::Context::Scope scope(context); - AtomBindings::BindTo(GetProcessObject(context)); + AtomBindings::BindTo(isolate, GetProcessObject(context)); } void AtomRendererBindings::OnBrowserMessage(content::RenderView* render_view, - const string16& channel, + const base::string16& channel, const base::ListValue& args) { if (!render_view->GetWebView()) return; - v8::HandleScope handle_scope(node_isolate); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); v8::Local context = render_view->GetWebView()->mainFrame()->mainWorldScriptContext(); @@ -67,7 +70,7 @@ void AtomRendererBindings::OnBrowserMessage(content::RenderView* render_view, std::vector> arguments; arguments.reserve(1 + args.GetSize()); - arguments.push_back(mate::ConvertToV8(node_isolate, channel)); + arguments.push_back(mate::ConvertToV8(isolate, channel)); for (size_t i = 0; i < args.GetSize(); i++) { const base::Value* value; @@ -75,7 +78,7 @@ void AtomRendererBindings::OnBrowserMessage(content::RenderView* render_view, arguments.push_back(converter->ToV8Value(value, context)); } - node::MakeCallback(process, "emit", arguments.size(), &arguments[0]); + node::MakeCallback(isolate, process, "emit", arguments.size(), &arguments[0]); } } // namespace atom diff --git a/atom/renderer/api/atom_renderer_bindings.h b/atom/renderer/api/atom_renderer_bindings.h index 8f5667766a25..1b0c9c2ae976 100644 --- a/atom/renderer/api/atom_renderer_bindings.h +++ b/atom/renderer/api/atom_renderer_bindings.h @@ -17,7 +17,7 @@ namespace content { class RenderView; } -namespace WebKit { +namespace blink { class WebFrame; } @@ -29,11 +29,11 @@ class AtomRendererBindings : public AtomBindings { virtual ~AtomRendererBindings(); // Call BindTo for process object of the frame. - void BindToFrame(WebKit::WebFrame* frame); + void BindToFrame(blink::WebFrame* frame); // Dispatch messages from browser. void OnBrowserMessage(content::RenderView* render_view, - const string16& channel, + const base::string16& channel, const base::ListValue& args); private: diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index e5f9c181a0fb..05d17e1d96fe 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -22,7 +22,7 @@ #include "atom/common/node_includes.h" -using WebKit::WebFrame; +using blink::WebFrame; namespace atom { @@ -36,7 +36,7 @@ AtomRenderViewObserver::AtomRenderViewObserver( AtomRenderViewObserver::~AtomRenderViewObserver() { } -void AtomRenderViewObserver::DidCreateDocumentElement(WebKit::WebFrame* frame) { +void AtomRenderViewObserver::DidCreateDocumentElement(blink::WebFrame* frame) { // Read --zoom-factor from command line. std::string zoom_factor_str = CommandLine::ForCurrentProcess()-> GetSwitchValueASCII(switches::kZoomFactor);; @@ -45,12 +45,12 @@ void AtomRenderViewObserver::DidCreateDocumentElement(WebKit::WebFrame* frame) { double zoom_factor; if (!base::StringToDouble(zoom_factor_str, &zoom_factor)) return; - double zoom_level = WebKit::WebView::zoomFactorToZoomLevel(zoom_factor); + double zoom_level = blink::WebView::zoomFactorToZoomLevel(zoom_factor); frame->view()->setZoomLevel(zoom_level); } -void AtomRenderViewObserver::DraggableRegionsChanged(WebKit::WebFrame* frame) { - WebKit::WebVector webregions = +void AtomRenderViewObserver::DraggableRegionsChanged(blink::WebFrame* frame) { + blink::WebVector webregions = frame->document().draggableRegions(); std::vector regions; for (size_t i = 0; i < webregions.size(); ++i) { @@ -72,12 +72,12 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { return handled; } -void AtomRenderViewObserver::OnBrowserMessage(const string16& channel, +void AtomRenderViewObserver::OnBrowserMessage(const base::string16& channel, const base::ListValue& args) { if (!render_view()->GetWebView()) return; - WebKit::WebFrame* frame = render_view()->GetWebView()->mainFrame(); + blink::WebFrame* frame = render_view()->GetWebView()->mainFrame(); if (!renderer_client_->IsNodeBindingEnabled(frame)) return; diff --git a/atom/renderer/atom_render_view_observer.h b/atom/renderer/atom_render_view_observer.h index 4de9fd33cfe3..8941c04b0172 100644 --- a/atom/renderer/atom_render_view_observer.h +++ b/atom/renderer/atom_render_view_observer.h @@ -25,11 +25,11 @@ class AtomRenderViewObserver : public content::RenderViewObserver { private: // content::RenderViewObserver implementation. - virtual void DidCreateDocumentElement(WebKit::WebFrame* frame) OVERRIDE; - virtual void DraggableRegionsChanged(WebKit::WebFrame* frame) OVERRIDE; + virtual void DidCreateDocumentElement(blink::WebFrame* frame) OVERRIDE; + virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - void OnBrowserMessage(const string16& channel, + void OnBrowserMessage(const base::string16& channel, const base::ListValue& args); // Weak reference to renderer client. diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index b9567b1323bc..8b3aaee517f6 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -11,7 +11,10 @@ #include "atom/common/options_switches.h" #include "atom/renderer/api/atom_renderer_bindings.h" #include "atom/renderer/atom_render_view_observer.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_frame_observer.h" #include "base/command_line.h" +#include "native_mate/converter.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" @@ -28,6 +31,27 @@ const char* kSecurityManualEnableIframe = "manual-enable-iframe"; const char* kSecurityDisable = "disable"; const char* kSecurityEnableNodeIntegration = "enable-node-integration"; +// Helper class to forward the WillReleaseScriptContext message to the client. +class AtomRenderFrameObserver : public content::RenderFrameObserver { + public: + AtomRenderFrameObserver(content::RenderFrame* frame, + AtomRendererClient* renderer_client) + : content::RenderFrameObserver(frame), + renderer_client_(renderer_client) {} + + // content::RenderFrameObserver: + virtual void WillReleaseScriptContext(v8::Handle context, + int world_id) OVERRIDE { + renderer_client_->WillReleaseScriptContext( + render_frame()->GetWebFrame(), context, world_id); + } + + private: + AtomRendererClient* renderer_client_; + + DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); +}; + } // namespace AtomRendererClient::AtomRendererClient() @@ -65,16 +89,22 @@ void AtomRendererClient::RenderThreadStarted() { // Create a default empty environment which would be used when we need to // run V8 code out of a window context (like running a uv callback). - v8::HandleScope handle_scope(node_isolate); - v8::Local context = v8::Context::New(node_isolate); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Local context = v8::Context::New(isolate); global_env = node::Environment::New(context); } +void AtomRendererClient::RenderFrameCreated( + content::RenderFrame* render_frame) { + new AtomRenderFrameObserver(render_frame, this); +} + void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { new AtomRenderViewObserver(render_view, this); } -void AtomRendererClient::DidCreateScriptContext(WebKit::WebFrame* frame, +void AtomRendererClient::DidCreateScriptContext(blink::WebFrame* frame, v8::Handle context, int extension_group, int world_id) { @@ -88,7 +118,8 @@ void AtomRendererClient::DidCreateScriptContext(WebKit::WebFrame* frame, v8::Context::Scope scope(context); // Check the existance of process object to prevent duplicate initialization. - if (context->Global()->Has(v8::String::New("process"))) + if (context->Global()->Has( + mate::StringToV8(context->GetIsolate(), "process"))) return; // Give the node loop a run to make sure everything is ready. @@ -109,7 +140,7 @@ void AtomRendererClient::DidCreateScriptContext(WebKit::WebFrame* frame, } void AtomRendererClient::WillReleaseScriptContext( - WebKit::WebFrame* frame, + blink::WebFrame* frame, v8::Handle context, int world_id) { if (!IsNodeBindingEnabled(frame)) @@ -143,7 +174,7 @@ void AtomRendererClient::WillReleaseScriptContext( } } -bool AtomRendererClient::ShouldFork(WebKit::WebFrame* frame, +bool AtomRendererClient::ShouldFork(blink::WebFrame* frame, const GURL& url, const std::string& http_method, bool is_initial_navigation, @@ -156,7 +187,7 @@ bool AtomRendererClient::ShouldFork(WebKit::WebFrame* frame, return http_method == "GET"; } -bool AtomRendererClient::IsNodeBindingEnabled(WebKit::WebFrame* frame) { +bool AtomRendererClient::IsNodeBindingEnabled(blink::WebFrame* frame) { if (node_integration_ == DISABLE) return false; // Node integration is enabled in main frame unless explictly disabled. diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 6cf63b798cfc..dd143d1a4a9f 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -24,7 +24,12 @@ class AtomRendererClient : public content::ContentRendererClient { AtomRendererClient(); virtual ~AtomRendererClient(); - bool IsNodeBindingEnabled(WebKit::WebFrame* frame = NULL); + bool IsNodeBindingEnabled(blink::WebFrame* frame = NULL); + + // Forwarded by RenderFrameObserver. + void WillReleaseScriptContext(blink::WebFrame* frame, + v8::Handle context, + int world_id); AtomRendererBindings* atom_bindings() const { return atom_bindings_.get(); } @@ -36,21 +41,20 @@ class AtomRendererClient : public content::ContentRendererClient { DISABLE, }; + // content::ContentRendererClient: virtual void RenderThreadStarted() OVERRIDE; + virtual void RenderFrameCreated(content::RenderFrame* render_frame) OVERRIDE; virtual void RenderViewCreated(content::RenderView*) OVERRIDE; - virtual void DidCreateScriptContext(WebKit::WebFrame* frame, + virtual void DidCreateScriptContext(blink::WebFrame* frame, v8::Handle context, int extension_group, int world_id) OVERRIDE; - virtual void WillReleaseScriptContext(WebKit::WebFrame* frame, - v8::Handle, - int world_id) OVERRIDE; - virtual bool ShouldFork(WebKit::WebFrame* frame, + virtual bool ShouldFork(blink::WebFrame* frame, const GURL& url, const std::string& http_method, bool is_initial_navigation, bool is_server_redirect, - bool* send_referrer); + bool* send_referrer) OVERRIDE; std::vector web_page_envs_; @@ -61,7 +65,7 @@ class AtomRendererClient : public content::ContentRendererClient { NodeIntegration node_integration_; // The main frame. - WebKit::WebFrame* main_frame_; + blink::WebFrame* main_frame_; DISALLOW_COPY_AND_ASSIGN(AtomRendererClient); }; diff --git a/atom/renderer/lib/inspector.coffee b/atom/renderer/lib/inspector.coffee index 43a258234ffa..8b6f748e00e1 100644 --- a/atom/renderer/lib/inspector.coffee +++ b/atom/renderer/lib/inspector.coffee @@ -1,11 +1,7 @@ window.onload = -> # Use menu API to show context menu. - WebInspector.ContextMenu.prototype.show = -> - menuObject = @_buildDescriptor() - if menuObject.length - WebInspector._contextMenu = this - createMenu(menuObject, @_event) - @_event.consume() + InspectorFrontendHost.showContextMenu = (event, items) -> + createMenu items, event # Use dialog API to override file chooser dialog. WebInspector.createFileSelectorElement = (callback) -> diff --git a/chrome/browser/ui/gtk/event_utils.cc b/chrome/browser/ui/gtk/event_utils.cc deleted file mode 100644 index f61c12165674..000000000000 --- a/chrome/browser/ui/gtk/event_utils.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/gtk/event_utils.h" - -#include "base/logging.h" -#include "ui/base/window_open_disposition.h" -#include "ui/events/event_constants.h" - -namespace event_utils { - -int EventFlagsFromGdkState(guint state) { - int flags = ui::EF_NONE; - flags |= (state & GDK_LOCK_MASK) ? ui::EF_CAPS_LOCK_DOWN : ui::EF_NONE; - flags |= (state & GDK_CONTROL_MASK) ? ui::EF_CONTROL_DOWN : ui::EF_NONE; - flags |= (state & GDK_SHIFT_MASK) ? ui::EF_SHIFT_DOWN : ui::EF_NONE; - flags |= (state & GDK_MOD1_MASK) ? ui::EF_ALT_DOWN : ui::EF_NONE; - flags |= (state & GDK_BUTTON1_MASK) ? ui::EF_LEFT_MOUSE_BUTTON : ui::EF_NONE; - flags |= (state & GDK_BUTTON2_MASK) ? ui::EF_MIDDLE_MOUSE_BUTTON - : ui::EF_NONE; - flags |= (state & GDK_BUTTON3_MASK) ? ui::EF_RIGHT_MOUSE_BUTTON : ui::EF_NONE; - return flags; -} - -// TODO(shinyak) This function will be removed after refactoring. -WindowOpenDisposition DispositionFromGdkState(guint state) { - int event_flags = EventFlagsFromGdkState(state); - return ui::DispositionFromEventFlags(event_flags); -} - -WindowOpenDisposition DispositionForCurrentButtonPressEvent() { - GdkEvent* event = gtk_get_current_event(); - if (!event) { - NOTREACHED(); - return NEW_FOREGROUND_TAB; - } - - guint state = event->button.state; - gdk_event_free(event); - return DispositionFromGdkState(state); -} - -} // namespace event_utils diff --git a/chrome/browser/ui/gtk/event_utils.h b/chrome/browser/ui/gtk/event_utils.h deleted file mode 100644 index fdcd8b7e6d24..000000000000 --- a/chrome/browser/ui/gtk/event_utils.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_GTK_EVENT_UTILS_H_ -#define CHROME_BROWSER_UI_GTK_EVENT_UTILS_H_ - -#include - -#include "ui/base/window_open_disposition.h" - -namespace event_utils { - -// Translates event flags into plaform independent event flags. -int EventFlagsFromGdkState(guint state); - -// Translates GdkEvent state into what kind of disposition they represent. -// For example, a middle click would mean to open a background tab. -WindowOpenDisposition DispositionFromGdkState(guint state); - -// Get the window open disposition from the state in gtk_get_current_event(). -// This is designed to be called inside a "clicked" event handler. It is an -// error to call it when gtk_get_current_event() won't return a GdkEventButton*. -WindowOpenDisposition DispositionForCurrentButtonPressEvent(); - -} // namespace event_utils - -#endif // CHROME_BROWSER_UI_GTK_EVENT_UTILS_H_ diff --git a/chrome/browser/ui/gtk/gtk_custom_menu.cc b/chrome/browser/ui/gtk/gtk_custom_menu.cc deleted file mode 100644 index bfa5a97284da..000000000000 --- a/chrome/browser/ui/gtk/gtk_custom_menu.cc +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/gtk/gtk_custom_menu.h" - -#include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" - -G_DEFINE_TYPE(GtkCustomMenu, gtk_custom_menu, GTK_TYPE_MENU) - -// Stolen directly from gtkmenushell.c. I'd love to call the library version -// instead, but it's static and isn't exported. :( -static gint gtk_menu_shell_is_item(GtkMenuShell* menu_shell, - GtkWidget* child) { - GtkWidget *parent; - - g_return_val_if_fail(GTK_IS_MENU_SHELL(menu_shell), FALSE); - g_return_val_if_fail(child != NULL, FALSE); - - parent = gtk_widget_get_parent(child); - while (GTK_IS_MENU_SHELL(parent)) { - if (parent == reinterpret_cast(menu_shell)) - return TRUE; - parent = GTK_MENU_SHELL(parent)->parent_menu_shell; - } - - return FALSE; -} - -// Stolen directly from gtkmenushell.c. I'd love to call the library version -// instead, but it's static and isn't exported. :( -static GtkWidget* gtk_menu_shell_get_item(GtkMenuShell* menu_shell, - GdkEvent* event) { - GtkWidget* menu_item = gtk_get_event_widget(event); - - while (menu_item && !GTK_IS_MENU_ITEM(menu_item)) - menu_item = gtk_widget_get_parent(menu_item); - - if (menu_item && gtk_menu_shell_is_item(menu_shell, menu_item)) - return menu_item; - else - return NULL; -} - -// When processing a button event, abort processing if the cursor isn't in a -// clickable region. -static gboolean gtk_custom_menu_button_press(GtkWidget* widget, - GdkEventButton* event) { - GtkWidget* menu_item = gtk_menu_shell_get_item( - GTK_MENU_SHELL(widget), reinterpret_cast(event)); - if (GTK_IS_CUSTOM_MENU_ITEM(menu_item)) { - if (!gtk_custom_menu_item_is_in_clickable_region( - GTK_CUSTOM_MENU_ITEM(menu_item))) { - return TRUE; - } - } - - return GTK_WIDGET_CLASS(gtk_custom_menu_parent_class)-> - button_press_event(widget, event); -} - -// When processing a button event, abort processing if the cursor isn't in a -// clickable region. If it's in a button that doesn't dismiss the menu, fire -// that event and abort having the normal GtkMenu code run. -static gboolean gtk_custom_menu_button_release(GtkWidget* widget, - GdkEventButton* event) { - GtkWidget* menu_item = gtk_menu_shell_get_item( - GTK_MENU_SHELL(widget), reinterpret_cast(event)); - if (GTK_IS_CUSTOM_MENU_ITEM(menu_item)) { - if (!gtk_custom_menu_item_is_in_clickable_region( - GTK_CUSTOM_MENU_ITEM(menu_item))) { - // Stop processing this event. This isn't a clickable region. - return TRUE; - } - - if (gtk_custom_menu_item_try_no_dismiss_command( - GTK_CUSTOM_MENU_ITEM(menu_item))) { - return TRUE; - } - } - - return GTK_WIDGET_CLASS(gtk_custom_menu_parent_class)-> - button_release_event(widget, event); -} - -// Manually forward button press events to the menu item (and then do what we'd -// do normally). -static gboolean gtk_custom_menu_motion_notify(GtkWidget* widget, - GdkEventMotion* event) { - GtkWidget* menu_item = gtk_menu_shell_get_item( - GTK_MENU_SHELL(widget), (GdkEvent*)event); - if (GTK_IS_CUSTOM_MENU_ITEM(menu_item)) { - gtk_custom_menu_item_receive_motion_event(GTK_CUSTOM_MENU_ITEM(menu_item), - event->x, event->y); - } - - return GTK_WIDGET_CLASS(gtk_custom_menu_parent_class)-> - motion_notify_event(widget, event); -} - -static void gtk_custom_menu_move_current(GtkMenuShell* menu_shell, - GtkMenuDirectionType direction) { - // If the currently selected item is custom, we give it first chance to catch - // up/down events. - - // TODO(erg): We are breaking a GSEAL by directly accessing this. We'll need - // to fix this by the time gtk3 comes out. - GtkWidget* menu_item = GTK_MENU_SHELL(menu_shell)->active_menu_item; - if (GTK_IS_CUSTOM_MENU_ITEM(menu_item)) { - switch (direction) { - case GTK_MENU_DIR_PREV: - case GTK_MENU_DIR_NEXT: - if (gtk_custom_menu_item_handle_move(GTK_CUSTOM_MENU_ITEM(menu_item), - direction)) - return; - break; - default: - break; - } - } - - GTK_MENU_SHELL_CLASS(gtk_custom_menu_parent_class)-> - move_current(menu_shell, direction); - - // In the case of hitting PREV and transitioning to a custom menu, we want to - // make sure we're selecting the final item in the list, not the first one. - menu_item = GTK_MENU_SHELL(menu_shell)->active_menu_item; - if (GTK_IS_CUSTOM_MENU_ITEM(menu_item)) { - gtk_custom_menu_item_select_item_by_direction( - GTK_CUSTOM_MENU_ITEM(menu_item), direction); - } -} - -static void gtk_custom_menu_init(GtkCustomMenu* menu) { -} - -static void gtk_custom_menu_class_init(GtkCustomMenuClass* klass) { - GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); - GtkMenuShellClass* menu_shell_class = GTK_MENU_SHELL_CLASS(klass); - - widget_class->button_press_event = gtk_custom_menu_button_press; - widget_class->button_release_event = gtk_custom_menu_button_release; - widget_class->motion_notify_event = gtk_custom_menu_motion_notify; - - menu_shell_class->move_current = gtk_custom_menu_move_current; -} - -GtkWidget* gtk_custom_menu_new() { - return GTK_WIDGET(g_object_new(GTK_TYPE_CUSTOM_MENU, NULL)); -} diff --git a/chrome/browser/ui/gtk/gtk_custom_menu.h b/chrome/browser/ui/gtk/gtk_custom_menu.h deleted file mode 100644 index 7aaa2b54f6f5..000000000000 --- a/chrome/browser/ui/gtk/gtk_custom_menu.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_H_ -#define CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_H_ - -// GtkCustomMenu is a GtkMenu subclass that can contain, and collaborates with, -// GtkCustomMenuItem instances. GtkCustomMenuItem is a GtkMenuItem that can -// have buttons and other normal widgets embeded in it. GtkCustomMenu exists -// only to override most of the button/motion/move callback functions so -// that the normal GtkMenu implementation doesn't handle events related to -// GtkCustomMenuItem items. -// -// For a more through overview of this system, see the comments in -// gtk_custom_menu_item.h. - -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_CUSTOM_MENU \ - (gtk_custom_menu_get_type()) -#define GTK_CUSTOM_MENU(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_CUSTOM_MENU, GtkCustomMenu)) -#define GTK_CUSTOM_MENU_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_CUSTOM_MENU, GtkCustomMenuClass)) -#define GTK_IS_CUSTOM_MENU(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CUSTOM_MENU)) -#define GTK_IS_CUSTOM_MENU_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CUSTOM_MENU)) -#define GTK_CUSTOM_MENU_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CUSTOM_MENU, GtkCustomMenuClass)) - -typedef struct _GtkCustomMenu GtkCustomMenu; -typedef struct _GtkCustomMenuClass GtkCustomMenuClass; - -struct _GtkCustomMenu { - GtkMenu menu; -}; - -struct _GtkCustomMenuClass { - GtkMenuClass parent_class; -}; - -GType gtk_custom_menu_get_type(void) G_GNUC_CONST; -GtkWidget* gtk_custom_menu_new(); - -G_END_DECLS - -#endif // CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_H_ diff --git a/chrome/browser/ui/gtk/gtk_custom_menu_item.cc b/chrome/browser/ui/gtk/gtk_custom_menu_item.cc deleted file mode 100644 index 2eda6010cea1..000000000000 --- a/chrome/browser/ui/gtk/gtk_custom_menu_item.cc +++ /dev/null @@ -1,493 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" - -#include "base/i18n/rtl.h" -#include "chrome/browser/ui/gtk/gtk_custom_menu.h" -#include "ui/gfx/gtk_compat.h" - -// This method was autogenerated by the program glib-genmarshall, which -// generated it from the line "BOOL:INT". Two different attempts at getting gyp -// to autogenerate this didn't work. If we need more non-standard marshallers, -// this should be deleted, and an actual build step should be added. -void chrome_marshall_BOOLEAN__INT(GClosure* closure, - GValue* return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue* param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) { - typedef gboolean(*GMarshalFunc_BOOLEAN__INT)(gpointer data1, - gint arg_1, - gpointer data2); - register GMarshalFunc_BOOLEAN__INT callback; - register GCClosure *cc = (GCClosure*)closure; - register gpointer data1, data2; - gboolean v_return; - - g_return_if_fail(return_value != NULL); - g_return_if_fail(n_param_values == 2); - - if (G_CCLOSURE_SWAP_DATA(closure)) { - data1 = closure->data; - // Note: This line (and the line setting data1 in the other if branch) - // were macros in the original autogenerated output. This is with the - // macro resolved for release mode. In debug mode, it uses an accessor - // that asserts saying that the object pointed to by param_values doesn't - // hold a pointer. This appears to be the cause of http://crbug.com/58945. - // - // This is more than a little odd because the gtype on this first param - // isn't set correctly by the time we get here, while I watched it - // explicitly set upstack. I verified that v_pointer is still set - // correctly. I'm not sure what's going on. :( - data2 = (param_values + 0)->data[0].v_pointer; - } else { - data1 = (param_values + 0)->data[0].v_pointer; - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__INT)(marshal_data ? marshal_data : - cc->callback); - - v_return = callback(data1, - g_value_get_int(param_values + 1), - data2); - - g_value_set_boolean(return_value, v_return); -} - -enum { - BUTTON_PUSHED, - TRY_BUTTON_PUSHED, - LAST_SIGNAL -}; - -static guint custom_menu_item_signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(GtkCustomMenuItem, gtk_custom_menu_item, GTK_TYPE_MENU_ITEM) - -static void set_selected(GtkCustomMenuItem* item, GtkWidget* selected) { - if (selected != item->currently_selected_button) { - if (item->currently_selected_button) { - gtk_widget_set_state(item->currently_selected_button, GTK_STATE_NORMAL); - gtk_widget_set_state( - gtk_bin_get_child(GTK_BIN(item->currently_selected_button)), - GTK_STATE_NORMAL); - } - - item->currently_selected_button = selected; - if (item->currently_selected_button) { - gtk_widget_set_state(item->currently_selected_button, GTK_STATE_SELECTED); - gtk_widget_set_state( - gtk_bin_get_child(GTK_BIN(item->currently_selected_button)), - GTK_STATE_PRELIGHT); - } - } -} - -// When GtkButtons set the label text, they rebuild the widget hierarchy each -// and every time. Therefore, we can't just fish out the label from the button -// and set some properties; we have to create this callback function that -// listens on the button's "notify" signal, which is emitted right after the -// label has been (re)created. (Label values can change dynamically.) -static void on_button_label_set(GObject* object) { - GtkButton* button = GTK_BUTTON(object); - GtkWidget* child = gtk_bin_get_child(GTK_BIN(button)); - gtk_widget_set_sensitive(child, FALSE); - gtk_misc_set_padding(GTK_MISC(child), 2, 0); -} - -static void gtk_custom_menu_item_finalize(GObject *object); -static gint gtk_custom_menu_item_expose(GtkWidget* widget, - GdkEventExpose* event); -static gboolean gtk_custom_menu_item_hbox_expose(GtkWidget* widget, - GdkEventExpose* event, - GtkCustomMenuItem* menu_item); -static void gtk_custom_menu_item_select(GtkItem *item); -static void gtk_custom_menu_item_deselect(GtkItem *item); -static void gtk_custom_menu_item_activate(GtkMenuItem* menu_item); - -static void gtk_custom_menu_item_init(GtkCustomMenuItem* item) { - item->all_widgets = NULL; - item->button_widgets = NULL; - item->currently_selected_button = NULL; - item->previously_selected_button = NULL; - - GtkWidget* menu_hbox = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(item), menu_hbox); - - item->label = gtk_label_new(NULL); - gtk_misc_set_alignment(GTK_MISC(item->label), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(menu_hbox), item->label, TRUE, TRUE, 0); - - item->hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_end(GTK_BOX(menu_hbox), item->hbox, FALSE, FALSE, 0); - - g_signal_connect(item->hbox, "expose-event", - G_CALLBACK(gtk_custom_menu_item_hbox_expose), - item); - - gtk_widget_show_all(menu_hbox); -} - -static void gtk_custom_menu_item_class_init(GtkCustomMenuItemClass* klass) { - GObjectClass* gobject_class = G_OBJECT_CLASS(klass); - GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); - GtkItemClass* item_class = GTK_ITEM_CLASS(klass); - GtkMenuItemClass* menu_item_class = GTK_MENU_ITEM_CLASS(klass); - - gobject_class->finalize = gtk_custom_menu_item_finalize; - - widget_class->expose_event = gtk_custom_menu_item_expose; - - item_class->select = gtk_custom_menu_item_select; - item_class->deselect = gtk_custom_menu_item_deselect; - - menu_item_class->activate = gtk_custom_menu_item_activate; - - custom_menu_item_signals[BUTTON_PUSHED] = - g_signal_new("button-pushed", - G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - custom_menu_item_signals[TRY_BUTTON_PUSHED] = - g_signal_new("try-button-pushed", - G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - chrome_marshall_BOOLEAN__INT, - G_TYPE_BOOLEAN, 1, G_TYPE_INT); -} - -static void gtk_custom_menu_item_finalize(GObject *object) { - GtkCustomMenuItem* item = GTK_CUSTOM_MENU_ITEM(object); - g_list_free(item->all_widgets); - g_list_free(item->button_widgets); - - G_OBJECT_CLASS(gtk_custom_menu_item_parent_class)->finalize(object); -} - -static gint gtk_custom_menu_item_expose(GtkWidget* widget, - GdkEventExpose* event) { - if (gtk_widget_get_visible(widget) && - gtk_widget_get_mapped(widget) && - gtk_bin_get_child(GTK_BIN(widget))) { - // We skip the drawing in the GtkMenuItem class it draws the highlighted - // background and we don't want that. - gtk_container_propagate_expose(GTK_CONTAINER(widget), - gtk_bin_get_child(GTK_BIN(widget)), - event); - } - - return FALSE; -} - -static void gtk_custom_menu_item_expose_button(GtkWidget* hbox, - GdkEventExpose* event, - GList* button_item) { - // We search backwards to find the leftmost and rightmost buttons. The - // current button may be that button. - GtkWidget* current_button = GTK_WIDGET(button_item->data); - GtkWidget* first_button = current_button; - for (GList* i = button_item; i && GTK_IS_BUTTON(i->data); - i = g_list_previous(i)) { - first_button = GTK_WIDGET(i->data); - } - - GtkWidget* last_button = current_button; - for (GList* i = button_item; i && GTK_IS_BUTTON(i->data); - i = g_list_next(i)) { - last_button = GTK_WIDGET(i->data); - } - - if (base::i18n::IsRTL()) - std::swap(first_button, last_button); - - GtkAllocation first_allocation; - gtk_widget_get_allocation(first_button, &first_allocation); - GtkAllocation current_allocation; - gtk_widget_get_allocation(current_button, ¤t_allocation); - GtkAllocation last_allocation; - gtk_widget_get_allocation(last_button, &last_allocation); - - int x = first_allocation.x; - int y = first_allocation.y; - int width = last_allocation.width + last_allocation.x - first_allocation.x; - int height = last_allocation.height; - - gtk_paint_box(gtk_widget_get_style(hbox), - gtk_widget_get_window(hbox), - gtk_widget_get_state(current_button), - GTK_SHADOW_OUT, - ¤t_allocation, hbox, "button", - x, y, width, height); - - // Propagate to the button's children. - gtk_container_propagate_expose( - GTK_CONTAINER(current_button), - gtk_bin_get_child(GTK_BIN(current_button)), - event); -} - -static gboolean gtk_custom_menu_item_hbox_expose(GtkWidget* widget, - GdkEventExpose* event, - GtkCustomMenuItem* menu_item) { - // First render all the buttons that aren't the currently selected item. - for (GList* current_item = menu_item->all_widgets; - current_item != NULL; current_item = g_list_next(current_item)) { - if (GTK_IS_BUTTON(current_item->data)) { - if (GTK_WIDGET(current_item->data) != - menu_item->currently_selected_button) { - gtk_custom_menu_item_expose_button(widget, event, current_item); - } - } - } - - // As a separate pass, draw the buton separators above. We need to draw the - // separators in a separate pass because we are drawing on top of the - // buttons. Otherwise, the vlines are overwritten by the next button. - for (GList* current_item = menu_item->all_widgets; - current_item != NULL; current_item = g_list_next(current_item)) { - if (GTK_IS_BUTTON(current_item->data)) { - // Check to see if this is the last button in a run. - GList* next_item = g_list_next(current_item); - if (next_item && GTK_IS_BUTTON(next_item->data)) { - GtkWidget* current_button = GTK_WIDGET(current_item->data); - GtkAllocation button_allocation; - gtk_widget_get_allocation(current_button, &button_allocation); - GtkAllocation child_alloc; - gtk_widget_get_allocation(gtk_bin_get_child(GTK_BIN(current_button)), - &child_alloc); - GtkStyle* style = gtk_widget_get_style(widget); - int half_offset = style->xthickness / 2; - gtk_paint_vline(style, - gtk_widget_get_window(widget), - gtk_widget_get_state(current_button), - &event->area, widget, "button", - child_alloc.y, - child_alloc.y + child_alloc.height, - button_allocation.x + - button_allocation.width - half_offset); - } - } - } - - // Finally, draw the selected item on top of the separators so there are no - // artifacts inside the button area. - GList* selected = g_list_find(menu_item->all_widgets, - menu_item->currently_selected_button); - if (selected) { - gtk_custom_menu_item_expose_button(widget, event, selected); - } - - return TRUE; -} - -static void gtk_custom_menu_item_select(GtkItem* item) { - GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(item); - - // When we are selected, the only thing we do is clear information from - // previous selections. Actual selection of a button is done either in the - // "mouse-motion-event" or is manually set from GtkCustomMenu's overridden - // "move-current" handler. - custom_item->previously_selected_button = NULL; - - gtk_widget_queue_draw(GTK_WIDGET(item)); -} - -static void gtk_custom_menu_item_deselect(GtkItem* item) { - GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(item); - - // When we are deselected, we store the item that was currently selected so - // that it can be acted on. Menu items are first deselected before they are - // activated. - custom_item->previously_selected_button = - custom_item->currently_selected_button; - if (custom_item->currently_selected_button) - set_selected(custom_item, NULL); - - gtk_widget_queue_draw(GTK_WIDGET(item)); -} - -static void gtk_custom_menu_item_activate(GtkMenuItem* menu_item) { - GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item); - - // We look at |previously_selected_button| because by the time we've been - // activated, we've already gone through our deselect handler. - if (custom_item->previously_selected_button) { - gpointer id_ptr = g_object_get_data( - G_OBJECT(custom_item->previously_selected_button), "command-id"); - if (id_ptr != NULL) { - int command_id = GPOINTER_TO_INT(id_ptr); - g_signal_emit(custom_item, custom_menu_item_signals[BUTTON_PUSHED], 0, - command_id); - set_selected(custom_item, NULL); - } - } -} - -GtkWidget* gtk_custom_menu_item_new(const char* title) { - GtkCustomMenuItem* item = GTK_CUSTOM_MENU_ITEM( - g_object_new(GTK_TYPE_CUSTOM_MENU_ITEM, NULL)); - gtk_label_set_text(GTK_LABEL(item->label), title); - return GTK_WIDGET(item); -} - -GtkWidget* gtk_custom_menu_item_add_button(GtkCustomMenuItem* menu_item, - int command_id) { - GtkWidget* button = gtk_button_new(); - g_object_set_data(G_OBJECT(button), "command-id", - GINT_TO_POINTER(command_id)); - gtk_box_pack_start(GTK_BOX(menu_item->hbox), button, FALSE, FALSE, 0); - gtk_widget_show(button); - - menu_item->all_widgets = g_list_append(menu_item->all_widgets, button); - menu_item->button_widgets = g_list_append(menu_item->button_widgets, button); - - return button; -} - -GtkWidget* gtk_custom_menu_item_add_button_label(GtkCustomMenuItem* menu_item, - int command_id) { - GtkWidget* button = gtk_button_new_with_label(""); - g_object_set_data(G_OBJECT(button), "command-id", - GINT_TO_POINTER(command_id)); - gtk_box_pack_start(GTK_BOX(menu_item->hbox), button, FALSE, FALSE, 0); - g_signal_connect(button, "notify::label", - G_CALLBACK(on_button_label_set), NULL); - gtk_widget_show(button); - - menu_item->all_widgets = g_list_append(menu_item->all_widgets, button); - - return button; -} - -void gtk_custom_menu_item_add_space(GtkCustomMenuItem* menu_item) { - GtkWidget* fixed = gtk_fixed_new(); - gtk_widget_set_size_request(fixed, 5, -1); - - gtk_box_pack_start(GTK_BOX(menu_item->hbox), fixed, FALSE, FALSE, 0); - gtk_widget_show(fixed); - - menu_item->all_widgets = g_list_append(menu_item->all_widgets, fixed); -} - -void gtk_custom_menu_item_receive_motion_event(GtkCustomMenuItem* menu_item, - gdouble x, gdouble y) { - GtkWidget* new_selected_widget = NULL; - GList* current = menu_item->button_widgets; - for (; current != NULL; current = current->next) { - GtkWidget* current_widget = GTK_WIDGET(current->data); - GtkAllocation alloc; - gtk_widget_get_allocation(current_widget, &alloc); - int offset_x, offset_y; - gtk_widget_translate_coordinates(current_widget, GTK_WIDGET(menu_item), - 0, 0, &offset_x, &offset_y); - if (x >= offset_x && x < (offset_x + alloc.width) && - y >= offset_y && y < (offset_y + alloc.height)) { - new_selected_widget = current_widget; - break; - } - } - - set_selected(menu_item, new_selected_widget); -} - -gboolean gtk_custom_menu_item_handle_move(GtkCustomMenuItem* menu_item, - GtkMenuDirectionType direction) { - GtkWidget* current = menu_item->currently_selected_button; - if (menu_item->button_widgets && current) { - switch (direction) { - case GTK_MENU_DIR_PREV: { - if (g_list_first(menu_item->button_widgets)->data == current) - return FALSE; - - set_selected(menu_item, GTK_WIDGET(g_list_previous(g_list_find( - menu_item->button_widgets, current))->data)); - break; - } - case GTK_MENU_DIR_NEXT: { - if (g_list_last(menu_item->button_widgets)->data == current) - return FALSE; - - set_selected(menu_item, GTK_WIDGET(g_list_next(g_list_find( - menu_item->button_widgets, current))->data)); - break; - } - default: - break; - } - } - - return TRUE; -} - -void gtk_custom_menu_item_select_item_by_direction( - GtkCustomMenuItem* menu_item, GtkMenuDirectionType direction) { - menu_item->previously_selected_button = NULL; - - // If we're just told to be selected by the menu system, select the first - // item. - if (menu_item->button_widgets) { - switch (direction) { - case GTK_MENU_DIR_PREV: { - GtkWidget* last_button = - GTK_WIDGET(g_list_last(menu_item->button_widgets)->data); - if (last_button) - set_selected(menu_item, last_button); - break; - } - case GTK_MENU_DIR_NEXT: { - GtkWidget* first_button = - GTK_WIDGET(g_list_first(menu_item->button_widgets)->data); - if (first_button) - set_selected(menu_item, first_button); - break; - } - default: - break; - } - } - - gtk_widget_queue_draw(GTK_WIDGET(menu_item)); -} - -gboolean gtk_custom_menu_item_is_in_clickable_region( - GtkCustomMenuItem* menu_item) { - return menu_item->currently_selected_button != NULL; -} - -gboolean gtk_custom_menu_item_try_no_dismiss_command( - GtkCustomMenuItem* menu_item) { - GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item); - gboolean activated = TRUE; - - // We work with |currently_selected_button| instead of - // |previously_selected_button| since we haven't been "deselect"ed yet. - gpointer id_ptr = g_object_get_data( - G_OBJECT(custom_item->currently_selected_button), "command-id"); - if (id_ptr != NULL) { - int command_id = GPOINTER_TO_INT(id_ptr); - g_signal_emit(custom_item, custom_menu_item_signals[TRY_BUTTON_PUSHED], 0, - command_id, &activated); - } - - return activated; -} - -void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item, - GtkCallback callback, - gpointer callback_data) { - // Even though we're filtering |all_widgets| on GTK_IS_BUTTON(), this isn't - // equivalent to |button_widgets| because we also want the button-labels. - for (GList* i = menu_item->all_widgets; i && GTK_IS_BUTTON(i->data); - i = g_list_next(i)) { - if (GTK_IS_BUTTON(i->data)) { - callback(GTK_WIDGET(i->data), callback_data); - } - } -} diff --git a/chrome/browser/ui/gtk/gtk_custom_menu_item.h b/chrome/browser/ui/gtk/gtk_custom_menu_item.h deleted file mode 100644 index 46e5cf721e9b..000000000000 --- a/chrome/browser/ui/gtk/gtk_custom_menu_item.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_ITEM_H_ -#define CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_ITEM_H_ - -// GtkCustomMenuItem is a GtkMenuItem subclass that has buttons in it and acts -// to support this. GtkCustomMenuItems only render properly when put in a -// GtkCustomMenu; there's a lot of collaboration between these two classes -// necessary to work around how gtk normally does menus. -// -// We can't rely on the normal event infrastructure. While a menu is up, the -// GtkMenu has a grab on all events. Instead of trying to pump events through -// the normal channels, we have the GtkCustomMenu selectively forward mouse -// motion through a back channel. The GtkCustomMenu only listens for button -// press information so it can block the effects of the click if the cursor -// isn't in a button in the menu item. -// -// A GtkCustomMenuItem doesn't try to take these signals and forward them to -// the buttons it owns. The GtkCustomMenu class keeps track of which button is -// selected (due to key events and mouse movement) and otherwise acts like a -// normal GtkItem. The buttons are only for sizing and rendering; they don't -// respond to events. Instead, when the GtkCustomMenuItem is activated by the -// GtkMenu, it uses which button was selected as a signal of what to do. -// -// Users should connect to the "button-pushed" signal to be notified when a -// button was pushed. We don't go through the normal "activate" signal because -// we need to communicate additional information, namely which button was -// activated. - -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_CUSTOM_MENU_ITEM \ - (gtk_custom_menu_item_get_type()) -#define GTK_CUSTOM_MENU_ITEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_CUSTOM_MENU_ITEM, \ - GtkCustomMenuItem)) -#define GTK_CUSTOM_MENU_ITEM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_CUSTOM_MENU_ITEM, \ - GtkCustomMenuItemClass)) -#define GTK_IS_CUSTOM_MENU_ITEM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CUSTOM_MENU_ITEM)) -#define GTK_IS_CUSTOM_MENU_ITEM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CUSTOM_MENU_ITEM)) -#define GTK_CUSTOM_MENU_ITEM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CUSTOM_MENU_ITEM, \ - GtkCustomMenuItemClass)) - -typedef struct _GtkCustomMenuItem GtkCustomMenuItem; -typedef struct _GtkCustomMenuItemClass GtkCustomMenuItemClass; - -struct _GtkCustomMenuItem { - GtkMenuItem menu_item; - - // Container for button widgets. - GtkWidget* hbox; - - // Label on left side of menu item. - GtkWidget* label; - - // List of all widgets we added. Used to find the leftmost and rightmost - // continuous buttons. - GList* all_widgets; - - // Possible button widgets. Used for keyboard navigation. - GList* button_widgets; - - // The widget that currently has highlight. - GtkWidget* currently_selected_button; - - // The widget that was selected *before* |currently_selected_button|. Why do - // we hang on to this? Because the menu system sends us a deselect signal - // right before activating us. We need to listen to deselect since that's - // what we receive when the mouse cursor leaves us entirely. - GtkWidget* previously_selected_button; -}; - -struct _GtkCustomMenuItemClass { - GtkMenuItemClass parent_class; -}; - -GType gtk_custom_menu_item_get_type(void) G_GNUC_CONST; -GtkWidget* gtk_custom_menu_item_new(const char* title); - -// Adds a button to our list of items in the |hbox|. -GtkWidget* gtk_custom_menu_item_add_button(GtkCustomMenuItem* menu_item, - int command_id); - -// Adds a button to our list of items in the |hbox|, but that isn't part of -// |button_widgets| to prevent it from being activatable. -GtkWidget* gtk_custom_menu_item_add_button_label(GtkCustomMenuItem* menu_item, - int command_id); - -// Adds a vertical space in the |hbox|. -void gtk_custom_menu_item_add_space(GtkCustomMenuItem* menu_item); - -// Receives a motion event from the GtkCustomMenu that contains us. We can't -// just subscribe to motion-event or the individual widget enter/leave events -// because the top level GtkMenu has an event grab. -void gtk_custom_menu_item_receive_motion_event(GtkCustomMenuItem* menu_item, - gdouble x, gdouble y); - -// Notification that the menu got a cursor key event. Used to move up/down -// within the menu buttons. Returns TRUE to stop the default signal handler -// from running. -gboolean gtk_custom_menu_item_handle_move(GtkCustomMenuItem* menu_item, - GtkMenuDirectionType direction); - -// Because we only get a generic "selected" signal when we've changed, we need -// to have a way for the GtkCustomMenu to tell us that we were just -// selected. -void gtk_custom_menu_item_select_item_by_direction( - GtkCustomMenuItem* menu_item, GtkMenuDirectionType direction); - -// Whether we are currently hovering over a clickable region on the menu -// item. Used by GtkCustomMenu to determine whether it should discard click -// events. -gboolean gtk_custom_menu_item_is_in_clickable_region( - GtkCustomMenuItem* menu_item); - -// If the button is released while the |currently_selected_button| isn't -// supposed to dismiss the menu, this signals to our listeners that we want to -// run this command if it doesn't dismiss the menu. Returns TRUE if we acted -// on this button click (and should prevent the normal GtkMenu machinery from -// firing an "activate" signal). -gboolean gtk_custom_menu_item_try_no_dismiss_command( - GtkCustomMenuItem* menu_item); - -// Calls |callback| with every button and button-label in the container. -void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item, - GtkCallback callback, - gpointer callback_data); - -G_END_DECLS - -#endif // CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_ITEM_H_ diff --git a/chrome/browser/ui/gtk/gtk_util.cc b/chrome/browser/ui/gtk/gtk_util.cc deleted file mode 100644 index b24c375e2c11..000000000000 --- a/chrome/browser/ui/gtk/gtk_util.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/gtk/gtk_util.h" - -#include - -#include "base/logging.h" - -namespace gtk_util { - -namespace { - -const char kBoldLabelMarkup[] = "%s"; - -// Returns the approximate number of characters that can horizontally fit in -// |pixel_width| pixels. -int GetCharacterWidthForPixels(GtkWidget* widget, int pixel_width) { - DCHECK(gtk_widget_get_realized(widget)) - << " widget must be realized to compute font metrics correctly"; - - PangoContext* context = gtk_widget_create_pango_context(widget); - GtkStyle* style = gtk_widget_get_style(widget); - PangoFontMetrics* metrics = pango_context_get_metrics(context, - style->font_desc, pango_context_get_language(context)); - - // This technique (max of char and digit widths) matches the code in - // gtklabel.c. - int char_width = pixel_width * PANGO_SCALE / - std::max(pango_font_metrics_get_approximate_char_width(metrics), - pango_font_metrics_get_approximate_digit_width(metrics)); - - pango_font_metrics_unref(metrics); - g_object_unref(context); - - return char_width; -} - -void OnLabelRealize(GtkWidget* label, gpointer pixel_width) { - gtk_label_set_width_chars( - GTK_LABEL(label), - GetCharacterWidthForPixels(label, GPOINTER_TO_INT(pixel_width))); -} - -} // namespace - -GtkWidget* LeftAlignMisc(GtkWidget* misc) { - gtk_misc_set_alignment(GTK_MISC(misc), 0, 0.5); - return misc; -} - -GtkWidget* CreateBoldLabel(const std::string& text) { - GtkWidget* label = gtk_label_new(NULL); - char* markup = g_markup_printf_escaped(kBoldLabelMarkup, text.c_str()); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - return LeftAlignMisc(label); -} - -void SetAlwaysShowImage(GtkWidget* image_menu_item) { - gtk_image_menu_item_set_always_show_image( - GTK_IMAGE_MENU_ITEM(image_menu_item), TRUE); -} - -bool IsWidgetAncestryVisible(GtkWidget* widget) { - GtkWidget* parent = widget; - while (parent && gtk_widget_get_visible(parent)) - parent = gtk_widget_get_parent(parent); - return !parent; -} - -void SetLabelWidth(GtkWidget* label, int pixel_width) { - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - - // Do the simple thing in LTR because the bug only affects right-aligned - // text. Also, when using the workaround, the label tries to maintain - // uniform line-length, which we don't really want. - if (gtk_widget_get_direction(label) == GTK_TEXT_DIR_LTR) { - gtk_widget_set_size_request(label, pixel_width, -1); - } else { - // The label has to be realized before we can adjust its width. - if (gtk_widget_get_realized(label)) { - OnLabelRealize(label, GINT_TO_POINTER(pixel_width)); - } else { - g_signal_connect(label, "realize", G_CALLBACK(OnLabelRealize), - GINT_TO_POINTER(pixel_width)); - } - } -} - -} // namespace gtk_util diff --git a/chrome/browser/ui/gtk/gtk_util.h b/chrome/browser/ui/gtk/gtk_util.h deleted file mode 100644 index 2434a386e78a..000000000000 --- a/chrome/browser/ui/gtk/gtk_util.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_GTK_GTK_UTIL_H_ -#define CHROME_BROWSER_UI_GTK_GTK_UTIL_H_ - -#include -#include - -namespace gtk_util { - -// Left-align the given GtkMisc and return the same pointer. -GtkWidget* LeftAlignMisc(GtkWidget* misc); - -// Create a left-aligned label with the given text in bold. -GtkWidget* CreateBoldLabel(const std::string& text); - -// Show the image for the given menu item, even if the user's default is to not -// show images. Only to be used for favicons or other menus where the image is -// crucial to its functionality. -void SetAlwaysShowImage(GtkWidget* image_menu_item); - -// Checks whether a widget is actually visible, i.e. whether it and all its -// ancestors up to its toplevel are visible. -bool IsWidgetAncestryVisible(GtkWidget* widget); - -// Sets the given label's size request to |pixel_width|. This will cause the -// label to wrap if it needs to. The reason for this function is that some -// versions of GTK mis-align labels that have a size request and line wrapping, -// and this function hides the complexity of the workaround. -void SetLabelWidth(GtkWidget* label, int pixel_width); - -} // namespace gtk_util - -#endif // CHROME_BROWSER_UI_GTK_GTK_UTIL_H_ diff --git a/chrome/browser/ui/gtk/gtk_window_util.cc b/chrome/browser/ui/gtk/gtk_window_util.cc deleted file mode 100644 index 09d2624b5df2..000000000000 --- a/chrome/browser/ui/gtk/gtk_window_util.cc +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/gtk/gtk_window_util.h" - -#include -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" - -using content::RenderWidgetHost; -using content::WebContents; - -namespace gtk_window_util { - -const int kFrameBorderThickness = 4; -const int kResizeAreaCornerSize = 16; - -// Keep track of the last click time and the last click position so we can -// filter out extra GDK_BUTTON_PRESS events when a double click happens. -static guint32 last_click_time; -static int last_click_x; -static int last_click_y; - -// Performs Cut/Copy/Paste operation on the |window|. -// If the current render view is focused, then just call the specified |method| -// against the current render view host, otherwise emit the specified |signal| -// against the focused widget. -// TODO(suzhe): This approach does not work for plugins. -void DoCutCopyPaste(GtkWindow* window, - WebContents* web_contents, - void (RenderWidgetHost::*method)(), - const char* signal) { - GtkWidget* widget = gtk_window_get_focus(window); - if (widget == NULL) - return; // Do nothing if no focused widget. - - if (web_contents && - widget == web_contents->GetView()->GetContentNativeView()) { - (web_contents->GetRenderViewHost()->*method)(); - } else { - guint id; - if ((id = g_signal_lookup(signal, G_OBJECT_TYPE(widget))) != 0) - g_signal_emit(widget, id, 0); - } -} - -void DoCut(GtkWindow* window, WebContents* web_contents) { - DoCutCopyPaste(window, web_contents, - &RenderWidgetHost::Cut, "cut-clipboard"); -} - -void DoCopy(GtkWindow* window, WebContents* web_contents) { - DoCutCopyPaste(window, web_contents, - &RenderWidgetHost::Copy, "copy-clipboard"); -} - -void DoPaste(GtkWindow* window, WebContents* web_contents) { - DoCutCopyPaste(window, web_contents, - &RenderWidgetHost::Paste, "paste-clipboard"); -} - -// Ubuntu patches their version of GTK+ so that there is always a -// gripper in the bottom right corner of the window. We dynamically -// look up this symbol because it's a non-standard Ubuntu extension to -// GTK+. We always need to disable this feature since we can't -// communicate this to WebKit easily. -typedef void (*gtk_window_set_has_resize_grip_func)(GtkWindow*, gboolean); -gtk_window_set_has_resize_grip_func gtk_window_set_has_resize_grip_sym; - -void DisableResizeGrip(GtkWindow* window) { - static bool resize_grip_looked_up = false; - if (!resize_grip_looked_up) { - resize_grip_looked_up = true; - gtk_window_set_has_resize_grip_sym = - reinterpret_cast( - dlsym(NULL, "gtk_window_set_has_resize_grip")); - } - if (gtk_window_set_has_resize_grip_sym) - gtk_window_set_has_resize_grip_sym(window, FALSE); -} - -GdkCursorType GdkWindowEdgeToGdkCursorType(GdkWindowEdge edge) { - switch (edge) { - case GDK_WINDOW_EDGE_NORTH_WEST: - return GDK_TOP_LEFT_CORNER; - case GDK_WINDOW_EDGE_NORTH: - return GDK_TOP_SIDE; - case GDK_WINDOW_EDGE_NORTH_EAST: - return GDK_TOP_RIGHT_CORNER; - case GDK_WINDOW_EDGE_WEST: - return GDK_LEFT_SIDE; - case GDK_WINDOW_EDGE_EAST: - return GDK_RIGHT_SIDE; - case GDK_WINDOW_EDGE_SOUTH_WEST: - return GDK_BOTTOM_LEFT_CORNER; - case GDK_WINDOW_EDGE_SOUTH: - return GDK_BOTTOM_SIDE; - case GDK_WINDOW_EDGE_SOUTH_EAST: - return GDK_BOTTOM_RIGHT_CORNER; - default: - NOTREACHED(); - } - return GDK_LAST_CURSOR; -} - -bool BoundsMatchMonitorSize(GtkWindow* window, gfx::Rect bounds) { - // A screen can be composed of multiple monitors. - GdkScreen* screen = gtk_window_get_screen(window); - GdkRectangle monitor_size; - - if (gtk_widget_get_realized(GTK_WIDGET(window))) { - // |window| has been realized. - gint monitor_num = gdk_screen_get_monitor_at_window(screen, - gtk_widget_get_window(GTK_WIDGET(window))); - gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor_size); - return bounds.size() == gfx::Size(monitor_size.width, monitor_size.height); - } - - // Make sure the window doesn't match any monitor size. We compare against - // all monitors because we don't know which monitor the window is going to - // open on before window realized. - gint num_monitors = gdk_screen_get_n_monitors(screen); - for (gint i = 0; i < num_monitors; ++i) { - GdkRectangle monitor_size; - gdk_screen_get_monitor_geometry(screen, i, &monitor_size); - if (bounds.size() == gfx::Size(monitor_size.width, monitor_size.height)) - return true; - } - return false; -} - -bool HandleTitleBarLeftMousePress( - GtkWindow* window, - const gfx::Rect& bounds, - GdkEventButton* event) { - // We want to start a move when the user single clicks, but not start a - // move when the user double clicks. However, a double click sends the - // following GDK events: GDK_BUTTON_PRESS, GDK_BUTTON_RELEASE, - // GDK_BUTTON_PRESS, GDK_2BUTTON_PRESS, GDK_BUTTON_RELEASE. If we - // start a gtk_window_begin_move_drag on the second GDK_BUTTON_PRESS, - // the call to gtk_window_maximize fails. To work around this, we - // keep track of the last click and if it's going to be a double click, - // we don't call gtk_window_begin_move_drag. - DCHECK_EQ(event->type, GDK_BUTTON_PRESS); - DCHECK_EQ(event->button, 1); - - static GtkSettings* settings = gtk_settings_get_default(); - gint double_click_time = 250; - gint double_click_distance = 5; - g_object_get(G_OBJECT(settings), - "gtk-double-click-time", &double_click_time, - "gtk-double-click-distance", &double_click_distance, - NULL); - - guint32 click_time = event->time - last_click_time; - int click_move_x = abs(event->x - last_click_x); - int click_move_y = abs(event->y - last_click_y); - - last_click_time = event->time; - last_click_x = static_cast(event->x); - last_click_y = static_cast(event->y); - - if (click_time > static_cast(double_click_time) || - click_move_x > double_click_distance || - click_move_y > double_click_distance) { - // Ignore drag requests if the window is the size of the screen. - // We do this to avoid triggering fullscreen mode in metacity - // (without the --no-force-fullscreen flag) and in compiz (with - // Legacy Fullscreen Mode enabled). - if (!BoundsMatchMonitorSize(window, bounds)) { - gtk_window_begin_move_drag(window, event->button, - static_cast(event->x_root), - static_cast(event->y_root), - event->time); - } - return TRUE; - } - return FALSE; -} - -void UnMaximize(GtkWindow* window, - const gfx::Rect& bounds, - const gfx::Rect& restored_bounds) { - gtk_window_unmaximize(window); - - // It can happen that you end up with a window whose restore size is the same - // as the size of the screen, so unmaximizing it merely remaximizes it due to - // the same WM feature that SetWindowSize() works around. We try to detect - // this and resize the window to work around the issue. - if (bounds.size() == restored_bounds.size()) - gtk_window_resize(window, bounds.width(), bounds.height() - 1); -} - -void SetWindowCustomClass(GtkWindow* window, const std::string& wmclass) { - gtk_window_set_wmclass(window, - wmclass.c_str(), - gdk_get_program_class()); - - // Set WM_WINDOW_ROLE for session management purposes. - // See http://tronche.com/gui/x/icccm/sec-5.html . - gtk_window_set_role(window, wmclass.c_str()); -} - -void SetWindowSize(GtkWindow* window, const gfx::Size& size) { - gfx::Size new_size = size; - gint current_width = 0; - gint current_height = 0; - gtk_window_get_size(window, ¤t_width, ¤t_height); - GdkRectangle size_with_decorations = {0}; - GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); - if (gdk_window) { - gdk_window_get_frame_extents(gdk_window, - &size_with_decorations); - } - - if (current_width == size_with_decorations.width && - current_height == size_with_decorations.height) { - // Make sure the window doesn't match any monitor size. We compare against - // all monitors because we don't know which monitor the window is going to - // open on (the WM decides that). - GdkScreen* screen = gtk_window_get_screen(window); - gint num_monitors = gdk_screen_get_n_monitors(screen); - for (gint i = 0; i < num_monitors; ++i) { - GdkRectangle monitor_size; - gdk_screen_get_monitor_geometry(screen, i, &monitor_size); - if (gfx::Size(monitor_size.width, monitor_size.height) == size) { - gtk_window_resize(window, size.width(), size.height() - 1); - return; - } - } - } else { - // gtk_window_resize is the size of the window not including decorations, - // but we are given the |size| including window decorations. - if (size_with_decorations.width > current_width) { - new_size.set_width(size.width() - size_with_decorations.width + - current_width); - } - if (size_with_decorations.height > current_height) { - new_size.set_height(size.height() - size_with_decorations.height + - current_height); - } - } - - gtk_window_resize(window, new_size.width(), new_size.height()); -} - -bool GetWindowEdge(const gfx::Size& window_size, - int top_edge_inset, - int x, - int y, - GdkWindowEdge* edge) { - gfx::Rect middle(window_size); - middle.Inset(kFrameBorderThickness, - kFrameBorderThickness - top_edge_inset, - kFrameBorderThickness, - kFrameBorderThickness); - if (middle.Contains(x, y)) - return false; - - gfx::Rect north(0, 0, window_size.width(), - kResizeAreaCornerSize - top_edge_inset); - gfx::Rect west(0, 0, kResizeAreaCornerSize, window_size.height()); - gfx::Rect south(0, window_size.height() - kResizeAreaCornerSize, - window_size.width(), kResizeAreaCornerSize); - gfx::Rect east(window_size.width() - kResizeAreaCornerSize, 0, - kResizeAreaCornerSize, window_size.height()); - - if (north.Contains(x, y)) { - if (west.Contains(x, y)) - *edge = GDK_WINDOW_EDGE_NORTH_WEST; - else if (east.Contains(x, y)) - *edge = GDK_WINDOW_EDGE_NORTH_EAST; - else - *edge = GDK_WINDOW_EDGE_NORTH; - } else if (south.Contains(x, y)) { - if (west.Contains(x, y)) - *edge = GDK_WINDOW_EDGE_SOUTH_WEST; - else if (east.Contains(x, y)) - *edge = GDK_WINDOW_EDGE_SOUTH_EAST; - else - *edge = GDK_WINDOW_EDGE_SOUTH; - } else { - if (west.Contains(x, y)) - *edge = GDK_WINDOW_EDGE_WEST; - else if (east.Contains(x, y)) - *edge = GDK_WINDOW_EDGE_EAST; - else - return false; // The cursor must be outside the window. - } - return true; -} - -} // namespace gtk_window_util diff --git a/chrome/browser/ui/gtk/gtk_window_util.h b/chrome/browser/ui/gtk/gtk_window_util.h deleted file mode 100644 index d4904ca8e947..000000000000 --- a/chrome/browser/ui/gtk/gtk_window_util.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_GTK_GTK_WINDOW_UTIL_H_ -#define CHROME_BROWSER_UI_GTK_GTK_WINDOW_UTIL_H_ - -#include -#include -#include "ui/gfx/rect.h" - -namespace content { -class WebContents; -} - -namespace gtk_window_util { - -// 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. -extern const int kFrameBorderThickness; -// 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. -extern const int kResizeAreaCornerSize; - -// Performs Cut/Copy/Paste operation on the |window|'s |web_contents|. -void DoCut(GtkWindow* window, content::WebContents* web_contents); -void DoCopy(GtkWindow* window, content::WebContents* web_contents); -void DoPaste(GtkWindow* window, content::WebContents* web_contents); - -// Ubuntu patches their version of GTK+ to that there is always a -// gripper in the bottom right corner of the window. We always need to -// disable this feature since we can't communicate this to WebKit easily. -void DisableResizeGrip(GtkWindow* window); - -// Returns the resize cursor corresponding to the window |edge|. -GdkCursorType GdkWindowEdgeToGdkCursorType(GdkWindowEdge edge); - -// Returns |true| if the window bounds match the monitor size. -bool BoundsMatchMonitorSize(GtkWindow* window, gfx::Rect bounds); - -bool HandleTitleBarLeftMousePress(GtkWindow* window, - const gfx::Rect& bounds, - GdkEventButton* event); - -// Request the underlying window to unmaximize. Also tries to work around -// a window manager "feature" that can prevent this in some edge cases. -void UnMaximize(GtkWindow* window, - const gfx::Rect& bounds, - const gfx::Rect& restored_bounds); - -// Set a custom WM_CLASS for a window. -void SetWindowCustomClass(GtkWindow* window, const std::string& wmclass); - -// A helper method for setting the GtkWindow size that should be used in place -// of calling gtk_window_resize directly. This is done to avoid a WM "feature" -// where setting the window size to the monitor size causes the WM to set the -// EWMH for full screen mode. -void SetWindowSize(GtkWindow* window, const gfx::Size& size); - -// 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. -// |top_edge_inset| specifies how much smaller (in px) than the default edge -// size the top edge should be, used by browser windows to make it easier to -// move the window since a lot of title bar space is taken by the tabs. -bool GetWindowEdge(const gfx::Size& window_size, - int top_edge_inset, - int x, - int y, - GdkWindowEdge* edge); - -} // namespace gtk_window_util - -#endif // CHROME_BROWSER_UI_GTK_GTK_WINDOW_UTIL_H_ diff --git a/chrome/browser/ui/gtk/menu_gtk.cc b/chrome/browser/ui/gtk/menu_gtk.cc deleted file mode 100644 index 1fde1ba39b15..000000000000 --- a/chrome/browser/ui/gtk/menu_gtk.cc +++ /dev/null @@ -1,879 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/gtk/menu_gtk.h" - -#include - -#include "base/bind.h" -#include "base/i18n/rtl.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/stl_util.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/gtk/event_utils.h" -#include "chrome/browser/ui/gtk/gtk_custom_menu.h" -#include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" -#include "chrome/browser/ui/gtk/gtk_util.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/accelerators/menu_label_accelerator_util_linux.h" -#include "ui/base/accelerators/platform_accelerator_gtk.h" -#include "ui/base/models/button_menu_item_model.h" -#include "ui/base/models/menu_model.h" -#include "ui/base/window_open_disposition.h" -#include "ui/gfx/gtk_util.h" -#include "ui/gfx/image/image.h" - -bool MenuGtk::block_activation_ = false; - -namespace { - -// Sets the ID of a menu item. -void SetMenuItemID(GtkWidget* menu_item, int menu_id) { - DCHECK_GE(menu_id, 0); - - // Add 1 to the menu_id to avoid setting zero (null) to "menu-id". - g_object_set_data(G_OBJECT(menu_item), "menu-id", - GINT_TO_POINTER(menu_id + 1)); -} - -// Gets the ID of a menu item. -// Returns true if the menu item has an ID. -bool GetMenuItemID(GtkWidget* menu_item, int* menu_id) { - gpointer id_ptr = g_object_get_data(G_OBJECT(menu_item), "menu-id"); - if (id_ptr != NULL) { - *menu_id = GPOINTER_TO_INT(id_ptr) - 1; - return true; - } - - return false; -} - -ui::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) { - return reinterpret_cast( - g_object_get_data(G_OBJECT(menu_item), "model")); -} - -void SetUpButtonShowHandler(GtkWidget* button, - ui::ButtonMenuItemModel* model, - int index) { - g_object_set_data(G_OBJECT(button), "button-model", - model); - g_object_set_data(G_OBJECT(button), "button-model-id", - GINT_TO_POINTER(index)); -} - -void OnSubmenuShowButtonImage(GtkWidget* widget, GtkButton* button) { - MenuGtk::Delegate* delegate = reinterpret_cast( - g_object_get_data(G_OBJECT(button), "menu-gtk-delegate")); - int icon_idr = GPOINTER_TO_INT(g_object_get_data( - G_OBJECT(button), "button-image-idr")); - - GtkIconSet* icon_set = delegate->GetIconSetForId(icon_idr); - if (icon_set) { - gtk_button_set_image( - button, gtk_image_new_from_icon_set(icon_set, - GTK_ICON_SIZE_MENU)); - } -} - -void SetupImageIcon(GtkWidget* button, - GtkWidget* menu, - int icon_idr, - MenuGtk::Delegate* menu_gtk_delegate) { - g_object_set_data(G_OBJECT(button), "button-image-idr", - GINT_TO_POINTER(icon_idr)); - g_object_set_data(G_OBJECT(button), "menu-gtk-delegate", - menu_gtk_delegate); - - g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShowButtonImage), button); -} - -// Popup menus may get squished if they open up too close to the bottom of the -// screen. This function takes the size of the screen, the size of the menu, -// an optional widget, the Y position of the mouse click, and adjusts the popup -// menu's Y position to make it fit if it's possible to do so. -// Returns the new Y position of the popup menu. -int CalculateMenuYPosition(const GdkRectangle* screen_rect, - const GtkRequisition* menu_req, - GtkWidget* widget, const int y) { - CHECK(screen_rect); - CHECK(menu_req); - // If the menu would run off the bottom of the screen, and there is enough - // screen space upwards to accommodate the menu, then pop upwards. If there - // is a widget, then also move the anchor point to the top of the widget - // rather than the bottom. - const int screen_top = screen_rect->y; - const int screen_bottom = screen_rect->y + screen_rect->height; - const int menu_bottom = y + menu_req->height; - int alternate_y = y - menu_req->height; - if (widget) { - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - alternate_y -= allocation.height; - } - if (menu_bottom >= screen_bottom && alternate_y >= screen_top) - return alternate_y; - return y; -} - -} // namespace - -bool MenuGtk::Delegate::AlwaysShowIconForCmd(int command_id) const { - return false; -} - -GtkIconSet* MenuGtk::Delegate::GetIconSetForId(int idr) { return NULL; } - -GtkWidget* MenuGtk::Delegate::GetDefaultImageForLabel( - const std::string& label) { - const char* stock = NULL; - if (label == "New") - stock = GTK_STOCK_NEW; - else if (label == "Close") - stock = GTK_STOCK_CLOSE; - else if (label == "Save As") - stock = GTK_STOCK_SAVE_AS; - else if (label == "Save") - stock = GTK_STOCK_SAVE; - else if (label == "Copy") - stock = GTK_STOCK_COPY; - else if (label == "Cut") - stock = GTK_STOCK_CUT; - else if (label == "Paste") - stock = GTK_STOCK_PASTE; - else if (label == "Delete") - stock = GTK_STOCK_DELETE; - else if (label == "Undo") - stock = GTK_STOCK_UNDO; - else if (label == "Redo") - stock = GTK_STOCK_REDO; - else if (label == "Search" || label == "Find") - stock = GTK_STOCK_FIND; - else if (label == "Select All") - stock = GTK_STOCK_SELECT_ALL; - else if (label == "Clear") - stock = GTK_STOCK_SELECT_ALL; - else if (label == "Back") - stock = GTK_STOCK_GO_BACK; - else if (label == "Forward") - stock = GTK_STOCK_GO_FORWARD; - else if (label == "Reload" || label == "Refresh") - stock = GTK_STOCK_REFRESH; - else if (label == "Print") - stock = GTK_STOCK_PRINT; - else if (label == "About") - stock = GTK_STOCK_ABOUT; - else if (label == "Quit") - stock = GTK_STOCK_QUIT; - else if (label == "Help") - stock = GTK_STOCK_HELP; - - return stock ? gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU) : NULL; -} - -GtkWidget* MenuGtk::Delegate::GetImageForCommandId(int command_id) const { - return NULL; -} - -MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, - ui::MenuModel* model, - bool is_menubar) - : delegate_(delegate), - model_(model), - is_menubar_(is_menubar), - dummy_accel_group_(gtk_accel_group_new()), - menu_(is_menubar ? gtk_menu_bar_new() : gtk_custom_menu_new()), - weak_factory_(this) { - DCHECK(model); - g_object_ref_sink(menu_); - ConnectSignalHandlers(); - BuildMenuFromModel(); -} - -MenuGtk::~MenuGtk() { - Cancel(); - - gtk_widget_destroy(menu_); - g_object_unref(menu_); - - g_object_unref(dummy_accel_group_); -} - -void MenuGtk::ConnectSignalHandlers() { - // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may - // take a long time or even start a nested message loop. - g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this); - g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this); - GtkWidget* toplevel_window = gtk_widget_get_toplevel(menu_); - signal_.Connect(toplevel_window, "focus-out-event", - G_CALLBACK(OnMenuFocusOutThunk), this); -} - -GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id, - const std::string& label) { - std::string converted_label = ui::ConvertAcceleratorsFromWindowsStyle(label); - GtkWidget* menu_item = BuildMenuItemWithLabel(converted_label, command_id); - return AppendMenuItem(command_id, menu_item); -} - -GtkWidget* MenuGtk::AppendMenuItemWithIcon(int command_id, - const std::string& label, - const gfx::Image& icon) { - std::string converted_label = ui::ConvertAcceleratorsFromWindowsStyle(label); - GtkWidget* menu_item = BuildMenuItemWithImage(converted_label, icon); - return AppendMenuItem(command_id, menu_item); -} - -GtkWidget* MenuGtk::AppendCheckMenuItemWithLabel(int command_id, - const std::string& label) { - std::string converted_label = ui::ConvertAcceleratorsFromWindowsStyle(label); - GtkWidget* menu_item = - gtk_check_menu_item_new_with_mnemonic(converted_label.c_str()); - return AppendMenuItem(command_id, menu_item); -} - -GtkWidget* MenuGtk::AppendSeparator() { - GtkWidget* menu_item = gtk_separator_menu_item_new(); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item); - return menu_item; -} - -GtkWidget* MenuGtk::InsertSeparator(int position) { - GtkWidget* menu_item = gtk_separator_menu_item_new(); - gtk_widget_show(menu_item); - gtk_menu_shell_insert(GTK_MENU_SHELL(menu_), menu_item, position); - return menu_item; -} - -GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) { - if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) && - GTK_IS_IMAGE_MENU_ITEM(menu_item)) - gtk_util::SetAlwaysShowImage(menu_item); - - return AppendMenuItemToMenu(command_id, NULL, menu_item, menu_, true); -} - -GtkWidget* MenuGtk::InsertMenuItem(int command_id, GtkWidget* menu_item, - int position) { - if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) && - GTK_IS_IMAGE_MENU_ITEM(menu_item)) - gtk_util::SetAlwaysShowImage(menu_item); - - return InsertMenuItemToMenu(command_id, NULL, menu_item, menu_, position, - true); -} - -GtkWidget* MenuGtk::AppendMenuItemToMenu(int index, - ui::MenuModel* model, - GtkWidget* menu_item, - GtkWidget* menu, - bool connect_to_activate) { - int children_count = g_list_length(GTK_MENU_SHELL(menu)->children); - return InsertMenuItemToMenu(index, model, menu_item, menu, - children_count, connect_to_activate); -} - -GtkWidget* MenuGtk::InsertMenuItemToMenu(int index, - ui::MenuModel* model, - GtkWidget* menu_item, - GtkWidget* menu, - int position, - bool connect_to_activate) { - SetMenuItemID(menu_item, index); - - // Native menu items do their own thing, so only selectively listen for the - // activate signal. - if (connect_to_activate) { - g_signal_connect(menu_item, "activate", - G_CALLBACK(OnMenuItemActivatedThunk), this); - } - - // AppendMenuItemToMenu is used both internally when we control menu creation - // from a model (where the model can choose to hide certain menu items), and - // with immediate commands which don't provide the option. - if (model) { - if (model->IsVisibleAt(index)) - gtk_widget_show(menu_item); - } else { - gtk_widget_show(menu_item); - } - gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menu_item, position); - return menu_item; -} - -void MenuGtk::PopupForWidget(GtkWidget* widget, int button, - guint32 event_time) { - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, - WidgetMenuPositionFunc, - widget, - button, event_time); -} - -void MenuGtk::PopupAsContext(const gfx::Point& point, guint32 event_time) { - // gtk_menu_popup doesn't like the "const" qualifier on point. - gfx::Point nonconst_point(point); - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, - PointMenuPositionFunc, &nonconst_point, - 3, event_time); -} - -void MenuGtk::PopupAsContextForStatusIcon(guint32 event_time, guint32 button, - GtkStatusIcon* icon) { - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, gtk_status_icon_position_menu, - icon, button, event_time); -} - -void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) { - PopupForWidget(widget, 0, gtk_get_current_event_time()); - gtk_menu_shell_select_first(GTK_MENU_SHELL(menu_), FALSE); -} - -void MenuGtk::Cancel() { - if (!is_menubar_) - gtk_menu_popdown(GTK_MENU(menu_)); -} - -void MenuGtk::UpdateMenu() { - gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this); -} - -GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label, - GtkWidget* image) { - GtkWidget* menu_item = - gtk_image_menu_item_new_with_mnemonic(label.c_str()); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image); - return menu_item; -} - -GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label, - const gfx::Image& icon) { - GtkWidget* menu_item = BuildMenuItemWithImage(label, - gtk_image_new_from_pixbuf(icon.ToGdkPixbuf())); - return menu_item; -} - -GtkWidget* MenuGtk::BuildMenuItemWithLabel(const std::string& label, - int command_id) { - GtkWidget* img = - delegate_ ? delegate_->GetImageForCommandId(command_id) : - MenuGtk::Delegate::GetDefaultImageForLabel(label); - return img ? BuildMenuItemWithImage(label, img) : - gtk_menu_item_new_with_mnemonic(label.c_str()); -} - -void MenuGtk::BuildMenuFromModel() { - BuildSubmenuFromModel(model_, menu_); -} - -void MenuGtk::BuildSubmenuFromModel(ui::MenuModel* model, GtkWidget* menu) { - std::map radio_groups; - GtkWidget* menu_item = NULL; - for (int i = 0; i < model->GetItemCount(); ++i) { - gfx::Image icon; - std::string label = ui::ConvertAcceleratorsFromWindowsStyle( - base::UTF16ToUTF8(model->GetLabelAt(i))); - bool connect_to_activate = true; - - switch (model->GetTypeAt(i)) { - case ui::MenuModel::TYPE_SEPARATOR: - menu_item = gtk_separator_menu_item_new(); - break; - - case ui::MenuModel::TYPE_CHECK: - menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str()); - break; - - case ui::MenuModel::TYPE_RADIO: { - std::map::iterator iter = - radio_groups.find(model->GetGroupIdAt(i)); - - if (iter == radio_groups.end()) { - menu_item = gtk_radio_menu_item_new_with_mnemonic( - NULL, label.c_str()); - radio_groups[model->GetGroupIdAt(i)] = menu_item; - } else { - menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget( - GTK_RADIO_MENU_ITEM(iter->second), label.c_str()); - } - break; - } - case ui::MenuModel::TYPE_BUTTON_ITEM: { - ui::ButtonMenuItemModel* button_menu_item_model = - model->GetButtonMenuItemAt(i); - menu_item = BuildButtonMenuItem(button_menu_item_model, menu); - connect_to_activate = false; - break; - } - case ui::MenuModel::TYPE_SUBMENU: - case ui::MenuModel::TYPE_COMMAND: { - int command_id = model->GetCommandIdAt(i); - if (model->GetIconAt(i, &icon)) - menu_item = BuildMenuItemWithImage(label, icon); - else - menu_item = BuildMenuItemWithLabel(label, command_id); - if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) && - GTK_IS_IMAGE_MENU_ITEM(menu_item)) { - gtk_util::SetAlwaysShowImage(menu_item); - } - break; - } - - default: - NOTREACHED(); - } - - if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) { - GtkWidget* submenu = gtk_menu_new(); - g_object_set_data(G_OBJECT(submenu), "menu-item", menu_item); - ui::MenuModel* submenu_model = model->GetSubmenuModelAt(i); - g_object_set_data(G_OBJECT(menu_item), "submenu-model", submenu_model); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu); - // We will populate the submenu on demand when shown. - g_signal_connect(submenu, "show", G_CALLBACK(OnSubMenuShowThunk), this); - g_signal_connect(submenu, "hide", G_CALLBACK(OnSubMenuHiddenThunk), this); - connect_to_activate = false; - } - - ui::Accelerator accelerator; - if (model->GetAcceleratorAt(i, &accelerator)) { - gtk_widget_add_accelerator(menu_item, - "activate", - dummy_accel_group_, - ui::GetGdkKeyCodeForAccelerator(accelerator), - ui::GetGdkModifierForAccelerator(accelerator), - GTK_ACCEL_VISIBLE); - } - - g_object_set_data(G_OBJECT(menu_item), "model", model); - AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate); - - menu_item = NULL; - } -} - -GtkWidget* MenuGtk::BuildButtonMenuItem(ui::ButtonMenuItemModel* model, - GtkWidget* menu) { - GtkWidget* menu_item = gtk_custom_menu_item_new( - ui::RemoveWindowsStyleAccelerators( - base::UTF16ToUTF8(model->label())).c_str()); - - // Set up the callback to the model for when it is clicked. - g_object_set_data(G_OBJECT(menu_item), "button-model", model); - g_signal_connect(menu_item, "button-pushed", - G_CALLBACK(OnMenuButtonPressedThunk), this); - g_signal_connect(menu_item, "try-button-pushed", - G_CALLBACK(OnMenuTryButtonPressedThunk), this); - - GtkSizeGroup* group = NULL; - for (int i = 0; i < model->GetItemCount(); ++i) { - GtkWidget* button = NULL; - - switch (model->GetTypeAt(i)) { - case ui::ButtonMenuItemModel::TYPE_SPACE: { - gtk_custom_menu_item_add_space(GTK_CUSTOM_MENU_ITEM(menu_item)); - break; - } - case ui::ButtonMenuItemModel::TYPE_BUTTON: { - button = gtk_custom_menu_item_add_button( - GTK_CUSTOM_MENU_ITEM(menu_item), - model->GetCommandIdAt(i)); - - int icon_idr; - if (model->GetIconAt(i, &icon_idr)) { - SetupImageIcon(button, menu, icon_idr, delegate_); - } else { - gtk_button_set_label( - GTK_BUTTON(button), - ui::RemoveWindowsStyleAccelerators( - base::UTF16ToUTF8(model->GetLabelAt(i))).c_str()); - } - - SetUpButtonShowHandler(button, model, i); - break; - } - case ui::ButtonMenuItemModel::TYPE_BUTTON_LABEL: { - button = gtk_custom_menu_item_add_button_label( - GTK_CUSTOM_MENU_ITEM(menu_item), - model->GetCommandIdAt(i)); - gtk_button_set_label( - GTK_BUTTON(button), - ui::RemoveWindowsStyleAccelerators( - base::UTF16ToUTF8(model->GetLabelAt(i))).c_str()); - SetUpButtonShowHandler(button, model, i); - break; - } - } - - if (button && model->PartOfGroup(i)) { - if (!group) - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - gtk_size_group_add_widget(group, button); - } - } - - if (group) - g_object_unref(group); - - return menu_item; -} - -void MenuGtk::OnMenuItemActivated(GtkWidget* menu_item) { - if (block_activation_) - return; - - ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item)); - - if (!model) { - // There won't be a model for "native" submenus like the "Input Methods" - // context menu. We don't need to handle activation messages for submenus - // anyway, so we can just return here. - DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))); - return; - } - - // The activate signal is sent to radio items as they get deselected; - // ignore it in this case. - if (GTK_IS_RADIO_MENU_ITEM(menu_item) && - !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) { - return; - } - - int id; - if (!GetMenuItemID(menu_item, &id)) - return; - - // The menu item can still be activated by hotkeys even if it is disabled. - if (model->IsEnabledAt(id)) - ExecuteCommand(model, id); -} - -void MenuGtk::OnMenuButtonPressed(GtkWidget* menu_item, int command_id) { - ui::ButtonMenuItemModel* model = - reinterpret_cast( - g_object_get_data(G_OBJECT(menu_item), "button-model")); - if (model && model->IsCommandIdEnabled(command_id)) { - if (delegate_) - delegate_->CommandWillBeExecuted(); - - model->ActivatedCommand(command_id); - } -} - -gboolean MenuGtk::OnMenuTryButtonPressed(GtkWidget* menu_item, - int command_id) { - gboolean pressed = FALSE; - ui::ButtonMenuItemModel* model = - reinterpret_cast( - g_object_get_data(G_OBJECT(menu_item), "button-model")); - if (model && - model->IsCommandIdEnabled(command_id) && - !model->DoesCommandIdDismissMenu(command_id)) { - if (delegate_) - delegate_->CommandWillBeExecuted(); - - model->ActivatedCommand(command_id); - pressed = TRUE; - } - - return pressed; -} - -// static -void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu, - int* x, - int* y, - gboolean* push_in, - void* void_widget) { - GtkWidget* widget = GTK_WIDGET(void_widget); - GtkRequisition menu_req; - - gtk_widget_size_request(GTK_WIDGET(menu), &menu_req); - - gdk_window_get_origin(gtk_widget_get_window(widget), x, y); - GdkScreen *screen = gtk_widget_get_screen(widget); - gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y); - - GdkRectangle screen_rect; - gdk_screen_get_monitor_geometry(screen, monitor, - &screen_rect); - - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - - if (!gtk_widget_get_has_window(widget)) { - *x += allocation.x; - *y += allocation.y; - } - *y += allocation.height; - - bool start_align = - !!g_object_get_data(G_OBJECT(widget), "left-align-popup"); - if (base::i18n::IsRTL()) - start_align = !start_align; - - if (!start_align) - *x += allocation.width - menu_req.width; - - *y = CalculateMenuYPosition(&screen_rect, &menu_req, widget, *y); - - *push_in = FALSE; -} - -// static -void MenuGtk::PointMenuPositionFunc(GtkMenu* menu, - int* x, - int* y, - gboolean* push_in, - gpointer userdata) { - *push_in = TRUE; - - gfx::Point* point = reinterpret_cast(userdata); - *x = point->x(); - *y = point->y(); - - GtkRequisition menu_req; - gtk_widget_size_request(GTK_WIDGET(menu), &menu_req); - GdkScreen* screen; - gdk_display_get_pointer(gdk_display_get_default(), &screen, NULL, NULL, NULL); - gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y); - - GdkRectangle screen_rect; - gdk_screen_get_monitor_geometry(screen, monitor, &screen_rect); - - *y = CalculateMenuYPosition(&screen_rect, &menu_req, NULL, *y); -} - -void MenuGtk::ExecuteCommand(ui::MenuModel* model, int id) { - if (delegate_) - delegate_->CommandWillBeExecuted(); - - GdkEvent* event = gtk_get_current_event(); - int event_flags = 0; - - if (event && event->type == GDK_BUTTON_RELEASE) - event_flags = event_utils::EventFlagsFromGdkState(event->button.state); - model->ActivatedAt(id, event_flags); - - if (event) - gdk_event_free(event); -} - -void MenuGtk::OnMenuShow(GtkWidget* widget) { - model_->MenuWillShow(); - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&MenuGtk::UpdateMenu, weak_factory_.GetWeakPtr())); -} - -void MenuGtk::OnMenuHidden(GtkWidget* widget) { - if (delegate_) - delegate_->StoppedShowing(); - model_->MenuClosed(); -} - -gboolean MenuGtk::OnMenuFocusOut(GtkWidget* widget, GdkEventFocus* event) { - gtk_widget_hide(menu_); - return TRUE; -} - -void MenuGtk::OnSubMenuShow(GtkWidget* submenu) { - GtkWidget* menu_item = static_cast( - g_object_get_data(G_OBJECT(submenu), "menu-item")); - // TODO(mdm): Figure out why this can sometimes be NULL. See bug 131974. - CHECK(menu_item); - // Notify the submenu model that the menu will be shown. - ui::MenuModel* submenu_model = static_cast( - g_object_get_data(G_OBJECT(menu_item), "submenu-model")); - // We're extra cautious here, and bail out if the submenu model is NULL. In - // some cases we clear it out from a parent menu; we shouldn't ever show the - // menu after that, but we play it safe since we're dealing with wacky - // injected libraries that toy with our menus. (See comments below.) - if (!submenu_model) - return; - - // If the submenu is already built, then return right away. This means we - // recently showed this submenu, and have not yet processed the fact that it - // was hidden before being shown again. - if (g_object_get_data(G_OBJECT(submenu), "submenu-built")) - return; - g_object_set_data(G_OBJECT(submenu), "submenu-built", GINT_TO_POINTER(1)); - - submenu_model->MenuWillShow(); - - // Actually build the submenu and attach it to the parent menu item. - BuildSubmenuFromModel(submenu_model, submenu); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu); - - // Update all the menu item info in the newly-generated menu. - gtk_container_foreach(GTK_CONTAINER(submenu), SetMenuItemInfo, this); -} - -void MenuGtk::OnSubMenuHidden(GtkWidget* submenu) { - if (is_menubar_) - return; - - // Increase the reference count of the old submenu, and schedule it to be - // deleted later. We get this hide notification before we've processed menu - // activations, so if we were to delete the submenu now, we might lose the - // activation. This also lets us reuse the menu if it is shown again before - // it gets deleted; in that case, OnSubMenuHiddenCallback() just decrements - // the reference count again. Note that the delay is just an optimization; we - // could use PostTask() and this would still work correctly. - g_object_ref(G_OBJECT(submenu)); - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&MenuGtk::OnSubMenuHiddenCallback, submenu), - base::TimeDelta::FromSeconds(2)); -} - -namespace { - -// Remove all descendant submenu-model data pointers. -void RemoveSubMenuModels(GtkWidget* menu_item, void* unused) { - if (!GTK_IS_MENU_ITEM(menu_item)) - return; - g_object_steal_data(G_OBJECT(menu_item), "submenu-model"); - GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)); - if (submenu) - gtk_container_foreach(GTK_CONTAINER(submenu), RemoveSubMenuModels, NULL); -} - -} // namespace - -// static -void MenuGtk::OnSubMenuHiddenCallback(GtkWidget* submenu) { - if (!gtk_widget_get_visible(submenu)) { - // Remove all the children of this menu, clearing out their submenu-model - // pointers in case they have pending calls to OnSubMenuHiddenCallback(). - // (Normally that won't happen: we'd have hidden them first, and so they'd - // have already been deleted. But in some cases [e.g. on Ubuntu 12.04], - // GTK menu operations may be hooked to allow external applications to - // mirror the menu structure, and the hooks may show and hide menus in - // order to trigger exactly the kind of dynamic menu building we're doing. - // The result is that we see show and hide events in strange orders.) - GList* children = gtk_container_get_children(GTK_CONTAINER(submenu)); - for (GList* child = children; child; child = g_list_next(child)) { - RemoveSubMenuModels(GTK_WIDGET(child->data), NULL); - gtk_container_remove(GTK_CONTAINER(submenu), GTK_WIDGET(child->data)); - } - g_list_free(children); - - // Clear out the bit that says the menu is built. - // We'll rebuild it next time it is shown. - g_object_steal_data(G_OBJECT(submenu), "submenu-built"); - - // Notify the submenu model that the menu has been hidden. This may cause - // it to delete descendant submenu models, which is why we cleared those - // pointers out above. - GtkWidget* menu_item = static_cast( - g_object_get_data(G_OBJECT(submenu), "menu-item")); - // TODO(mdm): Figure out why this can sometimes be NULL. See bug 124110. - CHECK(menu_item); - ui::MenuModel* submenu_model = static_cast( - g_object_get_data(G_OBJECT(menu_item), "submenu-model")); - if (submenu_model) - submenu_model->MenuClosed(); - } - - // Remove the reference we grabbed in OnSubMenuHidden() above. - g_object_unref(G_OBJECT(submenu)); -} - -// static -void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) { - ui::ButtonMenuItemModel* model = - reinterpret_cast( - g_object_get_data(G_OBJECT(button), "button-model")); - int index = GPOINTER_TO_INT(g_object_get_data( - G_OBJECT(button), "button-model-id")); - - if (model->IsItemDynamicAt(index)) { - std::string label = ui::ConvertAcceleratorsFromWindowsStyle( - base::UTF16ToUTF8(model->GetLabelAt(index))); - gtk_button_set_label(GTK_BUTTON(button), label.c_str()); - } - - gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index)); -} - -// static -void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) { - if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) { - // We need to explicitly handle this case because otherwise we'll ask the - // menu delegate about something with an invalid id. - return; - } - - int id; - if (!GetMenuItemID(widget, &id)) - return; - - ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(widget)); - if (!model) { - // If we're not providing the sub menu, then there's no model. For - // example, the IME submenu doesn't have a model. - return; - } - - if (GTK_IS_CHECK_MENU_ITEM(widget)) { - GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget); - - // gtk_check_menu_item_set_active() will send the activate signal. Touching - // the underlying "active" property will also call the "activate" handler - // for this menu item. So we prevent the "activate" handler from - // being called while we set the checkbox. - // Why not use one of the glib signal-blocking functions? Because when we - // toggle a radio button, it will deactivate one of the other radio buttons, - // which we don't have a pointer to. - // Wny not make this a member variable? Because "menu" is a pointer to the - // root of the MenuGtk and we want to disable *all* MenuGtks, including - // submenus. - block_activation_ = true; - gtk_check_menu_item_set_active(item, model->IsItemCheckedAt(id)); - block_activation_ = false; - } - - if (GTK_IS_CUSTOM_MENU_ITEM(widget)) { - // Iterate across all the buttons to update their visible properties. - gtk_custom_menu_item_foreach_button(GTK_CUSTOM_MENU_ITEM(widget), - SetButtonItemInfo, - userdata); - } - - if (GTK_IS_MENU_ITEM(widget)) { - gtk_widget_set_sensitive(widget, model->IsEnabledAt(id)); - - if (model->IsVisibleAt(id)) { - // Update the menu item label if it is dynamic. - if (model->IsItemDynamicAt(id)) { - std::string label = ui::ConvertAcceleratorsFromWindowsStyle( - base::UTF16ToUTF8(model->GetLabelAt(id))); - - gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str()); - if (GTK_IS_IMAGE_MENU_ITEM(widget)) { - gfx::Image icon; - if (model->GetIconAt(id, &icon)) { - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), - gtk_image_new_from_pixbuf( - icon.ToGdkPixbuf())); - } else { - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL); - } - } - } - - gtk_widget_show(widget); - } else { - gtk_widget_hide(widget); - } - - GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget)); - if (submenu) { - gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo, - userdata); - } - } -} diff --git a/chrome/browser/ui/gtk/menu_gtk.h b/chrome/browser/ui/gtk/menu_gtk.h deleted file mode 100644 index 50ef2c9c29fb..000000000000 --- a/chrome/browser/ui/gtk/menu_gtk.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_GTK_MENU_GTK_H_ -#define CHROME_BROWSER_UI_GTK_MENU_GTK_H_ - -#include - -#include -#include - -#include "base/memory/weak_ptr.h" -#include "ui/base/gtk/gtk_signal.h" -#include "ui/base/gtk/gtk_signal_registrar.h" -#include "ui/gfx/point.h" - -namespace gfx { -class Image; -} - -namespace ui { -class ButtonMenuItemModel; -class MenuModel; -} - -class MenuGtk { - public: - // Delegate class that lets another class control the status of the menu. - class Delegate { - public: - virtual ~Delegate() {} - - // Called before a command is executed. This exists for the case where a - // model is handling the actual execution of commands, but the delegate - // still needs to know that some command got executed. This is called before - // and not after the command is executed because its execution may delete - // the menu and/or the delegate. - virtual void CommandWillBeExecuted() {} - - // Called when the menu stops showing. This will be called before - // ExecuteCommand if the user clicks an item, but will also be called when - // the user clicks away from the menu. - virtual void StoppedShowing() {} - - // Return true if we should override the "gtk-menu-images" system setting - // when showing image menu items for this menu. - virtual bool AlwaysShowIconForCmd(int command_id) const; - - // Returns a tinted image used in button in a menu. - virtual GtkIconSet* GetIconSetForId(int idr); - - // Returns an icon for the menu item, if available. - virtual GtkWidget* GetImageForCommandId(int command_id) const; - - static GtkWidget* GetDefaultImageForLabel(const std::string& label); - }; - - MenuGtk(MenuGtk::Delegate* delegate, - ui::MenuModel* model, - bool is_menubar = false); - virtual ~MenuGtk(); - - // Initialize GTK signal handlers. - void ConnectSignalHandlers(); - - // These methods are used to build the menu dynamically. The return value - // is the new menu item. - GtkWidget* AppendMenuItemWithLabel(int command_id, const std::string& label); - GtkWidget* AppendMenuItemWithIcon(int command_id, const std::string& label, - const gfx::Image& icon); - GtkWidget* AppendCheckMenuItemWithLabel(int command_id, - const std::string& label); - GtkWidget* AppendSeparator(); - GtkWidget* InsertSeparator(int position); - GtkWidget* AppendMenuItem(int command_id, GtkWidget* menu_item); - GtkWidget* InsertMenuItem(int command_id, GtkWidget* menu_item, int position); - GtkWidget* AppendMenuItemToMenu(int index, - ui::MenuModel* model, - GtkWidget* menu_item, - GtkWidget* menu, - bool connect_to_activate); - GtkWidget* InsertMenuItemToMenu(int index, - ui::MenuModel* model, - GtkWidget* menu_item, - GtkWidget* menu, - int position, - bool connect_to_activate); - - // Displays the menu near a widget, as if the widget were a menu bar. - // Example: the wrench menu button. - // |button| is the mouse button that brought up the menu. - // |event_time| is the time from the GdkEvent. - void PopupForWidget(GtkWidget* widget, int button, guint32 event_time); - - // Displays the menu as a context menu, i.e. at the cursor location. - // It is implicit that it was brought up using the right mouse button. - // |point| is the point where to put the menu. - // |event_time| is the time of the event that triggered the menu's display. - void PopupAsContext(const gfx::Point& point, guint32 event_time); - - // Displays the menu as a context menu for the passed status icon. - void PopupAsContextForStatusIcon(guint32 event_time, guint32 button, - GtkStatusIcon* icon); - - // Displays the menu following a keyboard event (such as selecting |widget| - // and pressing "enter"). - void PopupAsFromKeyEvent(GtkWidget* widget); - - // Closes the menu. - void Cancel(); - - // Repositions the menu to be right under the button. Alignment is set as - // object data on |void_widget| with the tag "left_align". If "left_align" - // is true, it aligns the left side of the menu with the left side of the - // button. Otherwise it aligns the right side of the menu with the right side - // of the button. Public since some menus have odd requirements that don't - // belong in a public class. - static void WidgetMenuPositionFunc(GtkMenu* menu, - int* x, - int* y, - gboolean* push_in, - void* void_widget); - - // Positions the menu to appear at the gfx::Point represented by |userdata|. - static void PointMenuPositionFunc(GtkMenu* menu, - int* x, - int* y, - gboolean* push_in, - gpointer userdata); - - GtkWidget* widget() const { return menu_; } - ui::MenuModel* model() const { return model_;} - - // Updates all the enabled/checked states and the dynamic labels. - void UpdateMenu(); - - private: - // Builds a GtkImageMenuItem. - GtkWidget* BuildMenuItemWithImage(const std::string& label, - const gfx::Image& icon); - - GtkWidget* BuildMenuItemWithImage(const std::string& label, - GtkWidget* image); - - GtkWidget* BuildMenuItemWithLabel(const std::string& label, - int command_id); - - // A function that creates a GtkMenu from |model_|. - void BuildMenuFromModel(); - // Implementation of the above; called recursively. - void BuildSubmenuFromModel(ui::MenuModel* model, GtkWidget* menu); - // Builds a menu item with buttons in it from the data in the model. - GtkWidget* BuildButtonMenuItem(ui::ButtonMenuItemModel* model, - GtkWidget* menu); - - void ExecuteCommand(ui::MenuModel* model, int id); - - // Callback for when a menu item is clicked. - CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuItemActivated); - - // Called when one of the buttons is pressed. - CHROMEGTK_CALLBACK_1(MenuGtk, void, OnMenuButtonPressed, int); - - // Called to maybe activate a button if that button isn't supposed to dismiss - // the menu. - CHROMEGTK_CALLBACK_1(MenuGtk, gboolean, OnMenuTryButtonPressed, int); - - // Updates all the menu items' state. - CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuShow); - - // Sets the activating widget back to a normal appearance. - CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuHidden); - - // Focus out event handler for the menu. - CHROMEGTK_CALLBACK_1(MenuGtk, gboolean, OnMenuFocusOut, GdkEventFocus*); - - // Handles building dynamic submenus on demand when they are shown. - CHROMEGTK_CALLBACK_0(MenuGtk, void, OnSubMenuShow); - - // Handles trearing down dynamic submenus when they have been closed. - CHROMEGTK_CALLBACK_0(MenuGtk, void, OnSubMenuHidden); - - // Scheduled by OnSubMenuHidden() to avoid deleting submenus when hidden - // before pending activations within them are delivered. - static void OnSubMenuHiddenCallback(GtkWidget* submenu); - - // Sets the enable/disabled state and dynamic labels on our menu items. - static void SetButtonItemInfo(GtkWidget* button, gpointer userdata); - - // Sets the check mark, enabled/disabled state and dynamic labels on our menu - // items. - static void SetMenuItemInfo(GtkWidget* widget, void* raw_menu); - - // Queries this object about the menu state. - MenuGtk::Delegate* delegate_; - - // If non-NULL, the MenuModel that we use to populate and control the GTK - // menu (overriding the delegate as a controller). - ui::MenuModel* model_; - - // Whether this is a menu bar. - bool is_menubar_; - - // For some menu items, we want to show the accelerator, but not actually - // explicitly handle it. To this end we connect those menu items' accelerators - // to this group, but don't attach this group to any top level window. - GtkAccelGroup* dummy_accel_group_; - - // gtk_menu_popup() does not appear to take ownership of popup menus, so - // MenuGtk explicitly manages the lifetime of the menu. - GtkWidget* menu_; - - // True when we should ignore "activate" signals. Used to prevent - // menu items from getting activated when we are setting up the - // menu. - static bool block_activation_; - - ui::GtkSignalRegistrar signal_; - - base::WeakPtrFactory weak_factory_; -}; - -#endif // CHROME_BROWSER_UI_GTK_MENU_GTK_H_ diff --git a/chrome/LICENSE.chromium b/chromium_src/LICENSE.chromium similarity index 100% rename from chrome/LICENSE.chromium rename to chromium_src/LICENSE.chromium diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc b/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc new file mode 100644 index 000000000000..151117314c83 --- /dev/null +++ b/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc @@ -0,0 +1,123 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" + +#include + +#include "base/bind.h" +#include "base/debug/leak_annotations.h" +#include "chrome/browser/ui/libgtk2ui/menu_util.h" +#include "ui/base/models/menu_model.h" + +namespace libgtk2ui { + +AppIndicatorIconMenu::AppIndicatorIconMenu(ui::MenuModel* model) + : menu_model_(model), + click_action_replacement_menu_item_added_(false), + gtk_menu_(NULL), + block_activation_(false) { + { + ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/378770 + gtk_menu_ = gtk_menu_new(); + } + g_object_ref_sink(gtk_menu_); + if (menu_model_) { + BuildSubmenuFromModel(menu_model_, + gtk_menu_, + G_CALLBACK(OnMenuItemActivatedThunk), + &block_activation_, + this); + Refresh(); + } +} + +AppIndicatorIconMenu::~AppIndicatorIconMenu() { + gtk_widget_destroy(gtk_menu_); + g_object_unref(gtk_menu_); +} + +void AppIndicatorIconMenu::UpdateClickActionReplacementMenuItem( + const char* label, + const base::Closure& callback) { + click_action_replacement_callback_ = callback; + + if (click_action_replacement_menu_item_added_) { + GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_)); + for (GList* child = children; child; child = g_list_next(child)) { + if (g_object_get_data(G_OBJECT(child->data), "click-action-item") != + NULL) { + gtk_menu_item_set_label(GTK_MENU_ITEM(child->data), label); + break; + } + } + g_list_free(children); + } else { + click_action_replacement_menu_item_added_ = true; + + // If |menu_model_| is non empty, add a separator to separate the + // "click action replacement menu item" from the other menu items. + if (menu_model_ && menu_model_->GetItemCount() > 0) { + GtkWidget* menu_item = gtk_separator_menu_item_new(); + gtk_widget_show(menu_item); + gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item); + } + + GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(label); + g_object_set_data( + G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1)); + g_signal_connect(menu_item, + "activate", + G_CALLBACK(OnClickActionReplacementMenuItemActivatedThunk), + this); + gtk_widget_show(menu_item); + gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item); + } +} + +void AppIndicatorIconMenu::Refresh() { + gtk_container_foreach( + GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_); +} + +GtkMenu* AppIndicatorIconMenu::GetGtkMenu() { + return GTK_MENU(gtk_menu_); +} + + +void AppIndicatorIconMenu::OnClickActionReplacementMenuItemActivated( + GtkWidget* menu_item) { + click_action_replacement_callback_.Run(); +} + +void AppIndicatorIconMenu::OnMenuItemActivated(GtkWidget* menu_item) { + if (block_activation_) + return; + + ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item)); + if (!model) { + // There won't be a model for "native" submenus like the "Input Methods" + // context menu. We don't need to handle activation messages for submenus + // anyway, so we can just return here. + DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))); + return; + } + + // The activate signal is sent to radio items as they get deselected; + // ignore it in this case. + if (GTK_IS_RADIO_MENU_ITEM(menu_item) && + !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) { + return; + } + + int id; + if (!GetMenuItemID(menu_item, &id)) + return; + + // The menu item can still be activated by hotkeys even if it is disabled. + if (menu_model_->IsEnabledAt(id)) + ExecuteCommand(model, id); +} + +} // namespace libgtk2ui diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h b/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h new file mode 100644 index 000000000000..a204710f9c18 --- /dev/null +++ b/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h @@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_ +#define CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_ + +#include "base/callback.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" + +typedef struct _GtkMenu GtkMenu; +typedef struct _GtkWidget GtkWidget; + +namespace ui { +class MenuModel; +} + +namespace libgtk2ui { + +// The app indicator icon's menu. +class AppIndicatorIconMenu { + public: + explicit AppIndicatorIconMenu(ui::MenuModel* model); + virtual ~AppIndicatorIconMenu(); + + // Sets a menu item at the top of |gtk_menu_| as a replacement for the app + // indicator icon's click action. |callback| is called when the menu item + // is activated. + void UpdateClickActionReplacementMenuItem(const char* label, + const base::Closure& callback); + + // Refreshes all the menu item labels and menu item checked/enabled states. + void Refresh(); + + GtkMenu* GetGtkMenu(); + + private: + // Callback for when the "click action replacement" menu item is activated. + CHROMEGTK_CALLBACK_0(AppIndicatorIconMenu, + void, + OnClickActionReplacementMenuItemActivated); + + // Callback for when a menu item is activated. + CHROMEGTK_CALLBACK_0(AppIndicatorIconMenu, void, OnMenuItemActivated); + + // Not owned. + ui::MenuModel* menu_model_; + + // Whether a "click action replacement" menu item has been added to the menu. + bool click_action_replacement_menu_item_added_; + + // Called when the click action replacement menu item is activated. When a + // menu item from |menu_model_| is activated, MenuModel::ActivatedAt() is + // invoked and is assumed to do any necessary processing. + base::Closure click_action_replacement_callback_; + + GtkWidget* gtk_menu_; + + bool block_activation_; + + DISALLOW_COPY_AND_ASSIGN(AppIndicatorIconMenu); +}; + +} // namespace libgtk2ui + +#endif // CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_ diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc b/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc new file mode 100644 index 000000000000..2838bff2ea1f --- /dev/null +++ b/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc @@ -0,0 +1,80 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h" + +#include + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" +#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" +#include "ui/base/models/menu_model.h" +#include "ui/gfx/image/image_skia.h" + +namespace libgtk2ui { + +Gtk2StatusIcon::Gtk2StatusIcon(const gfx::ImageSkia& image, + const base::string16& tool_tip) { + GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap()); + gtk_status_icon_ = gtk_status_icon_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + + g_signal_connect(gtk_status_icon_, "activate", G_CALLBACK(OnClickThunk), + this); + g_signal_connect(gtk_status_icon_, "popup_menu", + G_CALLBACK(OnContextMenuRequestedThunk), this); + SetToolTip(tool_tip); +} + +Gtk2StatusIcon::~Gtk2StatusIcon() { + g_object_unref(gtk_status_icon_); +} + +void Gtk2StatusIcon::SetImage(const gfx::ImageSkia& image) { + GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap()); + gtk_status_icon_set_from_pixbuf(gtk_status_icon_, pixbuf); + g_object_unref(pixbuf); +} + +void Gtk2StatusIcon::SetPressedImage(const gfx::ImageSkia& image) { + // Ignore pressed images, since the standard on Linux is to not highlight + // pressed status icons. +} + +void Gtk2StatusIcon::SetToolTip(const base::string16& tool_tip) { + gtk_status_icon_set_tooltip_text(gtk_status_icon_, + base::UTF16ToUTF8(tool_tip).c_str()); +} + +void Gtk2StatusIcon::UpdatePlatformContextMenu(ui::MenuModel* model) { + menu_.reset(); + if (model) + menu_.reset(new AppIndicatorIconMenu(model)); +} + +void Gtk2StatusIcon::RefreshPlatformContextMenu() { + if (menu_.get()) + menu_->Refresh(); +} + +void Gtk2StatusIcon::OnClick(GtkStatusIcon* status_icon) { + if (delegate()) + delegate()->OnClick(); +} + +void Gtk2StatusIcon::OnContextMenuRequested(GtkStatusIcon* status_icon, + guint button, + guint32 activate_time) { + if (menu_.get()) { + gtk_menu_popup(menu_->GetGtkMenu(), + NULL, + NULL, + gtk_status_icon_position_menu, + gtk_status_icon_, + button, + activate_time); + } +} + +} // namespace libgtk2ui diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h b/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h new file mode 100644 index 000000000000..d25b487b6219 --- /dev/null +++ b/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_ +#define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/strings/string16.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" +#include "ui/base/glib/glib_integers.h" +#include "ui/base/glib/glib_signal.h" +#include "ui/views/linux_ui/status_icon_linux.h" + +typedef struct _GtkStatusIcon GtkStatusIcon; + +namespace gfx { +class ImageSkia; +} + +namespace ui { +class MenuModel; +} + +namespace libgtk2ui { +class AppIndicatorIconMenu; + +// Status icon implementation which uses the system tray X11 spec (via +// GtkStatusIcon). +class Gtk2StatusIcon : public views::StatusIconLinux { + public: + Gtk2StatusIcon(const gfx::ImageSkia& image, const base::string16& tool_tip); + virtual ~Gtk2StatusIcon(); + + // Overridden from views::StatusIconLinux: + virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE; + virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE; + virtual void SetToolTip(const base::string16& tool_tip) OVERRIDE; + virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE; + virtual void RefreshPlatformContextMenu() OVERRIDE; + + private: + CHROMEG_CALLBACK_0(Gtk2StatusIcon, void, OnClick, GtkStatusIcon*); + + CHROMEG_CALLBACK_2(Gtk2StatusIcon, + void, + OnContextMenuRequested, + GtkStatusIcon*, + guint, + guint); + + GtkStatusIcon* gtk_status_icon_; + + scoped_ptr menu_; + + DISALLOW_COPY_AND_ASSIGN(Gtk2StatusIcon); +}; + +} // namespace libgtk2ui + +#endif // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_ diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc new file mode 100644 index 000000000000..0d2a6dd73824 --- /dev/null +++ b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc @@ -0,0 +1,142 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h" + +#include "atom/browser/ui/views/global_menu_bar_x11.h" +#include "base/bind.h" +#include "base/debug/leak_annotations.h" +#include "base/logging.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace { + +const char kAppMenuRegistrarName[] = "com.canonical.AppMenu.Registrar"; +const char kAppMenuRegistrarPath[] = "/com/canonical/AppMenu/Registrar"; + +} // namespace + +// static +GlobalMenuBarRegistrarX11* GlobalMenuBarRegistrarX11::GetInstance() { + return Singleton::get(); +} + +void GlobalMenuBarRegistrarX11::OnWindowMapped(unsigned long xid) { + live_xids_.insert(xid); + + if (registrar_proxy_) + RegisterXID(xid); +} + +void GlobalMenuBarRegistrarX11::OnWindowUnmapped(unsigned long xid) { + if (registrar_proxy_) + UnregisterXID(xid); + + live_xids_.erase(xid); +} + +GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11() + : registrar_proxy_(NULL) { + // libdbusmenu uses the gio version of dbus; I tried using the code in dbus/, + // but it looks like that's isn't sharing the bus name with the gio version, + // even when |connection_type| is set to SHARED. + g_dbus_proxy_new_for_bus( + G_BUS_TYPE_SESSION, + static_cast( + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), + NULL, + kAppMenuRegistrarName, + kAppMenuRegistrarPath, + kAppMenuRegistrarName, + NULL, // TODO: Probalby want a real cancelable. + static_cast(OnProxyCreatedThunk), + this); +} + +GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() { + if (registrar_proxy_) { + g_signal_handlers_disconnect_by_func( + registrar_proxy_, + reinterpret_cast(OnNameOwnerChangedThunk), + this); + g_object_unref(registrar_proxy_); + } +} + +void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { + DCHECK(registrar_proxy_); + std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); + + ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 + // TODO(erg): The mozilla implementation goes to a lot of callback trouble + // just to make sure that they react to make sure there's some sort of + // cancelable object; including making a whole callback just to handle the + // cancelable. + // + // I don't see any reason why we should care if "RegisterWindow" completes or + // not. + g_dbus_proxy_call(registrar_proxy_, + "RegisterWindow", + g_variant_new("(uo)", xid, path.c_str()), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, + NULL, + NULL); +} + +void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) { + DCHECK(registrar_proxy_); + std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); + + ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 + // TODO(erg): The mozilla implementation goes to a lot of callback trouble + // just to make sure that they react to make sure there's some sort of + // cancelable object; including making a whole callback just to handle the + // cancelable. + // + // I don't see any reason why we should care if "UnregisterWindow" completes + // or not. + g_dbus_proxy_call(registrar_proxy_, + "UnregisterWindow", + g_variant_new("(u)", xid), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, + NULL, + NULL); +} + +void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source, + GAsyncResult* result) { + GError* error = NULL; + GDBusProxy* proxy = g_dbus_proxy_new_for_bus_finish(result, &error); + if (error) { + g_error_free(error); + return; + } + + // TODO(erg): Mozilla's implementation has a workaround for GDBus + // cancellation here. However, it's marked as fixed. If there's weird + // problems with cancelation, look at how they fixed their issues. + + registrar_proxy_ = proxy; + + g_signal_connect(registrar_proxy_, "notify::g-name-owner", + G_CALLBACK(OnNameOwnerChangedThunk), this); + + OnNameOwnerChanged(NULL, NULL); +} + +void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */, + GParamSpec* /* ignored */) { + // If the name owner changed, we need to reregister all the live xids with + // the system. + for (std::set::const_iterator it = live_xids_.begin(); + it != live_xids_.end(); ++it) { + RegisterXID(*it); + } +} diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h new file mode 100644 index 000000000000..e35e87c0d20c --- /dev/null +++ b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h @@ -0,0 +1,54 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ +#define CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ + +#include + +#include + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/singleton.h" +#include "ui/base/glib/glib_signal.h" + +// Advertises our menu bars to Unity. +// +// GlobalMenuBarX11 is responsible for managing the DbusmenuServer for each +// XID. We need a separate object to own the dbus channel to +// com.canonical.AppMenu.Registrar and to register/unregister the mapping +// between a XID and the DbusmenuServer instance we are offering. +class GlobalMenuBarRegistrarX11 { + public: + static GlobalMenuBarRegistrarX11* GetInstance(); + + void OnWindowMapped(unsigned long xid); + void OnWindowUnmapped(unsigned long xid); + + private: + friend struct DefaultSingletonTraits; + + GlobalMenuBarRegistrarX11(); + ~GlobalMenuBarRegistrarX11(); + + // Sends the actual message. + void RegisterXID(unsigned long xid); + void UnregisterXID(unsigned long xid); + + CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, void, OnProxyCreated, + GObject*, GAsyncResult*); + CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, void, OnNameOwnerChanged, + GObject*, GParamSpec*); + + GDBusProxy* registrar_proxy_; + + // Window XIDs which want to be registered, but haven't yet been because + // we're waiting for the proxy to become available. + std::set live_xids_; + + DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarRegistrarX11); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ diff --git a/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc b/chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc similarity index 100% rename from chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc rename to chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc diff --git a/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h b/chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h similarity index 100% rename from chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h rename to chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h diff --git a/common.gypi b/common.gypi index 820bf9594010..740da0baf572 100644 --- a/common.gypi +++ b/common.gypi @@ -5,7 +5,7 @@ ['OS=="mac" or OS=="linux"', { 'clang': 1, }], - ['OS=="win" and (MSVS_VERSION=="2012e" or MSVS_VERSION=="2010e")', { + ['OS=="win" and (MSVS_VERSION=="2013e" or MSVS_VERSION=="2012e" or MSVS_VERSION=="2010e")', { 'msvs_express': 1, 'windows_driver_kit_path%': 'C:/WinDDK/7600.16385.1', },{ @@ -24,12 +24,14 @@ 'node_shared_v8': 'true', 'node_shared_zlib': 'false', 'node_tag': '', - 'node_unsafe_optimizations': 0, 'node_use_dtrace': 'false', 'node_use_etw': 'false', + 'node_use_mdb': 'false', 'node_use_openssl': 'true', 'node_use_perfctr': 'false', - 'node_use_systemtap': 'false', + 'uv_library': 'static_library', + 'uv_parent_path': 'vendor/node/deps/uv', + 'uv_use_dtrace': 'false', 'v8_postmortem_support': 'false', # Required by Linux (empty for now, should support it in future). 'sysroot': '', @@ -39,6 +41,7 @@ 'target_conditions': [ ['_target_name in ["libuv", "http_parser", "cares", "openssl", "openssl-cli", "node_lib", "zlib"]', { 'msvs_disabled_warnings': [ + 4703, # potentially uninitialized local pointer variable 'req' used 4013, # 'free' undefined; assuming extern returning int 4054, # 4057, # 'function' : 'volatile LONG *' differs in indirection to slightly different base types from 'unsigned long *' @@ -136,6 +139,7 @@ 4201, # (uv.h) nameless struct/union 4800, # (v8.h) forcing value to bool 'true' or 'false' 4819, # The file contains a character that cannot be represented in the current code page + 4996, # (atlapp.h) 'GetVersionExW': was declared deprecated ], 'msvs_settings': { 'VCCLCompilerTool': { diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index e7dc022f859b..81dcd2e8123e 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -2,21 +2,17 @@ ## Prerequisites -* Windows 7 or later -* Visual Studio 2010 Express or Professional, with SP1 update - * Make sure "X64 Compilers and Tools" are installed if you use the - Professional edition. +* Windows 8 +* Visual Studio 2013 * [Python 2.7](http://www.python.org/download/releases/2.7/) * 32bit [node.js](http://nodejs.org/) * [git](http://git-scm.com) -If you are using Visual Studio 2010 __Express__ then you also need following +If you are using Visual Studio 2013 __Express__ then you also need following softwares: * [WDK](http://www.microsoft.com/en-us/download/details.aspx?id=11800) * `Build Environments` is required. -* [Windows 7 SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279) - * `Windows Headers` and `Visual C++ Compilers` are required. The instructions below are executed under [cygwin](http://www.cygwin.com), but it's not a requirement, you can also build atom-shell under the Windows @@ -79,8 +75,7 @@ $ python script/test.py ### Command xxxx not found If you encountered an error like `Command xxxx not found`, you may try to use -the `Visual Studio x64 Tools Command Prompt (2010)` console to execute the build -scripts. +the `VS2012 Command Prompt` console to execute the build scripts. ### Assertion failed: ((handle))->activecnt >= 0 @@ -110,11 +105,6 @@ you have installed python under `C:\Python27`): /cygdrive/c/Python27/python.exe script/bootstrap.py ``` -### LNK1123: failure during conversion to COFF: file invalid or corrupt - -Upgrading to VS 2010 SP1 would solve this, read the Microsoft Support article -on more of this: http://support.microsoft.com/kb/2757355. - ### LNK1181: cannot open input file 'kernel32.lib' Try reinstalling 32bit node.js. diff --git a/docs/development/source-code-directory-structure.md b/docs/development/source-code-directory-structure.md index 9f5725e842aa..01e84d7b0b6b 100644 --- a/docs/development/source-code-directory-structure.md +++ b/docs/development/source-code-directory-structure.md @@ -38,7 +38,7 @@ to understand the source code better. * **api** - The implementation of common APIs, and foundations of atom-shell's built-in modules. * **lib** - Javascript part of the API implementation. -* **chrome** - Source code modified from Chromium's `chrome` component. +* **chromium_src** - Source code that copied from Chromium. * **docs** - Documentations. * **spec** - Automatic tests. * **atom.gyp** - Building rules of atom-shell. diff --git a/filename_rules.gypi b/filename_rules.gypi index 87ab60819344..9f693827e34c 100644 --- a/filename_rules.gypi +++ b/filename_rules.gypi @@ -32,7 +32,11 @@ ['OS!="linux" and OS!="openbsd" and OS!="freebsd"', { 'sources/': [ ['exclude', '_linux(_unittest)?\\.(h|cc)$'], + ['exclude', '(^|/)linux_[^/]*\\.(h|cc)$'], ['exclude', '(^|/)linux/'], + ['exclude', '_x11(_unittest)?\\.(h|cc)$'], + ['exclude', '(^|/)x11_[^/]*\\.(h|cc)$'], + ['exclude', '(^|/)x11/'], ], }], ['OS!="android"', { @@ -57,10 +61,16 @@ ['exclude', '_gtk(_browsertest|_unittest)?\\.(h|cc)$'], ['exclude', '(^|/)gtk/'], ['exclude', '(^|/)gtk_[^/]*\\.(h|cc)$'], + ['exclude', '(^|/)libgtk2ui/'], + ['exclude', '(^|/)x/'], ], }], - ['OS!="win"', { - 'sources/': [ ['exclude', '_views\\.(h|cc)$'] ] + ['OS=="mac"', { + 'sources/': [ ['exclude', '_aura(_browsertest|_unittest)?\\.(h|cc)$'], + ['exclude', '(^|/)aura/'], + ['exclude', '_views\\.(h|cc)$'], + ['exclude', '(^|/)views/'], + ], }], ] } diff --git a/package.json b/package.json index 8a085ced60a2..7028c89be62b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "devDependencies": { - "atom-package-manager": "0.50.x", + "atom-package-manager": "0.76.x", "coffee-script": "~1.7.1", "coffeelint": "~1.3.0" }, diff --git a/script/bootstrap.py b/script/bootstrap.py index fb32a9758c48..3a687b79edc2 100755 --- a/script/bootstrap.py +++ b/script/bootstrap.py @@ -4,7 +4,7 @@ import argparse import os import sys -from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL +from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL, NODE_VERSION from lib.util import execute, scoped_cwd @@ -61,6 +61,7 @@ def update_node_modules(dirname): def update_atom_modules(dirname): + os.environ['ATOM_NODE_VERSION'] = NODE_VERSION[1:] with scoped_cwd(dirname): apm = os.path.join(SOURCE_ROOT, 'node_modules', '.bin', 'apm') if sys.platform in ['win32', 'cygwin']: diff --git a/script/create-dist.py b/script/create-dist.py index c39f56006470..b1cfc28796b1 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -37,15 +37,18 @@ TARGET_BINARIES = { 'chromiumcontent.dll', 'content_shell.pak', 'ffmpegsumo.dll', - 'icudt.dll', + 'icudtl.dat', 'libEGL.dll', 'libGLESv2.dll', 'd3dcompiler_43.dll', + 'ui_resources_200_percent.pak', + 'webkit_resources_200_percent.pak', 'xinput1_3.dll', ], 'linux': [ 'atom', 'content_shell.pak', + 'icudtl.dat', 'libchromiumcontent.so', 'libffmpegsumo.so', ], diff --git a/script/lib/config.py b/script/lib/config.py index f7d0add7d2b2..249478cc0d77 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -3,9 +3,9 @@ import platform import sys -NODE_VERSION = 'v0.11.10' +NODE_VERSION = 'v0.11.13' BASE_URL = 'https://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '765ec5dcf192845fed4aec0b117f1e53050911d6' +LIBCHROMIUMCONTENT_COMMIT = '177f00b33d8ba5a6befe646e8d39ce19b6a3c668' ARCH = { 'cygwin': '32bit', diff --git a/script/lib/util.py b/script/lib/util.py index c66dca810e67..c78ca213e199 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -30,6 +30,7 @@ def scoped_cwd(path): def download(text, url, path): + safe_mkdir(os.path.dirname(path)) with open(path, 'w') as local_file: web_file = urllib2.urlopen(url) file_size = int(web_file.info().getheaders("Content-Length")[0]) @@ -55,6 +56,7 @@ def download(text, url, path): print "%s done." % (text) else: print + return path def extract_tarball(tarball_path, member, destination): @@ -120,3 +122,28 @@ def execute(argv): def get_atom_shell_version(): return subprocess.check_output(['git', 'describe', '--tags']).strip() + + +def s3_config(): + config = (os.environ.get('ATOM_SHELL_S3_BUCKET', ''), + os.environ.get('ATOM_SHELL_S3_ACCESS_KEY', ''), + os.environ.get('ATOM_SHELL_S3_SECRET_KEY', '')) + message = ('Error: Please set the $ATOM_SHELL_S3_BUCKET, ' + '$ATOM_SHELL_S3_ACCESS_KEY, and ' + '$ATOM_SHELL_S3_SECRET_KEY environment variables') + assert all(len(c) for c in config), message + return config + + +def s3put(bucket, access_key, secret_key, prefix, key_prefix, files): + args = [ + 's3put', + '--bucket', bucket, + '--access_key', access_key, + '--secret_key', secret_key, + '--prefix', prefix, + '--key_prefix', key_prefix, + '--grant', 'public-read' + ] + files + + execute(args) diff --git a/script/upload-checksums.py b/script/upload-checksums.py new file mode 100755 index 000000000000..34a58fce5e90 --- /dev/null +++ b/script/upload-checksums.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +import argparse +import hashlib +import os +import tempfile + +from lib.util import download, rm_rf, s3_config, s3put + + +DIST_URL = 'https://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist/' + + +def main(): + args = parse_args() + + url = DIST_URL + args.version + '/' + directory, files = download_files(url, get_files_list(args.version)) + checksums = [ + create_checksum('sha1', directory, 'SHASUMS.txt', files), + create_checksum('sha256', directory, 'SHASUMS256.txt', files) + ] + + bucket, access_key, secret_key = s3_config() + s3put(bucket, access_key, secret_key, directory, + 'atom-shell/dist/{0}'.format(args.version), checksums) + + rm_rf(directory) + + +def parse_args(): + parser = argparse.ArgumentParser(description='upload sumsha file') + parser.add_argument('-v', '--version', help='Specify the version', + required=True) + return parser.parse_args() + + +def get_files_list(version): + return [ + 'node-{0}.tar.gz'.format(version), + 'node.lib', + 'x64/node.lib', + ] + + +def download_files(url, files): + directory = tempfile.mkdtemp(prefix='atom-shell-tmp') + return directory, [ + download(f, url + f, os.path.join(directory, f)) + for f in files + ] + + +def create_checksum(algorithm, directory, filename, files): + lines = [] + for path in files: + h = hashlib.new(algorithm) + with open(path, 'r') as f: + h.update(f.read()) + lines.append(h.hexdigest() + ' ' + os.path.relpath(path, directory)) + + checksum_file = os.path.join(directory, filename) + with open(checksum_file, 'w') as f: + f.write('\n'.join(lines) + '\n') + return checksum_file + + +if __name__ == '__main__': + import sys + sys.exit(main()) diff --git a/script/upload.py b/script/upload.py index afe0dbbd61e3..4cadf918d029 100755 --- a/script/upload.py +++ b/script/upload.py @@ -9,7 +9,8 @@ import sys import tempfile from lib.config import DIST_ARCH, NODE_VERSION, TARGET_PLATFORM -from lib.util import get_atom_shell_version, scoped_cwd, safe_mkdir, execute +from lib.util import get_atom_shell_version, scoped_cwd, safe_mkdir, execute, \ + s3_config, s3put from lib.github import GitHub @@ -48,6 +49,11 @@ def main(): upload_atom_shell(github, release_id, os.path.join(DIST_DIR, DIST_NAME)) upload_atom_shell(github, release_id, os.path.join(DIST_DIR, SYMBOLS_NAME)) if args.publish_release: + # Upload the SHASUMS.txt. + execute([sys.executable, + os.path.join(SOURCE_ROOT, 'script', 'upload-checksums.py')]) + + # Press the publish button. publish_release(github, release_id) # Upload node's headers to S3. @@ -176,31 +182,6 @@ def auth_token(): return token -def s3_config(): - config = (os.environ.get('ATOM_SHELL_S3_BUCKET', ''), - os.environ.get('ATOM_SHELL_S3_ACCESS_KEY', ''), - os.environ.get('ATOM_SHELL_S3_SECRET_KEY', '')) - message = ('Error: Please set the $ATOM_SHELL_S3_BUCKET, ' - '$ATOM_SHELL_S3_ACCESS_KEY, and ' - '$ATOM_SHELL_S3_SECRET_KEY environment variables') - assert all(len(c) for c in config), message - return config - - -def s3put(bucket, access_key, secret_key, prefix, key_prefix, files): - args = [ - 's3put', - '--bucket', bucket, - '--access_key', access_key, - '--secret_key', secret_key, - '--prefix', prefix, - '--key_prefix', key_prefix, - '--grant', 'public-read' - ] + files - - execute(args) - - def touch_x64_node_lib(): x64_dir = os.path.join(OUT_DIR, 'x64') safe_mkdir(x64_dir) diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index f9eb37d4d927..957ea271d092 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -103,12 +103,9 @@ describe 'browser-window module', -> assert.equal contentSize[1], 400 it 'make window created with window size when not used', -> - # No way to reliably set size when window has not been shown on Linux. - return if process.platform is 'linux' - - contentSize = w.getSize() - assert.equal contentSize[0], 400 - assert.equal contentSize[1], 400 + size = w.getSize() + assert.equal size[0], 400 + assert.equal size[1], 400 describe 'beforeunload handler', -> it 'returning true would not prevent close', (done) -> diff --git a/spec/api-protocol-spec.coffee b/spec/api-protocol-spec.coffee index 8cff8b331d63..b0b152aa5fd9 100644 --- a/spec/api-protocol-spec.coffee +++ b/spec/api-protocol-spec.coffee @@ -18,7 +18,6 @@ describe 'protocol module', -> it 'calls the callback when scheme is visited', (done) -> protocol.registerProtocol 'test2', (request) -> assert.equal request.url, 'test2://test2' - assert.equal request.referrer, window.location.toString() protocol.unregisterProtocol 'test2' done() $.get 'test2://test2', -> diff --git a/spec/chromium-spec.coffee b/spec/chromium-spec.coffee index e0695b58e217..5bec7bf8a897 100644 --- a/spec/chromium-spec.coffee +++ b/spec/chromium-spec.coffee @@ -75,3 +75,21 @@ describe 'chromium feature', -> return if process.platform is 'linux' webgl = document.createElement('canvas').getContext 'webgl' assert.notEqual webgl, null + + describe 'web workers', -> + it 'Worker can work', (done) -> + worker = new Worker('../fixtures/workers/worker.js') + message = 'ping' + worker.onmessage = (event) -> + assert.equal event.data, message + worker.terminate() + done() + worker.postMessage message + + it 'SharedWorker can work', (done) -> + worker = new SharedWorker('../fixtures/workers/shared_worker.js') + message = 'ping' + worker.port.onmessage = (event) -> + assert.equal event.data, message + done() + worker.port.postMessage message diff --git a/spec/fixtures/workers/shared_worker.js b/spec/fixtures/workers/shared_worker.js new file mode 100644 index 000000000000..d35b47435e8a --- /dev/null +++ b/spec/fixtures/workers/shared_worker.js @@ -0,0 +1,7 @@ +onconnect = function(event) { + var port = event.ports[0]; + port.start(); + port.onmessage = function(event) { + port.postMessage(event.data); + } +} diff --git a/spec/fixtures/workers/worker.js b/spec/fixtures/workers/worker.js new file mode 100644 index 000000000000..6f9533708a0d --- /dev/null +++ b/spec/fixtures/workers/worker.js @@ -0,0 +1,3 @@ +this.onmessage = function(msg) { + this.postMessage(msg.data); +} diff --git a/spec/package.json b/spec/package.json index 52c0c32d9d83..9d1ea580891f 100644 --- a/spec/package.json +++ b/spec/package.json @@ -6,10 +6,10 @@ "devDependencies": { "formidable": "~1.0.14", - "pathwatcher": "1.3.1", + "pathwatcher": "2.x", "q": "0.9.7", "mocha": "~1.18.2", - "runas": "0.5.*", + "runas": "1.x", "temp": "~0.6.0", "walkdir": "~0.0.7" } diff --git a/spec/static/main.js b/spec/static/main.js index 5b0817cca2fd..af9c0fdd0d93 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -139,7 +139,10 @@ app.on('ready', function() { title: 'atom-shell tests', show: false, width: 800, - height: 600 + height: 600, + 'web-preferences': { + javascript: true // Test whether web-preferences crashes. + }, }); window.loadUrl('file://' + __dirname + '/index.html'); window.on('unresponsive', function() { diff --git a/vendor/brightray b/vendor/brightray index 45ab10c1e674..13628c0d7f79 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 45ab10c1e6743ab1e6eafb9940d4913f7754914f +Subproject commit 13628c0d7f799952c2d0067dbacded0bd73d5671 diff --git a/vendor/native_mate b/vendor/native_mate index a5c4a2c7c642..3d713baa4c33 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit a5c4a2c7c64239ec5d007342f00f16f3981d6d80 +Subproject commit 3d713baa4c33baebfac82b242e8897504592c590 diff --git a/vendor/node b/vendor/node index 4e45fee905bc..a3ec3c255226 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 4e45fee905bc6d0605ba40f312991bcf76ab3cba +Subproject commit a3ec3c255226137961585cbdee659b3e0a7f3955