commit
e803d3cc7a
159 changed files with 4159 additions and 6768 deletions
74
atom.gyp
74
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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
#include <shellapi.h>
|
||||
|
||||
#include "atom/app/atom_main_delegate.h"
|
||||
#include "base/environment.h"
|
||||
#include "atom/common/crash_reporter/win/crash_service_main.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "content/public/app/startup_helper_win.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#elif defined(OS_LINUX) // defined(OS_WIN)
|
||||
#include "atom/app/atom_main_delegate.h" // NOLINT
|
||||
#include "content/public/app/content_main.h"
|
||||
|
@ -34,6 +36,13 @@ int Start(int argc, char *argv[]);
|
|||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
namespace {
|
||||
|
||||
const wchar_t kRegistryProfilePath[] = L"SOFTWARE\\Google\\Chrome\\Profile";
|
||||
const wchar_t kHighDPISupportW[] = L"high-dpi-support";
|
||||
|
||||
} // namespace
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
int argc = 0;
|
||||
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
|
@ -98,7 +107,18 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
|||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||
content::InitializeSandboxInfo(&sandbox_info);
|
||||
atom::AtomMainDelegate delegate;
|
||||
return content::ContentMain(instance, &sandbox_info, &delegate);
|
||||
|
||||
// Now chrome relies on a regkey to enable high dpi support.
|
||||
base::win::RegKey high_dpi_key(HKEY_CURRENT_USER);
|
||||
high_dpi_key.CreateKey(kRegistryProfilePath, KEY_SET_VALUE);
|
||||
high_dpi_key.WriteValue(kHighDPISupportW, 1);
|
||||
|
||||
gfx::EnableHighDPISupport();
|
||||
|
||||
content::ContentMainParams params(&delegate);
|
||||
params.instance = instance;
|
||||
params.sandbox_info = &sandbox_info;
|
||||
return content::ContentMain(params);
|
||||
}
|
||||
|
||||
#elif defined(OS_LINUX) // defined(OS_WIN)
|
||||
|
@ -109,7 +129,10 @@ int main(int argc, const char* argv[]) {
|
|||
return node::Start(argc, const_cast<char**>(argv));
|
||||
|
||||
atom::AtomMainDelegate delegate;
|
||||
return content::ContentMain(argc, argv, &delegate);
|
||||
content::ContentMainParams params(&delegate);
|
||||
params.argc = argc;
|
||||
params.argv = argv;
|
||||
return content::ContentMain(params);
|
||||
}
|
||||
|
||||
#else // defined(OS_LINUX)
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/renderer/atom_renderer_client.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/debug/stack_trace.h"
|
||||
#include "base/logging.h"
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "atom/renderer/atom_renderer_client.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
#include "base/path_service.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -23,6 +22,18 @@ AtomMainDelegate::AtomMainDelegate() {
|
|||
AtomMainDelegate::~AtomMainDelegate() {
|
||||
}
|
||||
|
||||
void AtomMainDelegate::AddDataPackFromPath(
|
||||
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) {
|
||||
#if defined(OS_WIN)
|
||||
bundle->AddDataPackFromPath(
|
||||
pak_dir.Append(FILE_PATH_LITERAL("ui_resources_200_percent.pak")),
|
||||
ui::SCALE_FACTOR_200P);
|
||||
bundle->AddDataPackFromPath(
|
||||
pak_dir.Append(FILE_PATH_LITERAL("webkit_resources_200_percent.pak")),
|
||||
ui::SCALE_FACTOR_200P);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
// Disable logging out to debug.log on Windows
|
||||
#if defined(OS_WIN)
|
||||
|
@ -35,8 +46,6 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
#else
|
||||
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
||||
#endif
|
||||
settings.dcheck_state =
|
||||
logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
|
||||
logging::InitLogging(settings);
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
|
@ -52,11 +61,7 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
}
|
||||
|
||||
void AtomMainDelegate::PreSandboxStartup() {
|
||||
#if defined(OS_MACOSX)
|
||||
OverrideChildProcessPath();
|
||||
OverrideFrameworkBundlePath();
|
||||
#endif
|
||||
InitializeResourceBundle();
|
||||
brightray::MainDelegate::PreSandboxStartup();
|
||||
|
||||
CommandLine* command_line = CommandLine::ForCurrentProcess();
|
||||
std::string process_type = command_line->GetSwitchValueASCII(
|
||||
|
@ -76,19 +81,6 @@ void AtomMainDelegate::PreSandboxStartup() {
|
|||
command_line->AppendSwitch("atom-shell-switches-end");
|
||||
}
|
||||
|
||||
void AtomMainDelegate::InitializeResourceBundle() {
|
||||
base::FilePath path;
|
||||
#if defined(OS_MACOSX)
|
||||
path = GetResourcesPakFilePath();
|
||||
#else
|
||||
base::FilePath pak_dir;
|
||||
PathService::Get(base::DIR_MODULE, &pak_dir);
|
||||
path = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
|
||||
#endif
|
||||
|
||||
ui::ResourceBundle::InitSharedInstanceWithPakPath(path);
|
||||
}
|
||||
|
||||
content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
|
||||
browser_client_.reset(new AtomBrowserClient);
|
||||
return browser_client_.get();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define ATOM_APP_ATOM_MAIN_DELEGATE_H_
|
||||
|
||||
#include "brightray/common/main_delegate.h"
|
||||
#include "brightray/common/content_client.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -15,14 +16,17 @@ class AtomMainDelegate : public brightray::MainDelegate {
|
|||
~AtomMainDelegate();
|
||||
|
||||
protected:
|
||||
// brightray::MainDelegate:
|
||||
virtual void AddDataPackFromPath(
|
||||
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) OVERRIDE;
|
||||
|
||||
// content::ContentMainDelegate:
|
||||
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
|
||||
virtual void PreSandboxStartup() OVERRIDE;
|
||||
virtual void InitializeResourceBundle();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
virtual base::FilePath GetResourcesPakFilePath();
|
||||
virtual void OverrideChildProcessPath();
|
||||
virtual void OverrideFrameworkBundlePath();
|
||||
virtual void OverrideChildProcessPath() OVERRIDE;
|
||||
virtual void OverrideFrameworkBundlePath() OVERRIDE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -30,6 +34,7 @@ class AtomMainDelegate : public brightray::MainDelegate {
|
|||
virtual content::ContentRendererClient*
|
||||
CreateContentRendererClient() OVERRIDE;
|
||||
|
||||
brightray::ContentClient content_client_;
|
||||
scoped_ptr<content::ContentBrowserClient> browser_client_;
|
||||
scoped_ptr<content::ContentRendererClient> renderer_client_;
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -109,8 +109,9 @@ int DockBounce(const std::string& type) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
Browser* browser = Browser::Get();
|
||||
CommandLine* command_line = CommandLine::ForCurrentProcess();
|
||||
|
||||
|
@ -140,4 +141,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_app, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_app, Initialize)
|
||||
|
|
|
@ -85,12 +85,13 @@ mate::Handle<AutoUpdater> AutoUpdater::Create(v8::Isolate* isolate) {
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("autoUpdater", atom::api::AutoUpdater::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_auto_updater, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_auto_updater, Initialize)
|
||||
|
|
|
@ -27,7 +27,7 @@ void ShowMessageBox(int type,
|
|||
mate::Arguments* args) {
|
||||
v8::Handle<v8::Value> peek = args->PeekNext();
|
||||
atom::MessageBoxCallback callback;
|
||||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(node_isolate,
|
||||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, title,
|
||||
|
@ -46,7 +46,7 @@ void ShowOpenDialog(const std::string& title,
|
|||
mate::Arguments* args) {
|
||||
v8::Handle<v8::Value> peek = args->PeekNext();
|
||||
file_dialog::OpenDialogCallback callback;
|
||||
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(node_isolate,
|
||||
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
file_dialog::ShowOpenDialog(window, title, default_path, properties,
|
||||
|
@ -65,7 +65,7 @@ void ShowSaveDialog(const std::string& title,
|
|||
mate::Arguments* args) {
|
||||
v8::Handle<v8::Value> peek = args->PeekNext();
|
||||
file_dialog::SaveDialogCallback callback;
|
||||
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(node_isolate,
|
||||
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
file_dialog::ShowSaveDialog(window, title, default_path, callback);
|
||||
|
@ -76,8 +76,9 @@ void ShowSaveDialog(const std::string& title,
|
|||
}
|
||||
}
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("showMessageBox", &ShowMessageBox);
|
||||
dict.SetMethod("showOpenDialog", &ShowOpenDialog);
|
||||
dict.SetMethod("showSaveDialog", &ShowSaveDialog);
|
||||
|
@ -85,4 +86,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_dialog, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_dialog, Initialize)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/constructor.h"
|
||||
|
@ -20,26 +20,23 @@ namespace api {
|
|||
namespace {
|
||||
|
||||
// Call method of delegate object.
|
||||
v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
|
||||
v8::Handle<v8::Value> CallDelegate(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> default_value,
|
||||
v8::Handle<v8::Object> menu,
|
||||
const char* method,
|
||||
int command_id) {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
|
||||
v8::Handle<v8::Value> delegate = menu->Get(v8::String::New("delegate"));
|
||||
v8::Handle<v8::Value> delegate = menu->Get(
|
||||
MATE_STRING_NEW(isolate, "delegate"));
|
||||
if (!delegate->IsObject())
|
||||
return default_value;
|
||||
|
||||
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(
|
||||
delegate->ToObject()->Get(v8::String::New(method)));
|
||||
delegate->ToObject()->Get(MATE_STRING_NEW(isolate, method)));
|
||||
if (!function->IsFunction())
|
||||
return default_value;
|
||||
|
||||
v8::Handle<v8::Value> argv = v8::Integer::New(command_id);
|
||||
|
||||
return handle_scope.Close(
|
||||
function->Call(v8::Context::GetCurrent()->Global(), 1, &argv));
|
||||
v8::Handle<v8::Value> argv = MATE_INTEGER_NEW(isolate, command_id);
|
||||
return function->Call(isolate->GetCurrentContext()->Global(), 1, &argv);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -53,38 +50,46 @@ Menu::~Menu() {
|
|||
}
|
||||
|
||||
bool Menu::IsCommandIdChecked(int command_id) const {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
return CallDelegate(v8::False(),
|
||||
const_cast<Menu*>(this)->GetWrapper(node_isolate),
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
return CallDelegate(isolate,
|
||||
MATE_FALSE(isolate),
|
||||
const_cast<Menu*>(this)->GetWrapper(isolate),
|
||||
"isCommandIdChecked",
|
||||
command_id)->BooleanValue();
|
||||
}
|
||||
|
||||
bool Menu::IsCommandIdEnabled(int command_id) const {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
return CallDelegate(v8::True(),
|
||||
const_cast<Menu*>(this)->GetWrapper(node_isolate),
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
return CallDelegate(isolate,
|
||||
MATE_TRUE(isolate),
|
||||
const_cast<Menu*>(this)->GetWrapper(isolate),
|
||||
"isCommandIdEnabled",
|
||||
command_id)->BooleanValue();
|
||||
}
|
||||
|
||||
bool Menu::IsCommandIdVisible(int command_id) const {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
return CallDelegate(v8::True(),
|
||||
const_cast<Menu*>(this)->GetWrapper(node_isolate),
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
return CallDelegate(isolate,
|
||||
MATE_TRUE(isolate),
|
||||
const_cast<Menu*>(this)->GetWrapper(isolate),
|
||||
"isCommandIdVisible",
|
||||
command_id)->BooleanValue();
|
||||
}
|
||||
|
||||
bool Menu::GetAcceleratorForCommandId(int command_id,
|
||||
ui::Accelerator* accelerator) {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
v8::Handle<v8::Value> shortcut = CallDelegate(v8::Undefined(),
|
||||
GetWrapper(node_isolate),
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Value> shortcut = CallDelegate(isolate,
|
||||
MATE_UNDEFINED(isolate),
|
||||
GetWrapper(isolate),
|
||||
"getAcceleratorForCommandId",
|
||||
command_id);
|
||||
if (shortcut->IsString()) {
|
||||
|
@ -96,51 +101,64 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
|
|||
}
|
||||
|
||||
bool Menu::IsItemForCommandIdDynamic(int command_id) const {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
return CallDelegate(v8::False(),
|
||||
const_cast<Menu*>(this)->GetWrapper(node_isolate),
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
return CallDelegate(isolate,
|
||||
MATE_FALSE(isolate),
|
||||
const_cast<Menu*>(this)->GetWrapper(isolate),
|
||||
"isItemForCommandIdDynamic",
|
||||
command_id)->BooleanValue();
|
||||
}
|
||||
|
||||
string16 Menu::GetLabelForCommandId(int command_id) const {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
base::string16 Menu::GetLabelForCommandId(int command_id) const {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Value> result = CallDelegate(
|
||||
v8::False(),
|
||||
const_cast<Menu*>(this)->GetWrapper(node_isolate),
|
||||
isolate,
|
||||
MATE_FALSE(isolate),
|
||||
const_cast<Menu*>(this)->GetWrapper(isolate),
|
||||
"getLabelForCommandId",
|
||||
command_id);
|
||||
string16 label;
|
||||
mate::ConvertFromV8(node_isolate, result, &label);
|
||||
base::string16 label;
|
||||
mate::ConvertFromV8(isolate, result, &label);
|
||||
return label;
|
||||
}
|
||||
|
||||
string16 Menu::GetSublabelForCommandId(int command_id) const {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
base::string16 Menu::GetSublabelForCommandId(int command_id) const {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Value> result = CallDelegate(
|
||||
v8::False(),
|
||||
const_cast<Menu*>(this)->GetWrapper(node_isolate),
|
||||
isolate,
|
||||
MATE_FALSE(isolate),
|
||||
const_cast<Menu*>(this)->GetWrapper(isolate),
|
||||
"getSubLabelForCommandId",
|
||||
command_id);
|
||||
string16 label;
|
||||
mate::ConvertFromV8(node_isolate, result, &label);
|
||||
base::string16 label;
|
||||
mate::ConvertFromV8(isolate, result, &label);
|
||||
return label;
|
||||
}
|
||||
|
||||
void Menu::ExecuteCommand(int command_id, int event_flags) {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
CallDelegate(v8::False(), GetWrapper(node_isolate), "executeCommand",
|
||||
command_id);
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
CallDelegate(isolate, MATE_FALSE(isolate), GetWrapper(isolate),
|
||||
"executeCommand", command_id);
|
||||
}
|
||||
|
||||
void Menu::MenuWillShow(ui::SimpleMenuModel* source) {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
CallDelegate(v8::False(), GetWrapper(node_isolate), "menuWillShow", -1);
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
CallDelegate(isolate, MATE_FALSE(isolate), GetWrapper(isolate),
|
||||
"menuWillShow", -1);
|
||||
}
|
||||
|
||||
void Menu::AttachToWindow(Window* window) {
|
||||
window->window()->SetMenu(model_.get());
|
||||
}
|
||||
|
||||
void Menu::InsertItemAt(
|
||||
|
@ -232,12 +250,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
||||
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
|
||||
.SetMethod("_attachToWindow", &Menu::AttachToWindow)
|
||||
#endif
|
||||
#if defined(OS_WIN)
|
||||
.SetMethod("_updateStates", &Menu::UpdateStates)
|
||||
#endif
|
||||
.SetMethod("attachToWindow", &Menu::AttachToWindow)
|
||||
.SetMethod("_popup", &Menu::Popup);
|
||||
}
|
||||
|
||||
|
@ -248,11 +261,13 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
using atom::api::Menu;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Function> constructor = mate::CreateConstructor<Menu>(
|
||||
node_isolate, "Menu", base::Bind(&Menu::Create));
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
isolate, "Menu", base::Bind(&Menu::Create));
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("Menu", static_cast<v8::Handle<v8::Value>>(constructor));
|
||||
#if defined(OS_MACOSX)
|
||||
dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu);
|
||||
|
@ -263,4 +278,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_menu, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_menu, Initialize)
|
||||
|
|
|
@ -48,11 +48,12 @@ class Menu : public mate::Wrappable,
|
|||
int command_id,
|
||||
ui::Accelerator* accelerator) OVERRIDE;
|
||||
virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
|
||||
virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
|
||||
virtual string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
|
||||
virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE;
|
||||
virtual base::string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
|
||||
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
|
||||
virtual void MenuWillShow(ui::SimpleMenuModel* source) OVERRIDE;
|
||||
|
||||
virtual void AttachToWindow(Window* window);
|
||||
virtual void Popup(Window* window) = 0;
|
||||
|
||||
scoped_ptr<ui::SimpleMenuModel> model_;
|
||||
|
@ -83,14 +84,6 @@ class Menu : public mate::Wrappable,
|
|||
bool IsEnabledAt(int index) const;
|
||||
bool IsVisibleAt(int index) const;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
virtual void UpdateStates() = 0;
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
|
||||
virtual void AttachToWindow(Window* window) = 0;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Menu);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_menu_gtk.h"
|
||||
|
||||
#include "atom/browser/native_window_gtk.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
MenuGtk::MenuGtk() {
|
||||
}
|
||||
|
||||
void MenuGtk::Popup(Window* window) {
|
||||
uint32_t triggering_event_time;
|
||||
gfx::Point point;
|
||||
|
||||
NativeWindow* native_window = window->window();
|
||||
GdkEventButton* event = native_window->GetWebContents()->
|
||||
GetRenderWidgetHostView()->GetLastMouseDown();
|
||||
if (event) {
|
||||
triggering_event_time = event->time;
|
||||
point = gfx::Point(event->x_root, event->y_root);
|
||||
} else {
|
||||
triggering_event_time = GDK_CURRENT_TIME;
|
||||
point = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
}
|
||||
|
||||
menu_gtk_.reset(new ::MenuGtk(this, model_.get()));
|
||||
menu_gtk_->PopupAsContext(point, triggering_event_time);
|
||||
}
|
||||
|
||||
void MenuGtk::AttachToWindow(Window* window) {
|
||||
static_cast<NativeWindowGtk*>(window->window())->SetMenu(model_.get());
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Menu::Create() {
|
||||
return new MenuGtk();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
|
@ -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_
|
45
atom/browser/api/atom_api_menu_views.cc
Normal file
45
atom/browser/api/atom_api_menu_views.cc
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_menu_views.h"
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
MenuViews::MenuViews() {
|
||||
}
|
||||
|
||||
void MenuViews::Popup(Window* window) {
|
||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
#if defined(OS_WIN)
|
||||
cursor = gfx::win::ScreenToDIPPoint(cursor);
|
||||
#endif
|
||||
|
||||
views::MenuRunner menu_runner(model());
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
static_cast<NativeWindowViews*>(window->window())->widget(),
|
||||
NULL,
|
||||
gfx::Rect(cursor, gfx::Size()),
|
||||
views::MenuItemView::TOPLEFT,
|
||||
ui::MENU_SOURCE_MOUSE,
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Menu::Create() {
|
||||
return new MenuViews();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
29
atom/browser/api/atom_api_menu_views.h
Normal file
29
atom/browser/api/atom_api_menu_views.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
|
||||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class MenuViews : public Menu {
|
||||
public:
|
||||
MenuViews();
|
||||
|
||||
protected:
|
||||
virtual void Popup(Window* window) OVERRIDE;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuViews);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_menu_win.h"
|
||||
|
||||
#include "atom/browser/native_window_win.h"
|
||||
#include "atom/browser/ui/win/menu_2.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
MenuWin::MenuWin() : menu_(NULL) {
|
||||
}
|
||||
|
||||
void MenuWin::Popup(Window* window) {
|
||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
popup_menu_.reset(new atom::Menu2(model_.get()));
|
||||
menu_ = popup_menu_.get();
|
||||
menu_->RunContextMenuAt(cursor);
|
||||
}
|
||||
|
||||
void MenuWin::UpdateStates() {
|
||||
MenuWin* top = this;
|
||||
while (top->parent_)
|
||||
top = static_cast<MenuWin*>(top->parent_);
|
||||
if (top->menu_)
|
||||
top->menu_->UpdateStates();
|
||||
}
|
||||
|
||||
void MenuWin::AttachToWindow(Window* window) {
|
||||
NativeWindowWin* nw = static_cast<NativeWindowWin*>(window->window());
|
||||
nw->SetMenu(model_.get());
|
||||
menu_ = nw->menu();
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Menu::Create() {
|
||||
return new MenuWin();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_
|
||||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
|
||||
namespace api {
|
||||
|
||||
class MenuWin : public Menu {
|
||||
public:
|
||||
MenuWin();
|
||||
|
||||
protected:
|
||||
virtual void Popup(Window* window) OVERRIDE;
|
||||
virtual void UpdateStates() OVERRIDE;
|
||||
virtual void AttachToWindow(Window* window) OVERRIDE;
|
||||
|
||||
private:
|
||||
atom::Menu2* menu_; // Weak ref, could be window menu or popup menu.
|
||||
scoped_ptr<atom::Menu2> popup_menu_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuWin);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_
|
|
@ -49,13 +49,14 @@ mate::Handle<PowerMonitor> PowerMonitor::Create(v8::Isolate* isolate) {
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
#if defined(OS_MACOSX)
|
||||
base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
|
||||
#endif
|
||||
|
||||
using atom::api::PowerMonitor;
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Handle<PowerMonitor> power_monitor = PowerMonitor::Create(isolate);
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("powerMonitor", power_monitor);
|
||||
|
@ -63,4 +64,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_power_monitor, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_monitor, Initialize)
|
||||
|
|
|
@ -58,8 +58,9 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
|||
virtual void GetJobTypeInUI() OVERRIDE {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
// Call the JS handler.
|
||||
Protocol::JsProtocolHandler callback =
|
||||
|
@ -75,7 +76,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
|||
return;
|
||||
} else if (result->IsObject()) {
|
||||
v8::Handle<v8::Object> obj = result->ToObject();
|
||||
mate::Dictionary dict(node_isolate, obj);
|
||||
mate::Dictionary dict(isolate, obj);
|
||||
std::string name = mate::V8ToString(obj->GetConstructorName());
|
||||
if (name == "RequestStringJob") {
|
||||
std::string mime_type, charset, data;
|
||||
|
@ -321,16 +322,17 @@ mate::Handle<Protocol> Protocol::Create(v8::Isolate* isolate) {
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
// Make sure the job factory has been created.
|
||||
atom::AtomBrowserContext::Get()->url_request_context_getter()->
|
||||
GetURLRequestContext();
|
||||
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("protocol", atom::api::Protocol::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_protocol, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_protocol, Initialize)
|
||||
|
|
|
@ -69,9 +69,10 @@ void Tray::BuildPrototype(v8::Isolate* isolate,
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
using atom::api::Tray;
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Handle<v8::Function> constructor = mate::CreateConstructor<Tray>(
|
||||
isolate, "Tray", base::Bind(&Tray::New));
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
|
@ -80,4 +81,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_tray, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_tray, Initialize)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -46,10 +46,11 @@ namespace api {
|
|||
namespace {
|
||||
|
||||
void OnCapturePageDone(
|
||||
v8::Isolate* isolate,
|
||||
const base::Callback<void(v8::Handle<v8::Value>)>& callback,
|
||||
const std::vector<unsigned char>& data) {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::Value> buffer = node::Buffer::New(
|
||||
reinterpret_cast<const char*>(data.data()),
|
||||
|
@ -311,7 +312,8 @@ void Window::CapturePage(mate::Arguments* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
window_->CapturePage(rect, base::Bind(&OnCapturePageDone, callback));
|
||||
window_->CapturePage(
|
||||
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
|
||||
}
|
||||
|
||||
void Window::SetRepresentedFilename(const std::string& filename) {
|
||||
|
@ -391,14 +393,16 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
using atom::api::Window;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Function> constructor = mate::CreateConstructor<Window>(
|
||||
node_isolate, "BrowserWindow", base::Bind(&Window::New));
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
isolate, "BrowserWindow", base::Bind(&Window::New));
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("BrowserWindow", static_cast<v8::Handle<v8::Value>>(constructor));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_browser_window, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_window, Initialize)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_; }
|
||||
|
|
|
@ -31,20 +31,21 @@ bool EventEmitter::Emit(const base::StringPiece& name,
|
|||
const base::ListValue& args,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message) {
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
|
||||
v8::Handle<v8::Context> context = isolate->GetCurrentContext();
|
||||
scoped_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter);
|
||||
|
||||
mate::Handle<mate::Event> event = mate::Event::Create(node_isolate);
|
||||
mate::Handle<mate::Event> event = mate::Event::Create(isolate);
|
||||
if (sender && message)
|
||||
event->SetSenderAndMessage(sender, message);
|
||||
|
||||
// v8_args = [name, event, args...];
|
||||
std::vector<v8::Handle<v8::Value>> v8_args;
|
||||
v8_args.reserve(args.GetSize() + 2);
|
||||
v8_args.push_back(mate::StringToV8(node_isolate, name));
|
||||
v8_args.push_back(mate::StringToV8(isolate, name));
|
||||
v8_args.push_back(event.ToV8());
|
||||
for (size_t i = 0; i < args.GetSize(); i++) {
|
||||
const base::Value* value(NULL);
|
||||
|
@ -53,8 +54,8 @@ bool EventEmitter::Emit(const base::StringPiece& name,
|
|||
}
|
||||
|
||||
// this.emit.apply(this, v8_args);
|
||||
node::MakeCallback(
|
||||
GetWrapper(node_isolate), "emit", v8_args.size(), &v8_args[0]);
|
||||
node::MakeCallback(isolate, GetWrapper(isolate), "emit", v8_args.size(),
|
||||
&v8_args[0]);
|
||||
|
||||
return event->prevent_default();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -26,6 +26,10 @@ struct FindByProcessId {
|
|||
}
|
||||
|
||||
bool operator() (NativeWindow* const window) {
|
||||
content::WebContents* web_contents = window->GetWebContents();
|
||||
if (!web_contents)
|
||||
return false;
|
||||
|
||||
int id = window->GetWebContents()->GetRenderProcessHost()->GetID();
|
||||
return id == child_process_id_;
|
||||
}
|
||||
|
@ -44,7 +48,8 @@ AtomBrowserClient::~AtomBrowserClient() {
|
|||
|
||||
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
|
||||
content::BrowserContext* browser_context,
|
||||
content::ProtocolHandlerMap* protocol_handlers) {
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::ProtocolHandlerScopedVector protocol_interceptors) {
|
||||
return static_cast<AtomBrowserContext*>(browser_context)->
|
||||
CreateRequestContext(protocol_handlers);
|
||||
}
|
||||
|
@ -77,7 +82,7 @@ void AtomBrowserClient::OverrideWebkitPrefs(
|
|||
window->OverrideWebkitPrefs(url, prefs);
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::ShouldSwapProcessesForNavigation(
|
||||
bool AtomBrowserClient::ShouldSwapBrowsingInstancesForNavigation(
|
||||
content::SiteInstance* site_instance,
|
||||
const GURL& current_url,
|
||||
const GURL& new_url) {
|
||||
|
@ -94,7 +99,7 @@ std::string AtomBrowserClient::GetApplicationLocale() {
|
|||
}
|
||||
|
||||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
CommandLine* command_line,
|
||||
base::CommandLine* command_line,
|
||||
int child_process_id) {
|
||||
WindowList* list = WindowList::GetInstance();
|
||||
NativeWindow* window = NULL;
|
||||
|
@ -124,6 +129,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
|||
|
||||
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) {
|
||||
v8::V8::Initialize(); // Init V8 before creating main parts.
|
||||
return new AtomBrowserMainParts;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -9,12 +9,17 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "base/command_line.h"
|
||||
#include "net/proxy/proxy_resolver_v8.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
|
||||
#endif
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
@ -25,7 +30,12 @@ AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
|||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: atom_bindings_(new AtomBindings),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)) {
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
isolate_(v8::Isolate::GetCurrent()),
|
||||
locker_(isolate_),
|
||||
handle_scope_(isolate_),
|
||||
context_(isolate_, v8::Context::New(isolate_)),
|
||||
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
|
||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||
self_ = this;
|
||||
}
|
||||
|
@ -43,31 +53,34 @@ brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
|
|||
return new AtomBrowserContext();
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::InitProxyResolverV8() {
|
||||
// Since we are integrating node in browser, we can just be sure that an
|
||||
// V8 instance would be prepared, while the ProxyResolverV8::CreateIsolate()
|
||||
// would try to create a V8 isolate, which messed everything on Windows, so
|
||||
// we have to override and call RememberDefaultIsolate on Windows instead.
|
||||
net::ProxyResolverV8::RememberDefaultIsolate();
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
node_bindings_->Initialize();
|
||||
|
||||
v8::V8::Initialize();
|
||||
|
||||
// Create context.
|
||||
v8::Locker locker(node_isolate);
|
||||
v8::HandleScope handle_scope(node_isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(node_isolate);
|
||||
|
||||
// Create the global environment.
|
||||
global_env = node_bindings_->CreateEnvironment(context);
|
||||
|
||||
// Wrap whole process in one global context.
|
||||
context->Enter();
|
||||
global_env = node_bindings_->CreateEnvironment(
|
||||
v8::Local<v8::Context>::New(isolate_, context_));
|
||||
|
||||
// Add atom-shell extended APIs.
|
||||
atom_bindings_->BindTo(global_env->process_object());
|
||||
atom_bindings_->BindTo(isolate_, global_env->process_object());
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||
|
||||
#if defined(USE_X11)
|
||||
libgtk2ui::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
|
||||
#endif
|
||||
|
||||
node_bindings_->PrepareMessageLoop();
|
||||
node_bindings_->RunMessageLoop();
|
||||
|
||||
|
@ -83,19 +96,4 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
|||
#endif
|
||||
}
|
||||
|
||||
int AtomBrowserMainParts::PreCreateThreads() {
|
||||
// Note that we are overriding the PreCreateThreads of brightray, since we
|
||||
// are integrating node in browser, we can just be sure that an V8 instance
|
||||
// would be prepared, while the ProxyResolverV8::CreateIsolate() would
|
||||
// try to create a V8 isolate, which messed everything on Windows, so we
|
||||
// have to override and call RememberDefaultIsolate on Windows instead.
|
||||
net::ProxyResolverV8::RememberDefaultIsolate();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
gfx::EnableHighDPISupport();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
|
||||
|
||||
#include "brightray/browser/browser_main_parts.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -25,11 +26,11 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
protected:
|
||||
// Implementations of brightray::BrowserMainParts.
|
||||
virtual brightray::BrowserContext* CreateBrowserContext() OVERRIDE;
|
||||
virtual void InitProxyResolverV8() OVERRIDE;
|
||||
|
||||
// Implementations of content::BrowserMainParts.
|
||||
virtual void PostEarlyInitialization() OVERRIDE;
|
||||
virtual void PreMainMessageLoopRun() OVERRIDE;
|
||||
virtual int PreCreateThreads() OVERRIDE;
|
||||
#if defined(OS_MACOSX)
|
||||
virtual void PreMainMessageLoopStart() OVERRIDE;
|
||||
virtual void PostDestroyThreads() OVERRIDE;
|
||||
|
@ -40,6 +41,13 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
|
||||
// The V8 environment of browser process.
|
||||
v8::Isolate* isolate_;
|
||||
v8::Locker locker_;
|
||||
v8::HandleScope handle_scope_;
|
||||
v8::UniquePersistent<v8::Context> context_;
|
||||
v8::Context::Scope context_scope_;
|
||||
|
||||
static AtomBrowserMainParts* self_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -44,7 +44,7 @@ std::string Browser::GetExecutableFileVersion() const {
|
|||
if (PathService::Get(base::FILE_EXE, &path)) {
|
||||
scoped_ptr<FileVersionInfo> version_info(
|
||||
FileVersionInfo::CreateFileVersionInfo(path));
|
||||
return UTF16ToUTF8(version_info->product_version());
|
||||
return base::UTF16ToUTF8(version_info->product_version());
|
||||
}
|
||||
|
||||
return ATOM_VERSION_STRING;
|
||||
|
@ -55,7 +55,7 @@ std::string Browser::GetExecutableFileProductName() const {
|
|||
if (PathService::Get(base::FILE_EXE, &path)) {
|
||||
scoped_ptr<FileVersionInfo> version_info(
|
||||
FileVersionInfo::CreateFileVersionInfo(path));
|
||||
return UTF16ToUTF8(version_info->product_name());
|
||||
return base::UTF16ToUTF8(version_info->product_name());
|
||||
}
|
||||
|
||||
return "Atom-Shell";
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<h2>Welcome to Atom Shell</h2>
|
||||
<h2 style="-webkit-app-region: drag">Welcome to Atom Shell</h2>
|
||||
|
||||
<p>
|
||||
To run your app with atom-shell, execute the following command under your
|
||||
|
|
|
@ -34,11 +34,13 @@
|
|||
#include "content/public/browser/notification_source.h"
|
||||
#include "content/public/browser/notification_types.h"
|
||||
#include "content/public/browser/plugin_service.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "content/public/common/renderer_preferences.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
|
@ -49,7 +51,6 @@
|
|||
#include "ui/gfx/size.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "webkit/common/user_agent/user_agent_util.h"
|
||||
#include "webkit/common/webpreferences.h"
|
||||
|
||||
using content::NavigationEntry;
|
||||
|
@ -69,12 +70,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
|||
brightray::InspectableWebContents::Create(web_contents)) {
|
||||
options.Get(switches::kFrame, &has_frame_);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Temporary fix for flashing devtools, try removing this after upgraded to
|
||||
// Chrome 32.
|
||||
web_contents->GetView()->SetAllowOverlappingViews(false);
|
||||
#endif
|
||||
|
||||
// Read icon before window is created.
|
||||
gfx::ImageSkia icon;
|
||||
if (options.Get(switches::kIcon, &icon))
|
||||
|
@ -84,9 +79,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
|||
options.Get(switches::kNodeIntegration, &node_integration_);
|
||||
|
||||
// Read the web preferences.
|
||||
scoped_ptr<mate::Dictionary> web_preferences(new mate::Dictionary);
|
||||
if (options.Get(switches::kWebPreferences, web_preferences.get()))
|
||||
web_preferences_.reset(web_preferences.release());
|
||||
options.Get(switches::kWebPreferences, &web_preferences_);
|
||||
|
||||
// Read the zoom factor before any navigation.
|
||||
options.Get(switches::kZoomFactor, &zoom_factor_);
|
||||
|
@ -104,7 +97,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
|||
browser->GetVersion().c_str(),
|
||||
CHROME_VERSION_STRING);
|
||||
web_contents->GetMutableRendererPrefs()->user_agent_override =
|
||||
webkit_glue::BuildUserAgentFromProduct(product_name);
|
||||
content::BuildUserAgentFromProduct(product_name);
|
||||
|
||||
// Get notified of title updated message.
|
||||
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
|
||||
|
@ -202,17 +195,15 @@ void NativeWindow::SetRepresentedFilename(const std::string& filename) {
|
|||
void NativeWindow::SetDocumentEdited(bool edited) {
|
||||
}
|
||||
|
||||
void NativeWindow::SetMenu(ui::MenuModel* menu) {
|
||||
}
|
||||
|
||||
bool NativeWindow::HasModalDialog() {
|
||||
return has_dialog_attached_;
|
||||
}
|
||||
|
||||
void NativeWindow::OpenDevTools() {
|
||||
inspectable_web_contents()->ShowDevTools();
|
||||
#if defined(OS_MACOSX)
|
||||
// Temporary fix for flashing devtools, try removing this after upgraded to
|
||||
// Chrome 32.
|
||||
GetDevToolsWebContents()->GetView()->SetAllowOverlappingViews(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindow::CloseDevTools() {
|
||||
|
@ -271,7 +262,8 @@ void NativeWindow::CapturePage(const gfx::Rect& rect,
|
|||
size,
|
||||
base::Bind(&NativeWindow::OnCapturePageDone,
|
||||
weak_factory_.GetWeakPtr(),
|
||||
callback));
|
||||
callback),
|
||||
SkBitmap::kARGB_8888_Config);
|
||||
}
|
||||
|
||||
void NativeWindow::DestroyWebContents() {
|
||||
|
@ -305,7 +297,7 @@ void NativeWindow::CloseWebContents() {
|
|||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
if (web_contents->NeedToFireBeforeUnload())
|
||||
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
|
||||
web_contents->GetMainFrame()->DispatchBeforeUnload(false);
|
||||
else
|
||||
web_contents->Close();
|
||||
}
|
||||
|
@ -322,8 +314,8 @@ content::WebContents* NativeWindow::GetDevToolsWebContents() const {
|
|||
return inspectable_web_contents()->devtools_web_contents();
|
||||
}
|
||||
|
||||
void NativeWindow::AppendExtraCommandLineSwitches(CommandLine* command_line,
|
||||
int child_process_id) {
|
||||
void NativeWindow::AppendExtraCommandLineSwitches(
|
||||
base::CommandLine* command_line, int child_process_id) {
|
||||
// Append --node-integration to renderer process.
|
||||
command_line->AppendSwitchASCII(switches::kNodeIntegration,
|
||||
node_integration_);
|
||||
|
@ -335,33 +327,32 @@ void NativeWindow::AppendExtraCommandLineSwitches(CommandLine* command_line,
|
|||
}
|
||||
|
||||
void NativeWindow::OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs) {
|
||||
// FIXME Disable accelerated composition in frameless window.
|
||||
if (!has_frame_)
|
||||
prefs->accelerated_compositing_enabled = false;
|
||||
if (web_preferences_.IsEmpty())
|
||||
return;
|
||||
|
||||
bool b;
|
||||
std::vector<base::FilePath> list;
|
||||
if (!web_preferences_)
|
||||
return;
|
||||
if (web_preferences_->Get("javascript", &b))
|
||||
mate::Dictionary web_preferences(web_preferences_.isolate(),
|
||||
web_preferences_.NewHandle());
|
||||
if (web_preferences.Get("javascript", &b))
|
||||
prefs->javascript_enabled = b;
|
||||
if (web_preferences_->Get("web-security", &b))
|
||||
if (web_preferences.Get("web-security", &b))
|
||||
prefs->web_security_enabled = b;
|
||||
if (web_preferences_->Get("images", &b))
|
||||
if (web_preferences.Get("images", &b))
|
||||
prefs->images_enabled = b;
|
||||
if (web_preferences_->Get("java", &b))
|
||||
if (web_preferences.Get("java", &b))
|
||||
prefs->java_enabled = b;
|
||||
if (web_preferences_->Get("text-areas-are-resizable", &b))
|
||||
if (web_preferences.Get("text-areas-are-resizable", &b))
|
||||
prefs->text_areas_are_resizable = b;
|
||||
if (web_preferences_->Get("webgl", &b))
|
||||
if (web_preferences.Get("webgl", &b))
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (web_preferences_->Get("webaudio", &b))
|
||||
if (web_preferences.Get("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (web_preferences_->Get("accelerated-compositing", &b))
|
||||
if (web_preferences.Get("accelerated-compositing", &b))
|
||||
prefs->accelerated_compositing_enabled = b;
|
||||
if (web_preferences_->Get("plugins", &b))
|
||||
if (web_preferences.Get("plugins", &b))
|
||||
prefs->plugins_enabled = b;
|
||||
if (web_preferences_->Get("extra-plugin-dirs", &list))
|
||||
if (web_preferences.Get("extra-plugin-dirs", &list))
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
content::PluginService::GetInstance()->AddExtraPluginDir(list[i]);
|
||||
}
|
||||
|
@ -517,7 +508,7 @@ void NativeWindow::Observe(int type,
|
|||
|
||||
if (title->first) {
|
||||
bool prevent_default = false;
|
||||
std::string text = UTF16ToUTF8(title->first->GetTitle());
|
||||
std::string text = base::UTF16ToUTF8(title->first->GetTitle());
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnPageTitleUpdated(&prevent_default, text));
|
||||
|
@ -537,19 +528,19 @@ void NativeWindow::DevToolsSaveToFile(const std::string& url,
|
|||
path = it->second;
|
||||
} else {
|
||||
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url));
|
||||
if (!file_dialog::ShowSaveDialog(this, url, default_path, &path))
|
||||
if (!file_dialog::ShowSaveDialog(this, url, default_path, &path)) {
|
||||
base::StringValue url_value(url);
|
||||
CallDevToolsFunction("InspectorFrontendAPI.canceledSaveURL", &url_value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
saved_files_[url] = path;
|
||||
file_util::WriteFile(path, content.data(), content.size());
|
||||
base::WriteFile(path, content.data(), content.size());
|
||||
|
||||
// Notify devtools.
|
||||
base::StringValue url_value(url);
|
||||
CallDevToolsFunction("InspectorFrontendAPI.savedURL", &url_value);
|
||||
|
||||
// TODO(zcbenz): In later Chrome we need to call canceledSaveURL when the save
|
||||
// failed.
|
||||
}
|
||||
|
||||
void NativeWindow::DevToolsAppendToFile(const std::string& url,
|
||||
|
@ -557,7 +548,7 @@ void NativeWindow::DevToolsAppendToFile(const std::string& url,
|
|||
PathsMap::iterator it = saved_files_.find(url);
|
||||
if (it == saved_files_.end())
|
||||
return;
|
||||
file_util::AppendToFile(it->second, content.data(), content.size());
|
||||
base::AppendToFile(it->second, content.data(), content.size());
|
||||
|
||||
// Notify devtools.
|
||||
base::StringValue url_value(url);
|
||||
|
@ -613,8 +604,9 @@ void NativeWindow::CallDevToolsFunction(const std::string& function_name,
|
|||
}
|
||||
}
|
||||
}
|
||||
GetDevToolsWebContents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
|
||||
string16(), base::UTF8ToUTF16(function_name + "(" + params + ");"));
|
||||
base::string16 javascript =
|
||||
base::UTF8ToUTF16(function_name + "(" + params + ");");
|
||||
GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -16,15 +16,20 @@
|
|||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "atom/browser/native_window_observer.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
#include "vendor/brightray/browser/default_web_contents_delegate.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_delegate.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_impl.h"
|
||||
|
||||
class CommandLine;
|
||||
struct WebPreferences;
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class WebContents;
|
||||
|
@ -41,6 +46,10 @@ namespace mate {
|
|||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
|
@ -127,6 +136,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
|||
virtual bool IsKiosk() = 0;
|
||||
virtual void SetRepresentedFilename(const std::string& filename);
|
||||
virtual void SetDocumentEdited(bool edited);
|
||||
virtual void SetMenu(ui::MenuModel* menu);
|
||||
virtual bool HasModalDialog();
|
||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||
|
||||
|
@ -161,7 +171,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
|||
content::WebContents* GetDevToolsWebContents() const;
|
||||
|
||||
// Called when renderer process is going to be started.
|
||||
void AppendExtraCommandLineSwitches(CommandLine* command_line,
|
||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
|
||||
int child_process_id);
|
||||
void OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs);
|
||||
|
||||
|
@ -281,7 +291,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
|||
base::CancelableClosure window_unresposive_closure_;
|
||||
|
||||
// Web preferences.
|
||||
scoped_ptr<mate::Dictionary> web_preferences_;
|
||||
mate::ScopedPersistent<v8::Object> web_preferences_;
|
||||
|
||||
// Page's default zoom factor.
|
||||
double zoom_factor_;
|
||||
|
|
|
@ -1,616 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/native_window_gtk.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/draggable_region.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "chrome/browser/ui/gtk/gtk_window_util.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "content/public/common/renderer_preferences.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_gtk.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/base/x/active_window_watcher_x.h"
|
||||
#include "ui/base/x/x11_util.h"
|
||||
#include "ui/gfx/font_render_params_linux.h"
|
||||
#include "ui/gfx/gtk_util.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/skia_utils_gtk.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Dividing GTK's cursor blink cycle time (in milliseconds) by this value yields
|
||||
// an appropriate value for content::RendererPreferences::caret_blink_interval.
|
||||
// This matches the logic in the WebKit GTK port.
|
||||
const double kGtkCursorBlinkCycleFactor = 2000.0;
|
||||
|
||||
// Substract window border's size from window size according to current window
|
||||
// manager.
|
||||
void SubstractBorderSize(int* width, int* height) {
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
base::nix::DesktopEnvironment de(base::nix::GetDesktopEnvironment(env.get()));
|
||||
if (de == base::nix::DESKTOP_ENVIRONMENT_UNITY) {
|
||||
*width -= 2;
|
||||
*height -= 29;
|
||||
} else if (de == base::nix::DESKTOP_ENVIRONMENT_GNOME) {
|
||||
*width -= 2;
|
||||
*height -= 33;
|
||||
} else if (de == base::nix::DESKTOP_ENVIRONMENT_XFCE) {
|
||||
*width -= 6;
|
||||
*height -= 27;
|
||||
} else {
|
||||
*width -= 2;
|
||||
*height -= 29;
|
||||
}
|
||||
}
|
||||
|
||||
content::RendererPreferencesHintingEnum GetRendererPreferencesHintingEnum(
|
||||
gfx::FontRenderParams::Hinting hinting) {
|
||||
switch (hinting) {
|
||||
case gfx::FontRenderParams::HINTING_NONE:
|
||||
return content::RENDERER_PREFERENCES_HINTING_NONE;
|
||||
case gfx::FontRenderParams::HINTING_SLIGHT:
|
||||
return content::RENDERER_PREFERENCES_HINTING_SLIGHT;
|
||||
case gfx::FontRenderParams::HINTING_MEDIUM:
|
||||
return content::RENDERER_PREFERENCES_HINTING_MEDIUM;
|
||||
case gfx::FontRenderParams::HINTING_FULL:
|
||||
return content::RENDERER_PREFERENCES_HINTING_FULL;
|
||||
default:
|
||||
NOTREACHED() << "Unhandled hinting style " << hinting;
|
||||
return content::RENDERER_PREFERENCES_HINTING_SYSTEM_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
content::RendererPreferencesSubpixelRenderingEnum
|
||||
GetRendererPreferencesSubpixelRenderingEnum(
|
||||
gfx::FontRenderParams::SubpixelRendering subpixel_rendering) {
|
||||
switch (subpixel_rendering) {
|
||||
case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
|
||||
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_NONE;
|
||||
case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
|
||||
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_RGB;
|
||||
case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
|
||||
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_BGR;
|
||||
case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
|
||||
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VRGB;
|
||||
case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
|
||||
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VBGR;
|
||||
default:
|
||||
NOTREACHED() << "Unhandled subpixel rendering style "
|
||||
<< subpixel_rendering;
|
||||
return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_SYSTEM_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindowGtk::NativeWindowGtk(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
window_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))),
|
||||
vbox_(gtk_vbox_new(FALSE, 0)),
|
||||
state_(GDK_WINDOW_STATE_WITHDRAWN),
|
||||
is_always_on_top_(false),
|
||||
is_active_(false),
|
||||
suppress_window_raise_(false),
|
||||
has_ever_been_shown_(false),
|
||||
frame_cursor_(NULL) {
|
||||
gtk_container_add(GTK_CONTAINER(window_), vbox_);
|
||||
gtk_container_add(GTK_CONTAINER(vbox_),
|
||||
GetWebContents()->GetView()->GetNativeView());
|
||||
|
||||
int width = 800, height = 600;
|
||||
options.Get(switches::kWidth, &width);
|
||||
options.Get(switches::kHeight, &height);
|
||||
|
||||
bool use_content_size = false;
|
||||
options.Get(switches::kUseContentSize, &use_content_size);
|
||||
if (has_frame_ && !use_content_size)
|
||||
SubstractBorderSize(&width, &height);
|
||||
|
||||
// Force a size allocation so the web page of hidden window can have correct
|
||||
// value of $(window).width().
|
||||
GtkAllocation size = { 0, 0, width, height };
|
||||
gtk_widget_show_all(vbox_);
|
||||
gtk_widget_size_allocate(GTK_WIDGET(window_), &size);
|
||||
gtk_window_util::SetWindowSize(window_, gfx::Size(width, height));
|
||||
|
||||
// Create the underlying gdk window.
|
||||
gtk_widget_realize(GTK_WIDGET(window_));
|
||||
|
||||
if (icon_)
|
||||
gtk_window_set_icon(window_, icon_->ToGdkPixbuf());
|
||||
|
||||
ui::ActiveWindowWatcherX::AddObserver(this);
|
||||
|
||||
// In some (older) versions of compiz, raising top-level windows when they
|
||||
// are partially off-screen causes them to get snapped back on screen, not
|
||||
// always even on the current virtual desktop. If we are running under
|
||||
// compiz, suppress such raises, as they are not necessary in compiz anyway.
|
||||
if (ui::GuessWindowManager() == ui::WM_COMPIZ)
|
||||
suppress_window_raise_ = true;
|
||||
|
||||
g_signal_connect(window_, "delete-event",
|
||||
G_CALLBACK(OnWindowDeleteEventThunk), this);
|
||||
g_signal_connect(window_, "focus-out-event",
|
||||
G_CALLBACK(OnFocusOutThunk), this);
|
||||
g_signal_connect(window_, "focus-in-event",
|
||||
G_CALLBACK(OnFocusInThunk), this);
|
||||
g_signal_connect(window_, "window-state-event",
|
||||
G_CALLBACK(OnWindowStateThunk), this);
|
||||
|
||||
if (!has_frame_) {
|
||||
gtk_window_set_decorated(window_, false);
|
||||
|
||||
g_signal_connect(window_, "motion-notify-event",
|
||||
G_CALLBACK(OnMouseMoveEventThunk), this);
|
||||
g_signal_connect(window_, "button-press-event",
|
||||
G_CALLBACK(OnButtonPressThunk), this);
|
||||
}
|
||||
|
||||
SetWebKitColorStyle();
|
||||
SetFontRenderering();
|
||||
}
|
||||
|
||||
NativeWindowGtk::~NativeWindowGtk() {
|
||||
CloseImmediately();
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Close() {
|
||||
CloseWebContents();
|
||||
}
|
||||
|
||||
void NativeWindowGtk::CloseImmediately() {
|
||||
if (window_ == NULL)
|
||||
return;
|
||||
|
||||
NotifyWindowClosed();
|
||||
ui::ActiveWindowWatcherX::RemoveObserver(this);
|
||||
|
||||
gtk_widget_destroy(GTK_WIDGET(window_));
|
||||
window_ = NULL;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Move(const gfx::Rect& pos) {
|
||||
gtk_window_move(window_, pos.x(), pos.y());
|
||||
SetSize(pos.size());
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Focus(bool focus) {
|
||||
if (!IsVisible())
|
||||
return;
|
||||
|
||||
if (focus)
|
||||
gtk_window_present(window_);
|
||||
else
|
||||
gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsFocused() {
|
||||
if (ui::ActiveWindowWatcherX::WMSupportsActivation())
|
||||
return is_active_;
|
||||
|
||||
// This still works even though we don't get the activation notification.
|
||||
return gtk_window_is_active(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Show() {
|
||||
has_ever_been_shown_ = true;
|
||||
gtk_widget_show_all(GTK_WIDGET(window_));
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Hide() {
|
||||
gtk_widget_hide(GTK_WIDGET(window_));
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsVisible() {
|
||||
return gtk_widget_get_visible(GTK_WIDGET(window_));
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Maximize() {
|
||||
gtk_window_maximize(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Unmaximize() {
|
||||
gtk_window_unmaximize(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Minimize() {
|
||||
gtk_window_iconify(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Restore() {
|
||||
gtk_window_present(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetFullscreen(bool fullscreen) {
|
||||
if (fullscreen)
|
||||
gtk_window_fullscreen(window_);
|
||||
else
|
||||
gtk_window_unfullscreen(window_);
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsFullscreen() {
|
||||
return state_ & GDK_WINDOW_STATE_FULLSCREEN;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetSize(const gfx::Size& size) {
|
||||
// When the window has not been mapped the window size does not include frame.
|
||||
int width = size.width();
|
||||
int height = size.height();
|
||||
if (has_frame_ && !has_ever_been_shown_)
|
||||
SubstractBorderSize(&width, &height);
|
||||
|
||||
gtk_window_util::SetWindowSize(window_, gfx::Size(width, height));
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowGtk::GetSize() {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
|
||||
|
||||
GdkRectangle frame_extents;
|
||||
gdk_window_get_frame_extents(gdk_window, &frame_extents);
|
||||
|
||||
return gfx::Size(frame_extents.width, frame_extents.height);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame_ || !has_ever_been_shown_) {
|
||||
gtk_window_util::SetWindowSize(window_, size);
|
||||
} else {
|
||||
gfx::Size large = GetSize();
|
||||
gfx::Size small = GetContentSize();
|
||||
gfx::Size target(size.width() + large.width() - small.width(),
|
||||
size.height() + large.height() - small.height());
|
||||
gtk_window_util::SetWindowSize(window_, target);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowGtk::GetContentSize() {
|
||||
gint width, height;
|
||||
gtk_window_get_size(window_, &width, &height);
|
||||
return gfx::Size(width, height);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetMinimumSize(const gfx::Size& size) {
|
||||
minimum_size_ = size;
|
||||
|
||||
GdkGeometry geometry = { 0 };
|
||||
geometry.min_width = size.width();
|
||||
geometry.min_height = size.height();
|
||||
int hints = GDK_HINT_POS | GDK_HINT_MIN_SIZE;
|
||||
gtk_window_set_geometry_hints(
|
||||
window_, GTK_WIDGET(window_), &geometry, (GdkWindowHints)hints);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowGtk::GetMinimumSize() {
|
||||
return minimum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetMaximumSize(const gfx::Size& size) {
|
||||
maximum_size_ = size;
|
||||
|
||||
GdkGeometry geometry = { 0 };
|
||||
geometry.max_width = size.width();
|
||||
geometry.max_height = size.height();
|
||||
int hints = GDK_HINT_POS | GDK_HINT_MAX_SIZE;
|
||||
gtk_window_set_geometry_hints(
|
||||
window_, GTK_WIDGET(window_), &geometry, (GdkWindowHints)hints);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowGtk::GetMaximumSize() {
|
||||
return maximum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetResizable(bool resizable) {
|
||||
// Should request widget size after setting unresizable, otherwise the
|
||||
// window will shrink to a very small size.
|
||||
if (!IsResizable() || !has_ever_been_shown_) {
|
||||
gint width, height;
|
||||
gtk_window_get_size(window_, &width, &height);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(window_), width, height);
|
||||
}
|
||||
|
||||
gtk_window_set_resizable(window_, resizable);
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsResizable() {
|
||||
return gtk_window_get_resizable(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetAlwaysOnTop(bool top) {
|
||||
is_always_on_top_ = top;
|
||||
gtk_window_set_keep_above(window_, top ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsAlwaysOnTop() {
|
||||
return is_always_on_top_;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::Center() {
|
||||
gtk_window_set_position(window_, GTK_WIN_POS_CENTER);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetPosition(const gfx::Point& position) {
|
||||
gtk_window_move(window_, position.x(), position.y());
|
||||
}
|
||||
|
||||
gfx::Point NativeWindowGtk::GetPosition() {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
|
||||
|
||||
GdkRectangle frame_extents;
|
||||
gdk_window_get_frame_extents(gdk_window, &frame_extents);
|
||||
|
||||
return gfx::Point(frame_extents.x, frame_extents.y);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetTitle(const std::string& title) {
|
||||
gtk_window_set_title(window_, title.c_str());
|
||||
}
|
||||
|
||||
std::string NativeWindowGtk::GetTitle() {
|
||||
return gtk_window_get_title(window_);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::FlashFrame(bool flash) {
|
||||
gtk_window_set_urgency_hint(window_, flash);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetSkipTaskbar(bool skip) {
|
||||
gtk_window_set_skip_taskbar_hint(window_, skip);
|
||||
gtk_window_set_skip_pager_hint(window_, skip);
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetKiosk(bool kiosk) {
|
||||
SetFullscreen(kiosk);
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsKiosk() {
|
||||
return IsFullscreen();
|
||||
}
|
||||
|
||||
gfx::NativeWindow NativeWindowGtk::GetNativeWindow() {
|
||||
return window_;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetMenu(ui::MenuModel* menu_model) {
|
||||
menu_.reset(new ::MenuGtk(this, menu_model, true));
|
||||
gtk_box_pack_start(GTK_BOX(vbox_), menu_->widget(), FALSE, FALSE, 0);
|
||||
gtk_box_reorder_child(GTK_BOX(vbox_), menu_->widget(), 0);
|
||||
gtk_widget_show_all(vbox_);
|
||||
RegisterAccelerators();
|
||||
}
|
||||
|
||||
void NativeWindowGtk::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// Draggable region is not supported for non-frameless window.
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
draggable_region_.reset(new SkRegion);
|
||||
|
||||
// By default, the whole window is non-draggable. We need to explicitly
|
||||
// include those draggable regions.
|
||||
for (std::vector<DraggableRegion>::const_iterator iter =
|
||||
regions.begin();
|
||||
iter != regions.end(); ++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region_->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowGtk::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (event.type == WebKit::WebInputEvent::RawKeyDown) {
|
||||
GdkEventKey* os_event = reinterpret_cast<GdkEventKey*>(event.os_event);
|
||||
ui::Accelerator accelerator = ui::AcceleratorForGdkKeyCodeAndModifier(
|
||||
os_event->keyval, static_cast<GdkModifierType>(os_event->state));
|
||||
accelerator_util::TriggerAcceleratorTableCommand(&accelerator_table_,
|
||||
accelerator);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
|
||||
is_active_ = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::RegisterAccelerators() {
|
||||
DCHECK(menu_);
|
||||
accelerator_table_.clear();
|
||||
accelerator_util::GenerateAcceleratorTable(&accelerator_table_,
|
||||
menu_->model());
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetWebKitColorStyle() {
|
||||
content::RendererPreferences* prefs =
|
||||
GetWebContents()->GetMutableRendererPrefs();
|
||||
GtkStyle* frame_style = gtk_rc_get_style(GTK_WIDGET(window_));
|
||||
prefs->focus_ring_color =
|
||||
gfx::GdkColorToSkColor(frame_style->bg[GTK_STATE_SELECTED]);
|
||||
prefs->thumb_active_color = SkColorSetRGB(244, 244, 244);
|
||||
prefs->thumb_inactive_color = SkColorSetRGB(234, 234, 234);
|
||||
prefs->track_color = SkColorSetRGB(211, 211, 211);
|
||||
|
||||
GtkWidget* url_entry = gtk_entry_new();
|
||||
GtkStyle* entry_style = gtk_rc_get_style(url_entry);
|
||||
prefs->active_selection_bg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
|
||||
prefs->active_selection_fg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
|
||||
prefs->inactive_selection_bg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
|
||||
prefs->inactive_selection_fg_color =
|
||||
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]);
|
||||
gtk_widget_destroy(url_entry);
|
||||
|
||||
const base::TimeDelta cursor_blink_time = gfx::GetCursorBlinkCycle();
|
||||
prefs->caret_blink_interval =
|
||||
cursor_blink_time.InMilliseconds() ?
|
||||
cursor_blink_time.InMilliseconds() / kGtkCursorBlinkCycleFactor :
|
||||
0;
|
||||
}
|
||||
|
||||
void NativeWindowGtk::SetFontRenderering() {
|
||||
content::RendererPreferences* prefs =
|
||||
GetWebContents()->GetMutableRendererPrefs();
|
||||
const gfx::FontRenderParams& params = gfx::GetDefaultWebKitFontRenderParams();
|
||||
prefs->should_antialias_text = params.antialiasing;
|
||||
prefs->use_subpixel_positioning = params.subpixel_positioning;
|
||||
prefs->hinting = GetRendererPreferencesHintingEnum(params.hinting);
|
||||
prefs->use_autohinter = params.autohinter;
|
||||
prefs->use_bitmaps = params.use_bitmaps;
|
||||
prefs->subpixel_rendering =
|
||||
GetRendererPreferencesSubpixelRenderingEnum(params.subpixel_rendering);
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::IsMaximized() const {
|
||||
return state_ & GDK_WINDOW_STATE_MAXIMIZED;
|
||||
}
|
||||
|
||||
bool NativeWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) {
|
||||
if (has_frame_)
|
||||
return false;
|
||||
|
||||
if (IsMaximized() || IsFullscreen())
|
||||
return false;
|
||||
|
||||
return gtk_window_util::GetWindowEdge(GetSize(), 0, x, y, edge);
|
||||
}
|
||||
|
||||
gboolean NativeWindowGtk::OnWindowDeleteEvent(GtkWidget* widget,
|
||||
GdkEvent* event) {
|
||||
Close();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean NativeWindowGtk::OnFocusIn(GtkWidget* window, GdkEventFocus*) {
|
||||
NotifyWindowFocus();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean NativeWindowGtk::OnFocusOut(GtkWidget* window, GdkEventFocus*) {
|
||||
NotifyWindowBlur();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean NativeWindowGtk::OnWindowState(GtkWidget* window,
|
||||
GdkEventWindowState* event) {
|
||||
state_ = event->new_window_state;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean NativeWindowGtk::OnMouseMoveEvent(GtkWidget* widget,
|
||||
GdkEventMotion* event) {
|
||||
if (has_frame_) {
|
||||
// Reset the cursor.
|
||||
if (frame_cursor_) {
|
||||
frame_cursor_ = NULL;
|
||||
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!IsResizable())
|
||||
return FALSE;
|
||||
|
||||
// Update the cursor if we're on the custom frame border.
|
||||
GdkWindowEdge edge;
|
||||
bool has_hit_edge = GetWindowEdge(static_cast<int>(event->x),
|
||||
static_cast<int>(event->y), &edge);
|
||||
GdkCursorType new_cursor = GDK_LAST_CURSOR;
|
||||
if (has_hit_edge)
|
||||
new_cursor = gtk_window_util::GdkWindowEdgeToGdkCursorType(edge);
|
||||
|
||||
GdkCursorType last_cursor = GDK_LAST_CURSOR;
|
||||
if (frame_cursor_)
|
||||
last_cursor = frame_cursor_->type;
|
||||
|
||||
if (last_cursor != new_cursor) {
|
||||
frame_cursor_ = has_hit_edge ? gfx::GetCursor(new_cursor) : NULL;
|
||||
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)),
|
||||
frame_cursor_);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean NativeWindowGtk::OnButtonPress(GtkWidget* widget,
|
||||
GdkEventButton* event) {
|
||||
DCHECK(!has_frame_);
|
||||
// Make the button press coordinate relative to the browser window.
|
||||
int win_x, win_y;
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
|
||||
gdk_window_get_origin(gdk_window, &win_x, &win_y);
|
||||
|
||||
GdkWindowEdge edge;
|
||||
gfx::Point point(static_cast<int>(event->x_root - win_x),
|
||||
static_cast<int>(event->y_root - win_y));
|
||||
bool has_hit_edge = IsResizable() &&
|
||||
GetWindowEdge(point.x(), point.y(), &edge);
|
||||
bool has_hit_titlebar =
|
||||
draggable_region_ && draggable_region_->contains(event->x, event->y);
|
||||
|
||||
if (event->button == 1) {
|
||||
if (GDK_BUTTON_PRESS == event->type) {
|
||||
// Raise the window after a click on either the titlebar or the border to
|
||||
// match the behavior of most window managers, unless that behavior has
|
||||
// been suppressed.
|
||||
if ((has_hit_titlebar || has_hit_edge) && !suppress_window_raise_)
|
||||
gdk_window_raise(GTK_WIDGET(widget)->window);
|
||||
|
||||
if (has_hit_edge) {
|
||||
gtk_window_begin_resize_drag(window_, edge, event->button,
|
||||
static_cast<gint>(event->x_root),
|
||||
static_cast<gint>(event->y_root),
|
||||
event->time);
|
||||
return TRUE;
|
||||
} else if (has_hit_titlebar) {
|
||||
GdkRectangle window_bounds = {0};
|
||||
gdk_window_get_frame_extents(gdk_window, &window_bounds);
|
||||
gfx::Rect bounds(window_bounds.x, window_bounds.y,
|
||||
window_bounds.width, window_bounds.height);
|
||||
return gtk_window_util::HandleTitleBarLeftMousePress(
|
||||
window_, bounds, event);
|
||||
}
|
||||
} else if (GDK_2BUTTON_PRESS == event->type) {
|
||||
if (has_hit_titlebar && IsResizable()) {
|
||||
// Maximize/restore on double click.
|
||||
if (IsMaximized())
|
||||
gtk_window_unmaximize(window_);
|
||||
else
|
||||
gtk_window_maximize(window_);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
} else if (event->button == 2) {
|
||||
if (has_hit_titlebar || has_hit_edge)
|
||||
gdk_window_lower(gdk_window);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowGtk(web_contents, options);
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -1,155 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
|
||||
#define ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "chrome/browser/ui/gtk/menu_gtk.h"
|
||||
#include "third_party/skia/include/core/SkRegion.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/gtk/gtk_signal.h"
|
||||
#include "ui/base/x/active_window_watcher_x_observer.h"
|
||||
#include "ui/gfx/size.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowGtk : public NativeWindow,
|
||||
public MenuGtk::Delegate,
|
||||
public ui::ActiveWindowWatcherXObserver {
|
||||
public:
|
||||
explicit NativeWindowGtk(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
virtual ~NativeWindowGtk();
|
||||
|
||||
// NativeWindow implementation.
|
||||
virtual void Close() OVERRIDE;
|
||||
virtual void CloseImmediately() OVERRIDE;
|
||||
virtual void Move(const gfx::Rect& pos) OVERRIDE;
|
||||
virtual void Focus(bool focus) OVERRIDE;
|
||||
virtual bool IsFocused() OVERRIDE;
|
||||
virtual void Show() OVERRIDE;
|
||||
virtual void Hide() OVERRIDE;
|
||||
virtual bool IsVisible() OVERRIDE;
|
||||
virtual void Maximize() OVERRIDE;
|
||||
virtual void Unmaximize() OVERRIDE;
|
||||
virtual bool IsMaximized() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
virtual void Restore() OVERRIDE;
|
||||
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
|
||||
virtual bool IsFullscreen() OVERRIDE;
|
||||
virtual void SetSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetSize() OVERRIDE;
|
||||
virtual void SetContentSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetContentSize() OVERRIDE;
|
||||
virtual void SetMinimumSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE;
|
||||
virtual void SetMaximumSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE;
|
||||
virtual void SetResizable(bool resizable) OVERRIDE;
|
||||
virtual bool IsResizable() OVERRIDE;
|
||||
virtual void SetAlwaysOnTop(bool top) OVERRIDE;
|
||||
virtual bool IsAlwaysOnTop() OVERRIDE;
|
||||
virtual void Center() OVERRIDE;
|
||||
virtual void SetPosition(const gfx::Point& position) OVERRIDE;
|
||||
virtual gfx::Point GetPosition() OVERRIDE;
|
||||
virtual void SetTitle(const std::string& title) OVERRIDE;
|
||||
virtual std::string GetTitle() OVERRIDE;
|
||||
virtual void FlashFrame(bool flash) OVERRIDE;
|
||||
virtual void SetSkipTaskbar(bool skip) OVERRIDE;
|
||||
virtual void SetKiosk(bool kiosk) OVERRIDE;
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
// Set the native window menu.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
|
||||
protected:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Overridden from content::WebContentsDelegate:
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) OVERRIDE;
|
||||
|
||||
// Overridden from ActiveWindowWatcherXObserver.
|
||||
virtual void ActiveWindowChanged(GdkWindow* active_window) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Register accelerators supported by the menu model.
|
||||
void RegisterAccelerators();
|
||||
|
||||
// Set WebKit's style from current theme.
|
||||
void SetWebKitColorStyle();
|
||||
|
||||
// Set how font is renderered.
|
||||
void SetFontRenderering();
|
||||
|
||||
// If the point (|x|, |y|) is within the resize border area of the window,
|
||||
// returns true and sets |edge| to the appropriate GdkWindowEdge value.
|
||||
// Otherwise, returns false.
|
||||
bool GetWindowEdge(int x, int y, GdkWindowEdge* edge);
|
||||
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowDeleteEvent,
|
||||
GdkEvent*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusIn, GdkEventFocus*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusOut, GdkEventFocus*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowState,
|
||||
GdkEventWindowState*);
|
||||
|
||||
// Mouse move and mouse button press callbacks.
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnMouseMoveEvent,
|
||||
GdkEventMotion*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnButtonPress,
|
||||
GdkEventButton*);
|
||||
|
||||
GtkWindow* window_;
|
||||
GtkWidget* vbox_;
|
||||
|
||||
GdkWindowState state_;
|
||||
bool is_always_on_top_;
|
||||
gfx::Size minimum_size_;
|
||||
gfx::Size maximum_size_;
|
||||
|
||||
// The region is treated as title bar, can be dragged to move and double
|
||||
// clicked to maximize.
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
// True if the window manager thinks the window is active. It could happpen
|
||||
// that the WM thinks a window is active but it's actually not, like when
|
||||
// showing a context menu.
|
||||
bool is_active_;
|
||||
|
||||
// If true, don't call gdk_window_raise() when we get a click in the title
|
||||
// bar or window border. This is to work around a compiz bug.
|
||||
bool suppress_window_raise_;
|
||||
|
||||
// True if the window has been visible for once, on Linux the window frame
|
||||
// would // only be considered as part of the window untill the window has
|
||||
// been shown, so we need it to correctly set the window size.
|
||||
bool has_ever_been_shown_;
|
||||
|
||||
// The current window cursor. We set it to a resize cursor when over the
|
||||
// custom frame border. We set it to NULL if we want the default cursor.
|
||||
GdkCursor* frame_cursor_;
|
||||
|
||||
// The window menu.
|
||||
scoped_ptr<MenuGtk> menu_;
|
||||
|
||||
// Map from accelerator to menu item's command id.
|
||||
accelerator_util::AcceleratorTable accelerator_table_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowGtk);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
|
|
@ -524,6 +524,12 @@ void NativeWindowMac::HandleKeyboardEvent(
|
|||
void NativeWindowMac::InstallView() {
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
if (has_frame_) {
|
||||
// Add layer with white background for the contents view.
|
||||
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
|
||||
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
|
||||
[view setLayer:layer];
|
||||
[view setWantsLayer:YES];
|
||||
|
||||
[view setFrame:[[window_ contentView] bounds]];
|
||||
[[window_ contentView] addSubview:view];
|
||||
} else {
|
||||
|
|
497
atom/browser/native_window_views.cc
Normal file
497
atom/browser/native_window_views.cc
Normal file
|
@ -0,0 +1,497 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shobjidl.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
#include "atom/browser/ui/views/menu_layout.h"
|
||||
#include "atom/common/draggable_region.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "browser/inspectable_web_contents_view.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
|
||||
#include "ui/views/controls/webview/webview.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "atom/browser/ui/views/global_menu_bar_x11.h"
|
||||
#include "atom/browser/ui/views/linux_frame_view.h"
|
||||
#elif defined(OS_WIN)
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// The menu bar height in pixels.
|
||||
const int kMenuBarHeight = 25;
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
NativeWindowViews* contents_view)
|
||||
: views::ClientView(widget, contents_view) {
|
||||
}
|
||||
virtual ~NativeWindowClientView() {}
|
||||
|
||||
virtual bool CanClose() OVERRIDE {
|
||||
static_cast<NativeWindowViews*>(contents_view())->CloseWebContents();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
window_(new views::Widget),
|
||||
menu_bar_(NULL),
|
||||
web_view_(inspectable_web_contents()->GetView()->GetView()),
|
||||
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
|
||||
use_content_size_(false),
|
||||
resizable_(true) {
|
||||
options.Get(switches::kResizable, &resizable_);
|
||||
options.Get(switches::kTitle, &title_);
|
||||
|
||||
int width = 800, height = 600;
|
||||
options.Get(switches::kWidth, &width);
|
||||
options.Get(switches::kHeight, &height);
|
||||
gfx::Rect bounds(0, 0, width, height);
|
||||
|
||||
window_->AddObserver(this);
|
||||
|
||||
views::Widget::InitParams params;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
params.bounds = bounds;
|
||||
params.delegate = this;
|
||||
params.type = views::Widget::InitParams::TYPE_WINDOW;
|
||||
params.top_level = true;
|
||||
|
||||
#if defined(USE_X11)
|
||||
// In X11 the window frame is drawn by the application.
|
||||
params.remove_standard_frame = true;
|
||||
#elif defined(OS_WIN)
|
||||
if (!has_frame_)
|
||||
params.remove_standard_frame = true;
|
||||
#endif
|
||||
|
||||
#if defined(USE_X11)
|
||||
// FIXME Find out how to do this dynamically on Linux.
|
||||
bool skip_taskbar = false;
|
||||
if (options.Get(switches::kSkipTaskbar, &skip_taskbar) && skip_taskbar)
|
||||
params.type = views::Widget::InitParams::TYPE_BUBBLE;
|
||||
#endif
|
||||
|
||||
window_->Init(params);
|
||||
|
||||
// Add web view.
|
||||
SetLayoutManager(new MenuLayout(kMenuBarHeight));
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
AddChildView(web_view_);
|
||||
|
||||
if (has_frame_ &&
|
||||
options.Get(switches::kUseContentSize, &use_content_size_) &&
|
||||
use_content_size_)
|
||||
bounds = ContentBoundsToWindowBounds(bounds);
|
||||
|
||||
window_->CenterWindow(bounds.size());
|
||||
Layout();
|
||||
}
|
||||
|
||||
NativeWindowViews::~NativeWindowViews() {
|
||||
window_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void NativeWindowViews::Close() {
|
||||
window_->Close();
|
||||
}
|
||||
|
||||
void NativeWindowViews::CloseImmediately() {
|
||||
window_->CloseNow();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Move(const gfx::Rect& bounds) {
|
||||
window_->SetBounds(bounds);
|
||||
}
|
||||
|
||||
void NativeWindowViews::Focus(bool focus) {
|
||||
if (focus)
|
||||
window_->Activate();
|
||||
else
|
||||
window_->Deactivate();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsFocused() {
|
||||
return window_->IsActive();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Show() {
|
||||
window_->Show();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Hide() {
|
||||
window_->Hide();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsVisible() {
|
||||
return window_->IsVisible();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Maximize() {
|
||||
window_->Maximize();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Unmaximize() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsMaximized() {
|
||||
return window_->IsMaximized();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Minimize() {
|
||||
window_->Minimize();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Restore() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetFullscreen(bool fullscreen) {
|
||||
window_->SetFullscreen(fullscreen);
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsFullscreen() {
|
||||
return window_->IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetSize(const gfx::Size& size) {
|
||||
window_->SetSize(size);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetSize() {
|
||||
return window_->GetWindowBoundsInScreen().size();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame_) {
|
||||
SetSize(size);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::Rect bounds = window_->GetWindowBoundsInScreen();
|
||||
bounds.set_size(size);
|
||||
window_->SetBounds(ContentBoundsToWindowBounds(bounds));
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetContentSize() {
|
||||
if (!has_frame_)
|
||||
return GetSize();
|
||||
|
||||
gfx::Size content_size =
|
||||
window_->non_client_view()->frame_view()->GetBoundsForClientView().size();
|
||||
if (menu_bar_)
|
||||
content_size.set_height(content_size.height() - kMenuBarHeight);
|
||||
return content_size;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) {
|
||||
minimum_size_ = size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
return minimum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
|
||||
maximum_size_ = size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
return maximum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetResizable(bool resizable) {
|
||||
resizable_ = resizable;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsResizable() {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetAlwaysOnTop(bool top) {
|
||||
window_->SetAlwaysOnTop(top);
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsAlwaysOnTop() {
|
||||
return window_->IsAlwaysOnTop();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Center() {
|
||||
window_->CenterWindow(GetSize());
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetPosition(const gfx::Point& position) {
|
||||
window_->SetBounds(gfx::Rect(position, GetSize()));
|
||||
}
|
||||
|
||||
gfx::Point NativeWindowViews::GetPosition() {
|
||||
return window_->GetWindowBoundsInScreen().origin();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetTitle(const std::string& title) {
|
||||
title_ = title;
|
||||
window_->UpdateWindowTitle();
|
||||
}
|
||||
|
||||
std::string NativeWindowViews::GetTitle() {
|
||||
return title_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::FlashFrame(bool flash) {
|
||||
window_->FlashFrame(flash);
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetSkipTaskbar(bool skip) {
|
||||
#if defined(OS_WIN)
|
||||
base::win::ScopedComPtr<ITaskbarList> taskbar;
|
||||
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
|
||||
CLSCTX_INPROC_SERVER)) ||
|
||||
FAILED(taskbar->HrInit()))
|
||||
return;
|
||||
if (skip)
|
||||
taskbar->DeleteTab(GetAcceleratedWidget());
|
||||
else
|
||||
taskbar->AddTab(GetAcceleratedWidget());
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetKiosk(bool kiosk) {
|
||||
SetFullscreen(kiosk);
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsKiosk() {
|
||||
return IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
RegisterAccelerators(menu_model);
|
||||
|
||||
#if defined(USE_X11)
|
||||
if (!global_menu_bar_)
|
||||
global_menu_bar_.reset(new GlobalMenuBarX11(this));
|
||||
|
||||
// Use global application menu bar when possible.
|
||||
if (global_menu_bar_->IsServerStarted()) {
|
||||
global_menu_bar_->SetMenu(menu_model);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Do not show menu bar in frameless window.
|
||||
if (!has_frame_)
|
||||
return;
|
||||
|
||||
if (!menu_bar_) {
|
||||
gfx::Size content_size = GetContentSize();
|
||||
menu_bar_ = new MenuBar;
|
||||
AddChildViewAt(menu_bar_, 0);
|
||||
|
||||
if (use_content_size_)
|
||||
SetContentSize(content_size);
|
||||
}
|
||||
|
||||
menu_bar_->SetMenu(menu_model);
|
||||
Layout();
|
||||
}
|
||||
|
||||
gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
|
||||
return window_->GetNativeWindow();
|
||||
}
|
||||
|
||||
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() {
|
||||
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
|
||||
}
|
||||
|
||||
void NativeWindowViews::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
SkRegion* draggable_region = new SkRegion;
|
||||
|
||||
// By default, the whole window is non-draggable. We need to explicitly
|
||||
// include those draggable regions.
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end(); ++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
|
||||
draggable_region_.reset(draggable_region);
|
||||
}
|
||||
|
||||
void NativeWindowViews::OnWidgetActivationChanged(
|
||||
views::Widget* widget, bool active) {
|
||||
if (widget != window_.get())
|
||||
return;
|
||||
|
||||
if (active)
|
||||
NotifyWindowFocus();
|
||||
else
|
||||
NotifyWindowBlur();
|
||||
}
|
||||
|
||||
void NativeWindowViews::DeleteDelegate() {
|
||||
NotifyWindowClosed();
|
||||
}
|
||||
|
||||
views::View* NativeWindowViews::GetInitiallyFocusedView() {
|
||||
return inspectable_web_contents()->GetView()->GetWebView();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::CanResize() const {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::CanMaximize() const {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
base::string16 NativeWindowViews::GetWindowTitle() const {
|
||||
return base::UTF8ToUTF16(title_);
|
||||
}
|
||||
|
||||
bool NativeWindowViews::ShouldHandleSystemCommands() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
|
||||
if (icon_)
|
||||
return *(icon_->ToImageSkia());
|
||||
else
|
||||
return gfx::ImageSkia();
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
|
||||
return GetWindowAppIcon();
|
||||
}
|
||||
|
||||
views::Widget* NativeWindowViews::GetWidget() {
|
||||
return window_.get();
|
||||
}
|
||||
|
||||
const views::Widget* NativeWindowViews::GetWidget() const {
|
||||
return window_.get();
|
||||
}
|
||||
|
||||
views::View* NativeWindowViews::GetContentsView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
||||
gfx::NativeView child,
|
||||
const gfx::Point& location) {
|
||||
// App window should claim mouse events that fall within the draggable region.
|
||||
if (draggable_region_ &&
|
||||
draggable_region_->contains(location.x(), location.y()))
|
||||
return false;
|
||||
|
||||
// And the events on border for dragging resizable frameless window.
|
||||
if (!has_frame_ && CanResize()) {
|
||||
FramelessView* frame = static_cast<FramelessView*>(
|
||||
window_->non_client_view()->frame_view());
|
||||
return frame->ResizingBorderHitTest(location) == HTNOWHERE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
|
||||
return new NativeWindowClientView(widget, this);
|
||||
}
|
||||
|
||||
views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
#if defined(USE_X11)
|
||||
LinuxFrameView* frame_view = new LinuxFrameView;
|
||||
#else
|
||||
WinFrameView* frame_view = new WinFrameView;
|
||||
#endif
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
}
|
||||
|
||||
void NativeWindowViews::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
keyboard_event_handler_->HandleKeyboardEvent(event, GetFocusManager());
|
||||
}
|
||||
|
||||
bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
|
||||
return accelerator_util::TriggerAcceleratorTableCommand(
|
||||
&accelerator_table_, accelerator);
|
||||
}
|
||||
|
||||
void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
|
||||
// Clear previous accelerators.
|
||||
views::FocusManager* focus_manager = GetFocusManager();
|
||||
accelerator_table_.clear();
|
||||
focus_manager->UnregisterAccelerators(this);
|
||||
|
||||
// Register accelerators with focus manager.
|
||||
accelerator_util::GenerateAcceleratorTable(&accelerator_table_, menu_model);
|
||||
accelerator_util::AcceleratorTable::const_iterator iter;
|
||||
for (iter = accelerator_table_.begin();
|
||||
iter != accelerator_table_.end();
|
||||
++iter) {
|
||||
focus_manager->RegisterAccelerator(
|
||||
iter->first, ui::AcceleratorManager::kNormalPriority, this);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
gfx::Rect window_bounds =
|
||||
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
|
||||
if (menu_bar_)
|
||||
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowViews(web_contents, options);
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -1,44 +1,38 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
|
||||
#define ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
|
||||
#ifndef ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
|
||||
#define ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "ui/gfx/size.h"
|
||||
#include "ui/views/focus/widget_focus_manager.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "vendor/brightray/browser/win/inspectable_web_contents_view_win.h"
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
#include "ui/views/widget/widget_observer.h"
|
||||
|
||||
namespace views {
|
||||
class UnhandledKeyboardEventHandler;
|
||||
class Widget;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
class GlobalMenuBarX11;
|
||||
class MenuBar;
|
||||
|
||||
class NativeWindowWin : public NativeWindow,
|
||||
public views::WidgetFocusChangeListener,
|
||||
public views::WidgetDelegateView {
|
||||
class NativeWindowViews : public NativeWindow,
|
||||
public views::WidgetDelegateView,
|
||||
public views::WidgetObserver {
|
||||
public:
|
||||
explicit NativeWindowWin(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
virtual ~NativeWindowWin();
|
||||
explicit NativeWindowViews(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
virtual ~NativeWindowViews();
|
||||
|
||||
// NativeWindow implementation.
|
||||
// NativeWindow:
|
||||
virtual void Close() OVERRIDE;
|
||||
virtual void CloseImmediately() OVERRIDE;
|
||||
virtual void Move(const gfx::Rect& pos) OVERRIDE;
|
||||
|
@ -75,89 +69,82 @@ class NativeWindowWin : public NativeWindow,
|
|||
virtual void SetSkipTaskbar(bool skip) OVERRIDE;
|
||||
virtual void SetKiosk(bool kiosk) OVERRIDE;
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual void SetMenu(ui::MenuModel* menu_model) OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
void OnMenuCommand(int position, HMENU menu);
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget();
|
||||
|
||||
// Set the native window menu.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
views::Widget* widget() const { return window_.get(); }
|
||||
|
||||
brightray::InspectableWebContentsViewWin* inspectable_web_contents_view()
|
||||
const {
|
||||
return static_cast<brightray::InspectableWebContentsViewWin*>(
|
||||
inspectable_web_contents()->GetView());
|
||||
}
|
||||
|
||||
views::Widget* window() const { return window_.get(); }
|
||||
atom::Menu2* menu() const { return menu_.get(); }
|
||||
SkRegion* draggable_region() { return draggable_region_.get(); }
|
||||
|
||||
protected:
|
||||
private:
|
||||
// NativeWindow:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Overridden from content::WebContentsDelegate:
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) OVERRIDE;
|
||||
// views::WidgetObserver:
|
||||
virtual void OnWidgetActivationChanged(
|
||||
views::Widget* widget, bool active) OVERRIDE;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual void Layout() OVERRIDE;
|
||||
virtual void ViewHierarchyChanged(
|
||||
const ViewHierarchyChangedDetails& details) OVERRIDE;
|
||||
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Overridden from views::WidgetDelegate:
|
||||
// views::WidgetDelegate:
|
||||
virtual void DeleteDelegate() OVERRIDE;
|
||||
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
|
||||
virtual bool CanResize() const OVERRIDE;
|
||||
virtual bool CanMaximize() const OVERRIDE;
|
||||
virtual string16 GetWindowTitle() const OVERRIDE;
|
||||
virtual base::string16 GetWindowTitle() const OVERRIDE;
|
||||
virtual bool ShouldHandleSystemCommands() const OVERRIDE;
|
||||
virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
|
||||
virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
|
||||
virtual views::Widget* GetWidget() OVERRIDE;
|
||||
virtual const views::Widget* GetWidget() const OVERRIDE;
|
||||
virtual views::View* GetContentsView() OVERRIDE;
|
||||
virtual bool ShouldDescendIntoChildForEventHandling(
|
||||
gfx::NativeView child,
|
||||
const gfx::Point& location) OVERRIDE;
|
||||
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
|
||||
virtual views::NonClientFrameView* CreateNonClientFrameView(
|
||||
views::Widget* widget) OVERRIDE;
|
||||
|
||||
// Overridden from views::WidgetFocusChangeListener:
|
||||
virtual void OnNativeFocusChange(gfx::NativeView focused_before,
|
||||
gfx::NativeView focused_now) OVERRIDE;
|
||||
// content::WebContentsDelegate:
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef struct { int position; ui::MenuModel* model; } MenuItem;
|
||||
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
|
||||
|
||||
void ClientAreaSizeToWindowSize(gfx::Size* size);
|
||||
|
||||
void OnViewWasResized();
|
||||
// views::View:
|
||||
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Register accelerators supported by the menu model.
|
||||
void RegisterAccelerators();
|
||||
void RegisterAccelerators(ui::MenuModel* menu_model);
|
||||
|
||||
// Converts between client area and window area, since we include the menu bar
|
||||
// in client area we need to substract/add menu bar's height in convertions.
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& content_bounds);
|
||||
|
||||
scoped_ptr<views::Widget> window_;
|
||||
views::View* web_view_; // managed by window_.
|
||||
MenuBar* menu_bar_;
|
||||
views::View* web_view_; // Managed by inspectable_web_contents_.
|
||||
|
||||
// The window menu.
|
||||
scoped_ptr<atom::Menu2> menu_;
|
||||
#if defined(USE_X11)
|
||||
scoped_ptr<GlobalMenuBarX11> global_menu_bar_;
|
||||
#endif
|
||||
|
||||
// Handles unhandled keyboard messages coming back from the renderer process.
|
||||
scoped_ptr<views::UnhandledKeyboardEventHandler> keyboard_event_handler_;
|
||||
|
||||
// Map from accelerator to menu item's command id.
|
||||
accelerator_util::AcceleratorTable accelerator_table_;
|
||||
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
bool use_content_size_;
|
||||
|
||||
bool resizable_;
|
||||
string16 title_;
|
||||
std::string title_;
|
||||
gfx::Size minimum_size_;
|
||||
gfx::Size maximum_size_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowWin);
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
|
||||
#endif // ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_
|
|
@ -1,636 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/native_window_win.h"
|
||||
|
||||
#include <shobjidl.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
#include "atom/browser/ui/win/menu_2.h"
|
||||
#include "atom/browser/ui/win/native_menu_win.h"
|
||||
#include "atom/common/draggable_region.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/path.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/native_widget_win.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kResizeInsideBoundsSize = 5;
|
||||
const int kResizeAreaCornerSize = 16;
|
||||
|
||||
// Returns true if |possible_parent| is a parent window of |child|.
|
||||
bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) {
|
||||
if (!child)
|
||||
return false;
|
||||
if (::GetWindow(child, GW_OWNER) == possible_parent)
|
||||
return true;
|
||||
gfx::NativeView parent = ::GetParent(child);
|
||||
while (parent) {
|
||||
if (possible_parent == parent)
|
||||
return true;
|
||||
parent = ::GetParent(parent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wrapper of NativeWidgetWin to handle WM_MENUCOMMAND messages, which are
|
||||
// triggered by window menus.
|
||||
class MenuCommandNativeWidget : public views::NativeWidgetWin {
|
||||
public:
|
||||
explicit MenuCommandNativeWidget(NativeWindowWin* delegate)
|
||||
: views::NativeWidgetWin(delegate->window()),
|
||||
delegate_(delegate) {}
|
||||
virtual ~MenuCommandNativeWidget() {}
|
||||
|
||||
protected:
|
||||
virtual bool PreHandleMSG(UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param,
|
||||
LRESULT* result) OVERRIDE {
|
||||
if (message == WM_MENUCOMMAND) {
|
||||
delegate_->OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
|
||||
*result = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NativeWindowWin* delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuCommandNativeWidget);
|
||||
};
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
NativeWindowWin* contents_view)
|
||||
: views::ClientView(widget, contents_view) {
|
||||
}
|
||||
virtual ~NativeWindowClientView() {}
|
||||
|
||||
virtual bool CanClose() OVERRIDE {
|
||||
static_cast<NativeWindowWin*>(contents_view())->CloseWebContents();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
|
||||
};
|
||||
|
||||
class NativeWindowFrameView : public views::NativeFrameView {
|
||||
public:
|
||||
explicit NativeWindowFrameView(views::Widget* frame, NativeWindowWin* shell)
|
||||
: NativeFrameView(frame),
|
||||
shell_(shell) {
|
||||
}
|
||||
virtual ~NativeWindowFrameView() {}
|
||||
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE {
|
||||
return shell_->GetMinimumSize();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE {
|
||||
return shell_->GetMaximumSize();
|
||||
}
|
||||
|
||||
private:
|
||||
NativeWindowWin* shell_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
|
||||
};
|
||||
|
||||
class NativeWindowFramelessView : public views::NonClientFrameView {
|
||||
public:
|
||||
explicit NativeWindowFramelessView(views::Widget* frame,
|
||||
NativeWindowWin* shell)
|
||||
: frame_(frame),
|
||||
shell_(shell) {
|
||||
}
|
||||
virtual ~NativeWindowFramelessView() {}
|
||||
|
||||
// views::NonClientFrameView implementations:
|
||||
virtual gfx::Rect NativeWindowFramelessView::GetBoundsForClientView() const
|
||||
OVERRIDE {
|
||||
return bounds();
|
||||
}
|
||||
|
||||
virtual gfx::Rect NativeWindowFramelessView::GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const OVERRIDE {
|
||||
gfx::Rect window_bounds = client_bounds;
|
||||
// Enforce minimum size (1, 1) in case that client_bounds is passed with
|
||||
// empty size. This could occur when the frameless window is being
|
||||
// initialized.
|
||||
if (window_bounds.IsEmpty()) {
|
||||
window_bounds.set_width(1);
|
||||
window_bounds.set_height(1);
|
||||
}
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
|
||||
if (frame_->IsFullscreen())
|
||||
return HTCLIENT;
|
||||
|
||||
// Check the frame first, as we allow a small area overlapping the contents
|
||||
// to be used for resize handles.
|
||||
bool can_ever_resize = frame_->widget_delegate() ?
|
||||
frame_->widget_delegate()->CanResize() :
|
||||
false;
|
||||
// Don't allow overlapping resize handles when the window is maximized or
|
||||
// fullscreen, as it can't be resized in those states.
|
||||
int resize_border =
|
||||
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
|
||||
kResizeInsideBoundsSize;
|
||||
int frame_component = GetHTComponentForFrame(point,
|
||||
resize_border,
|
||||
resize_border,
|
||||
kResizeAreaCornerSize,
|
||||
kResizeAreaCornerSize,
|
||||
can_ever_resize);
|
||||
if (frame_component != HTNOWHERE)
|
||||
return frame_component;
|
||||
|
||||
// Check for possible draggable region in the client area for the frameless
|
||||
// window.
|
||||
if (shell_->draggable_region() &&
|
||||
shell_->draggable_region()->contains(point.x(), point.y()))
|
||||
return HTCAPTION;
|
||||
|
||||
int client_component = frame_->client_view()->NonClientHitTest(point);
|
||||
if (client_component != HTNOWHERE)
|
||||
return client_component;
|
||||
|
||||
// Caption is a safe default.
|
||||
return HTCAPTION;
|
||||
}
|
||||
|
||||
virtual void GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) OVERRIDE {}
|
||||
virtual void ResetWindowControls() OVERRIDE {}
|
||||
virtual void UpdateWindowIcon() OVERRIDE {}
|
||||
virtual void UpdateWindowTitle() OVERRIDE {}
|
||||
|
||||
// views::View implementations:
|
||||
virtual gfx::Size NativeWindowFramelessView::GetPreferredSize() OVERRIDE {
|
||||
gfx::Size pref = frame_->client_view()->GetPreferredSize();
|
||||
gfx::Rect bounds(0, 0, pref.width(), pref.height());
|
||||
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
bounds).size();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE {
|
||||
return shell_->GetMinimumSize();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE {
|
||||
return shell_->GetMaximumSize();
|
||||
}
|
||||
|
||||
private:
|
||||
views::Widget* frame_;
|
||||
NativeWindowWin* shell_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
window_(new views::Widget),
|
||||
web_view_(inspectable_web_contents_view()->GetView()),
|
||||
use_content_size_(false),
|
||||
resizable_(true) {
|
||||
options.Get(switches::kResizable, &resizable_);
|
||||
|
||||
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
|
||||
params.delegate = this;
|
||||
params.native_widget = new MenuCommandNativeWidget(this);
|
||||
params.remove_standard_frame = !has_frame_;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
|
||||
window_->Init(params);
|
||||
|
||||
views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
|
||||
|
||||
int width = 800, height = 600;
|
||||
options.Get(switches::kWidth, &width);
|
||||
options.Get(switches::kHeight, &height);
|
||||
|
||||
gfx::Size size(width, height);
|
||||
options.Get(switches::kUseContentSize, &use_content_size_);
|
||||
if (has_frame_ && use_content_size_)
|
||||
ClientAreaSizeToWindowSize(&size);
|
||||
|
||||
window_->CenterWindow(size);
|
||||
window_->UpdateWindowIcon();
|
||||
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
NativeWindowWin::~NativeWindowWin() {
|
||||
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
|
||||
}
|
||||
|
||||
void NativeWindowWin::Close() {
|
||||
window_->Close();
|
||||
}
|
||||
|
||||
void NativeWindowWin::CloseImmediately() {
|
||||
window_->CloseNow();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Move(const gfx::Rect& bounds) {
|
||||
window_->SetBounds(bounds);
|
||||
}
|
||||
|
||||
void NativeWindowWin::Focus(bool focus) {
|
||||
if (focus)
|
||||
window_->Activate();
|
||||
else
|
||||
window_->Deactivate();
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsFocused() {
|
||||
return window_->IsActive();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Show() {
|
||||
window_->Show();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Hide() {
|
||||
window_->Hide();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Maximize() {
|
||||
window_->Maximize();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Unmaximize() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsMaximized() {
|
||||
return window_->IsMaximized();
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsVisible() {
|
||||
return window_->IsVisible();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Minimize() {
|
||||
window_->Minimize();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Restore() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetFullscreen(bool fullscreen) {
|
||||
window_->SetFullscreen(fullscreen);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsFullscreen() {
|
||||
return window_->IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetSize(const gfx::Size& size) {
|
||||
window_->SetSize(size);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowWin::GetSize() {
|
||||
return window_->GetWindowBoundsInScreen().size();
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetContentSize(const gfx::Size& size) {
|
||||
gfx::Size resized(size);
|
||||
ClientAreaSizeToWindowSize(&resized);
|
||||
SetSize(resized);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowWin::GetContentSize() {
|
||||
return window_->GetClientAreaBoundsInScreen().size();
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetMinimumSize(const gfx::Size& size) {
|
||||
minimum_size_ = size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowWin::GetMinimumSize() {
|
||||
return minimum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetMaximumSize(const gfx::Size& size) {
|
||||
maximum_size_ = size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowWin::GetMaximumSize() {
|
||||
return maximum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetResizable(bool resizable) {
|
||||
resizable_ = resizable;
|
||||
|
||||
// WS_MAXIMIZEBOX => Maximize/Minimize button
|
||||
// WS_THICKFRAME => Resize handle
|
||||
DWORD style = ::GetWindowLong(GetNativeWindow(), GWL_STYLE);
|
||||
if (resizable)
|
||||
style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
|
||||
else
|
||||
style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
|
||||
::SetWindowLong(GetNativeWindow(), GWL_STYLE, style);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsResizable() {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetAlwaysOnTop(bool top) {
|
||||
window_->SetAlwaysOnTop(top);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsAlwaysOnTop() {
|
||||
DWORD style = ::GetWindowLong(window_->GetNativeView(), GWL_EXSTYLE);
|
||||
return style & WS_EX_TOPMOST;
|
||||
}
|
||||
|
||||
void NativeWindowWin::Center() {
|
||||
window_->CenterWindow(GetSize());
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetPosition(const gfx::Point& position) {
|
||||
window_->SetBounds(gfx::Rect(position, GetSize()));
|
||||
}
|
||||
|
||||
gfx::Point NativeWindowWin::GetPosition() {
|
||||
return window_->GetWindowBoundsInScreen().origin();
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetTitle(const std::string& title) {
|
||||
title_ = UTF8ToUTF16(title);
|
||||
window_->UpdateWindowTitle();
|
||||
}
|
||||
|
||||
std::string NativeWindowWin::GetTitle() {
|
||||
return UTF16ToUTF8(title_);
|
||||
}
|
||||
|
||||
void NativeWindowWin::FlashFrame(bool flash) {
|
||||
window_->FlashFrame(flash);
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetSkipTaskbar(bool skip) {
|
||||
base::win::ScopedComPtr<ITaskbarList> taskbar;
|
||||
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
|
||||
CLSCTX_INPROC_SERVER)) ||
|
||||
FAILED(taskbar->HrInit()))
|
||||
return;
|
||||
if (skip)
|
||||
taskbar->DeleteTab(GetNativeWindow());
|
||||
else
|
||||
taskbar->AddTab(GetNativeWindow());
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetKiosk(bool kiosk) {
|
||||
SetFullscreen(kiosk);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsKiosk() {
|
||||
return IsFullscreen();
|
||||
}
|
||||
|
||||
gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
|
||||
return window_->GetNativeView();
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
|
||||
DCHECK(menu_);
|
||||
menu_->wrapper()->OnMenuCommand(position, menu);
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
|
||||
menu_.reset(new atom::Menu2(menu_model, true));
|
||||
menu_->UpdateStates();
|
||||
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
|
||||
RegisterAccelerators();
|
||||
|
||||
// Resize the window so SetMenu won't change client area size.
|
||||
if (use_content_size_) {
|
||||
gfx::Size size = GetSize();
|
||||
size.set_height(size.height() + GetSystemMetrics(SM_CYMENU));
|
||||
SetSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowWin::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
SkRegion* draggable_region = new SkRegion;
|
||||
|
||||
// By default, the whole window is non-draggable. We need to explicitly
|
||||
// include those draggable regions.
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end(); ++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
|
||||
draggable_region_.reset(draggable_region);
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
void NativeWindowWin::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (event.type == WebKit::WebInputEvent::RawKeyDown) {
|
||||
ui::Accelerator accelerator(
|
||||
static_cast<ui::KeyboardCode>(event.windowsKeyCode),
|
||||
content::GetModifiersFromNativeWebKeyboardEvent(event));
|
||||
|
||||
if (GetFocusManager()->ProcessAccelerator(accelerator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Any unhandled keyboard/character messages should be defproced.
|
||||
// This allows stuff like F10, etc to work correctly.
|
||||
DefWindowProc(event.os_event.hwnd, event.os_event.message,
|
||||
event.os_event.wParam, event.os_event.lParam);
|
||||
}
|
||||
|
||||
void NativeWindowWin::Layout() {
|
||||
DCHECK(web_view_);
|
||||
web_view_->SetBounds(0, 0, width(), height());
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
void NativeWindowWin::ViewHierarchyChanged(
|
||||
const ViewHierarchyChangedDetails& details) {
|
||||
if (details.is_add && details.child == this)
|
||||
AddChildView(web_view_);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::AcceleratorPressed(
|
||||
const ui::Accelerator& accelerator) {
|
||||
return accelerator_util::TriggerAcceleratorTableCommand(
|
||||
&accelerator_table_, accelerator);
|
||||
}
|
||||
|
||||
void NativeWindowWin::DeleteDelegate() {
|
||||
NotifyWindowClosed();
|
||||
}
|
||||
|
||||
views::View* NativeWindowWin::GetInitiallyFocusedView() {
|
||||
return inspectable_web_contents_view()->GetWebView();
|
||||
}
|
||||
|
||||
bool NativeWindowWin::CanResize() const {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
bool NativeWindowWin::CanMaximize() const {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
string16 NativeWindowWin::GetWindowTitle() const {
|
||||
return title_;
|
||||
}
|
||||
|
||||
bool NativeWindowWin::ShouldHandleSystemCommands() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
|
||||
if (icon_)
|
||||
return *(icon_->ToImageSkia());
|
||||
else
|
||||
return gfx::ImageSkia();
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
|
||||
return GetWindowAppIcon();
|
||||
}
|
||||
|
||||
views::Widget* NativeWindowWin::GetWidget() {
|
||||
return window_.get();
|
||||
}
|
||||
|
||||
const views::Widget* NativeWindowWin::GetWidget() const {
|
||||
return window_.get();
|
||||
}
|
||||
|
||||
views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
|
||||
return new NativeWindowClientView(widget, this);
|
||||
}
|
||||
|
||||
views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
if (has_frame_)
|
||||
return new NativeWindowFrameView(widget, this);
|
||||
|
||||
return new NativeWindowFramelessView(widget, this);
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnNativeFocusChange(gfx::NativeView focused_before,
|
||||
gfx::NativeView focused_now) {
|
||||
gfx::NativeView this_window = GetWidget()->GetNativeView();
|
||||
if (IsParent(focused_now, this_window))
|
||||
return;
|
||||
|
||||
if (focused_now == this_window)
|
||||
NotifyWindowFocus();
|
||||
else if (focused_before == this_window)
|
||||
NotifyWindowBlur();
|
||||
}
|
||||
|
||||
void NativeWindowWin::ClientAreaSizeToWindowSize(gfx::Size* size) {
|
||||
gfx::Size window = window_->GetWindowBoundsInScreen().size();
|
||||
gfx::Size client = window_->GetClientAreaBoundsInScreen().size();
|
||||
size->set_width(size->width() + window.width() - client.width());
|
||||
size->set_height(size->height() + window.height() - client.height());
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnViewWasResized() {
|
||||
// Set the window shape of the RWHV.
|
||||
gfx::Size sz = web_view_->size();
|
||||
int height = sz.height(), width = sz.width();
|
||||
gfx::Path path;
|
||||
path.addRect(0, 0, width, height);
|
||||
SetWindowRgn(web_contents()->GetView()->GetNativeView(),
|
||||
path.CreateNativeRegion(),
|
||||
1);
|
||||
|
||||
SkRegion* rgn = new SkRegion;
|
||||
if (!window_->IsFullscreen() && !window_->IsMaximized()) {
|
||||
if (draggable_region())
|
||||
rgn->op(*draggable_region(), SkRegion::kUnion_Op);
|
||||
|
||||
if (!has_frame_ && CanResize()) {
|
||||
rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
|
||||
rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
|
||||
rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
|
||||
SkRegion::kUnion_Op);
|
||||
rgn->op(0, height - kResizeInsideBoundsSize, width, height,
|
||||
SkRegion::kUnion_Op);
|
||||
}
|
||||
}
|
||||
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (web_contents->GetRenderViewHost()->GetView())
|
||||
web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
|
||||
}
|
||||
|
||||
void NativeWindowWin::RegisterAccelerators() {
|
||||
views::FocusManager* focus_manager = GetFocusManager();
|
||||
accelerator_table_.clear();
|
||||
focus_manager->UnregisterAccelerators(this);
|
||||
|
||||
accelerator_util::GenerateAcceleratorTable(&accelerator_table_,
|
||||
menu_->model());
|
||||
accelerator_util::AcceleratorTable::const_iterator iter;
|
||||
for (iter = accelerator_table_.begin();
|
||||
iter != accelerator_table_.end();
|
||||
++iter) {
|
||||
focus_manager->RegisterAccelerator(
|
||||
iter->first, ui::AcceleratorManager::kNormalPriority, this);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowWin(web_contents, options);
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -32,6 +32,7 @@
|
|||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_storage.h"
|
||||
#include "vendor/brightray/browser/network_delegate.h"
|
||||
#include "webkit/browser/quota/special_storage_policy.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -75,18 +76,18 @@ net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
|
|||
url_request_context_->set_network_delegate(network_delegate_.get());
|
||||
storage_.reset(
|
||||
new net::URLRequestContextStorage(url_request_context_.get()));
|
||||
storage_->set_cookie_store(content::CreatePersistentCookieStore(
|
||||
auto cookie_config = content::CookieStoreConfig(
|
||||
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
|
||||
false,
|
||||
content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr));
|
||||
nullptr);
|
||||
storage_->set_cookie_store(content::CreateCookieStore(cookie_config));
|
||||
storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
|
||||
new net::DefaultServerBoundCertStore(NULL),
|
||||
base::WorkerPool::GetTaskRunner(true)));
|
||||
storage_->set_http_user_agent_settings(
|
||||
new net::StaticHttpUserAgentSettings(
|
||||
"en-us,en", EmptyString()));
|
||||
"en-us,en", base::EmptyString()));
|
||||
|
||||
scoped_ptr<net::HostResolver> host_resolver(
|
||||
net::HostResolver::CreateDefaultResolver(NULL));
|
||||
|
@ -163,9 +164,9 @@ net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
|
|||
content::BrowserThread::GetBlockingPool()->
|
||||
GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
|
||||
job_factory_->SetProtocolHandler(chrome::kDataScheme,
|
||||
job_factory_->SetProtocolHandler(content::kDataScheme,
|
||||
new net::DataProtocolHandler);
|
||||
job_factory_->SetProtocolHandler(chrome::kFileScheme,
|
||||
job_factory_->SetProtocolHandler(content::kFileScheme,
|
||||
file_protocol_handler.release());
|
||||
storage_->set_job_factory(job_factory_);
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_gtk.h"
|
||||
|
||||
namespace accelerator_util {
|
||||
|
||||
void SetPlatformAccelerator(ui::Accelerator* accelerator) {
|
||||
scoped_ptr<ui::PlatformAccelerator> platform_accelerator(
|
||||
new ui::PlatformAcceleratorGtk(
|
||||
GetGdkKeyCodeForAccelerator(*accelerator),
|
||||
GetGdkModifierForAccelerator(*accelerator)));
|
||||
accelerator->set_platform_accelerator(platform_accelerator.Pass());
|
||||
}
|
||||
|
||||
} // namespace accelerator_util
|
|
@ -131,7 +131,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
|
|||
- (void)addItemToMenu:(NSMenu*)menu
|
||||
atIndex:(NSInteger)index
|
||||
fromModel:(ui::MenuModel*)model {
|
||||
string16 label16 = model->GetLabelAt(index);
|
||||
base::string16 label16 = model->GetLabelAt(index);
|
||||
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
|
||||
base::scoped_nsobject<NSMenuItem> item(
|
||||
[[NSMenuItem alloc] initWithTitle:label
|
||||
|
|
|
@ -4,16 +4,47 @@
|
|||
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
// This conflicts with mate::Converter,
|
||||
#undef True
|
||||
#undef False
|
||||
// and V8.
|
||||
#undef None
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/file_util.h"
|
||||
#include "chrome/browser/ui/gtk/gtk_util.h"
|
||||
#include "ui/base/gtk/gtk_signal.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kAuraTransientParent[] = "aura-transient-parent";
|
||||
|
||||
void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
|
||||
if (!parent || !parent->GetHost())
|
||||
return;
|
||||
|
||||
gtk_widget_realize(dialog);
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(dialog);
|
||||
|
||||
// TODO(erg): Check to make sure we're using X11 if wayland or some other
|
||||
// display server ever happens. Otherwise, this will crash.
|
||||
XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window),
|
||||
GDK_WINDOW_XID(gdk_window),
|
||||
parent->GetHost()->GetAcceleratedWidget());
|
||||
|
||||
// We also set the |parent| as a property of |dialog|, so that we can unlink
|
||||
// the two later.
|
||||
g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent);
|
||||
}
|
||||
|
||||
class FileChooserDialog {
|
||||
public:
|
||||
FileChooserDialog(GtkFileChooserAction action,
|
||||
|
@ -27,14 +58,17 @@ class FileChooserDialog {
|
|||
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
confirm_text = GTK_STOCK_OPEN;
|
||||
|
||||
GtkWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
dialog_ = gtk_file_chooser_dialog_new(
|
||||
title.c_str(),
|
||||
window,
|
||||
NULL,
|
||||
action,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
confirm_text, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
if (parent_window) {
|
||||
gfx::NativeWindow window = parent_window->GetNativeWindow();
|
||||
SetGtkTransientForAura(dialog_, window);
|
||||
}
|
||||
|
||||
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog_),
|
||||
|
@ -42,10 +76,6 @@ class FileChooserDialog {
|
|||
if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE);
|
||||
|
||||
// Set window-to-parent modality by adding the dialog to the same window
|
||||
// group as the parent.
|
||||
gtk_window_group_add_window(gtk_window_get_group(window),
|
||||
GTK_WINDOW(dialog_));
|
||||
gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
|
||||
|
||||
if (!default_path.empty()) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <commdlg.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/i18n/case_conversion.h"
|
||||
#include "base/strings/string_util.h"
|
||||
|
@ -25,8 +25,8 @@ namespace {
|
|||
|
||||
// Distinguish directories from regular files.
|
||||
bool IsDirectory(const base::FilePath& path) {
|
||||
base::PlatformFileInfo file_info;
|
||||
return file_util::GetFileInfo(path, &file_info) ?
|
||||
base::File::Info file_info;
|
||||
return base::GetFileInfo(path, &file_info) ?
|
||||
file_info.is_directory : path.EndsWithSeparator();
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ void FormatFilterForExtensions(
|
|||
// the we create a description "QQQ File (.qqq)").
|
||||
include_all_files = true;
|
||||
// TODO(zcbenz): should be localized.
|
||||
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
|
||||
desc = base::i18n::ToUpper(base::WideToUTF16(ext_name)) + L" File";
|
||||
}
|
||||
desc += L" (*." + ext_name + L")";
|
||||
|
||||
|
@ -157,14 +157,16 @@ class FileDialog {
|
|||
filters.size()));
|
||||
|
||||
if (!title.empty())
|
||||
GetPtr()->SetTitle(UTF8ToUTF16(title).c_str());
|
||||
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
|
||||
|
||||
SetDefaultFolder(default_path);
|
||||
}
|
||||
|
||||
bool Show(atom::NativeWindow* parent_window) {
|
||||
atom::NativeWindow::DialogScope dialog_scope(parent_window);
|
||||
HWND window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
HWND window = parent_window ? static_cast<atom::NativeWindowViews*>(
|
||||
parent_window)->GetAcceleratedWidget() :
|
||||
NULL;
|
||||
return dialog_->DoModal(window) == IDOK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,268 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/gtk/app_indicator_icon.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/guid.h"
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "chrome/browser/ui/gtk/menu_gtk.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef enum {
|
||||
APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
|
||||
APP_INDICATOR_CATEGORY_COMMUNICATIONS,
|
||||
APP_INDICATOR_CATEGORY_SYSTEM_SERVICES,
|
||||
APP_INDICATOR_CATEGORY_HARDWARE,
|
||||
APP_INDICATOR_CATEGORY_OTHER
|
||||
} AppIndicatorCategory;
|
||||
|
||||
typedef enum {
|
||||
APP_INDICATOR_STATUS_PASSIVE,
|
||||
APP_INDICATOR_STATUS_ACTIVE,
|
||||
APP_INDICATOR_STATUS_ATTENTION
|
||||
} AppIndicatorStatus;
|
||||
|
||||
typedef AppIndicator* (*app_indicator_new_func)(const gchar* id,
|
||||
const gchar* icon_name,
|
||||
AppIndicatorCategory category);
|
||||
|
||||
typedef AppIndicator* (*app_indicator_new_with_path_func)(
|
||||
const gchar* id,
|
||||
const gchar* icon_name,
|
||||
AppIndicatorCategory category,
|
||||
const gchar* icon_theme_path);
|
||||
|
||||
typedef void (*app_indicator_set_status_func)(AppIndicator* self,
|
||||
AppIndicatorStatus status);
|
||||
|
||||
typedef void (*app_indicator_set_attention_icon_full_func)(
|
||||
AppIndicator* self,
|
||||
const gchar* icon_name,
|
||||
const gchar* icon_desc);
|
||||
|
||||
typedef void (*app_indicator_set_menu_func)(AppIndicator* self, GtkMenu* menu);
|
||||
|
||||
typedef void (*app_indicator_set_icon_full_func)(AppIndicator* self,
|
||||
const gchar* icon_name,
|
||||
const gchar* icon_desc);
|
||||
|
||||
typedef void (*app_indicator_set_icon_theme_path_func)(
|
||||
AppIndicator* self,
|
||||
const gchar* icon_theme_path);
|
||||
|
||||
bool g_attempted_load = false;
|
||||
bool g_opened = false;
|
||||
|
||||
// Retrieved functions from libappindicator.
|
||||
app_indicator_new_func app_indicator_new = NULL;
|
||||
app_indicator_new_with_path_func app_indicator_new_with_path = NULL;
|
||||
app_indicator_set_status_func app_indicator_set_status = NULL;
|
||||
app_indicator_set_attention_icon_full_func
|
||||
app_indicator_set_attention_icon_full = NULL;
|
||||
app_indicator_set_menu_func app_indicator_set_menu = NULL;
|
||||
app_indicator_set_icon_full_func app_indicator_set_icon_full = NULL;
|
||||
app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL;
|
||||
|
||||
void EnsureMethodsLoaded() {
|
||||
if (g_attempted_load)
|
||||
return;
|
||||
|
||||
g_attempted_load = true;
|
||||
|
||||
void* indicator_lib = dlopen("libappindicator.so", RTLD_LAZY);
|
||||
if (!indicator_lib) {
|
||||
indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY);
|
||||
}
|
||||
if (!indicator_lib) {
|
||||
indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY);
|
||||
}
|
||||
if (!indicator_lib) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_opened = true;
|
||||
|
||||
app_indicator_new = reinterpret_cast<app_indicator_new_func>(
|
||||
dlsym(indicator_lib, "app_indicator_new"));
|
||||
|
||||
app_indicator_new_with_path =
|
||||
reinterpret_cast<app_indicator_new_with_path_func>(
|
||||
dlsym(indicator_lib, "app_indicator_new_with_path"));
|
||||
|
||||
app_indicator_set_status = reinterpret_cast<app_indicator_set_status_func>(
|
||||
dlsym(indicator_lib, "app_indicator_set_status"));
|
||||
|
||||
app_indicator_set_attention_icon_full =
|
||||
reinterpret_cast<app_indicator_set_attention_icon_full_func>(
|
||||
dlsym(indicator_lib, "app_indicator_set_attention_icon_full"));
|
||||
|
||||
app_indicator_set_menu = reinterpret_cast<app_indicator_set_menu_func>(
|
||||
dlsym(indicator_lib, "app_indicator_set_menu"));
|
||||
|
||||
app_indicator_set_icon_full =
|
||||
reinterpret_cast<app_indicator_set_icon_full_func>(
|
||||
dlsym(indicator_lib, "app_indicator_set_icon_full"));
|
||||
|
||||
app_indicator_set_icon_theme_path =
|
||||
reinterpret_cast<app_indicator_set_icon_theme_path_func>(
|
||||
dlsym(indicator_lib, "app_indicator_set_icon_theme_path"));
|
||||
}
|
||||
|
||||
base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr,
|
||||
int icon_change_count,
|
||||
std::string id) {
|
||||
scoped_ptr<gfx::ImageSkia> image(image_ptr);
|
||||
|
||||
scoped_refptr<base::RefCountedMemory> png_data =
|
||||
gfx::Image(*image.get()).As1xPNGBytes();
|
||||
if (png_data->size() == 0) {
|
||||
// If the bitmap could not be encoded to PNG format, skip it.
|
||||
LOG(WARNING) << "Could not encode icon";
|
||||
return base::FilePath();
|
||||
}
|
||||
|
||||
base::FilePath temp_dir;
|
||||
base::FilePath new_file_path;
|
||||
|
||||
// Create a new temporary directory for each image since using a single
|
||||
// temporary directory seems to have issues when changing icons in quick
|
||||
// succession.
|
||||
if (!file_util::CreateNewTempDirectory(base::FilePath::StringType(),
|
||||
&temp_dir))
|
||||
return base::FilePath();
|
||||
new_file_path =
|
||||
temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count));
|
||||
int bytes_written =
|
||||
file_util::WriteFile(
|
||||
new_file_path,
|
||||
reinterpret_cast<const char*>(png_data->front()),
|
||||
png_data->size());
|
||||
|
||||
if (bytes_written != static_cast<int>(png_data->size()))
|
||||
return base::FilePath();
|
||||
return new_file_path;
|
||||
}
|
||||
|
||||
void DeleteTempImagePath(const base::FilePath& icon_file_path) {
|
||||
if (icon_file_path.empty())
|
||||
return;
|
||||
base::DeleteFile(icon_file_path, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace atom {
|
||||
|
||||
AppIndicatorIcon::AppIndicatorIcon()
|
||||
: icon_(NULL),
|
||||
id_(base::GenerateGUID()),
|
||||
icon_change_count_(0),
|
||||
weak_factory_(this) {
|
||||
}
|
||||
|
||||
AppIndicatorIcon::~AppIndicatorIcon() {
|
||||
if (icon_) {
|
||||
app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
|
||||
g_object_unref(icon_);
|
||||
content::BrowserThread::GetBlockingPool()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&DeleteTempImagePath, icon_file_path_.DirName()));
|
||||
}
|
||||
}
|
||||
|
||||
bool AppIndicatorIcon::CouldOpen() {
|
||||
EnsureMethodsLoaded();
|
||||
return g_opened;
|
||||
}
|
||||
|
||||
void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) {
|
||||
if (!g_opened)
|
||||
return;
|
||||
|
||||
++icon_change_count_;
|
||||
|
||||
// We create a deep copy of the image since it may have been freed by the time
|
||||
// it's accessed in the other thread.
|
||||
scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy());
|
||||
base::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::GetBlockingPool()
|
||||
->GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
|
||||
FROM_HERE,
|
||||
base::Bind(&CreateTempImageFile,
|
||||
safe_image.release(),
|
||||
icon_change_count_,
|
||||
id_),
|
||||
base::Bind(&AppIndicatorIcon::SetImageFromFile,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
|
||||
// Ignore pressed images, since the standard on Linux is to not highlight
|
||||
// pressed status icons.
|
||||
}
|
||||
|
||||
void AppIndicatorIcon::SetToolTip(const std::string& tool_tip) {
|
||||
// App indicator doesn't have tooltips:
|
||||
// https://bugs.launchpad.net/indicator-application/+bug/527458
|
||||
}
|
||||
|
||||
void AppIndicatorIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
|
||||
// The icon is created asynchronously, wait until the icon has been ready.
|
||||
if (!icon_) {
|
||||
content::BrowserThread::GetBlockingPool()
|
||||
->GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&AppIndicatorIcon::SetContextMenu,
|
||||
weak_factory_.GetWeakPtr(),
|
||||
base::Unretained(menu_model)));
|
||||
return;
|
||||
}
|
||||
|
||||
menu_.reset(new MenuGtk(NULL, menu_model));
|
||||
app_indicator_set_menu(icon_, GTK_MENU(menu_->widget()));
|
||||
}
|
||||
|
||||
void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
||||
if (icon_file_path.empty())
|
||||
return;
|
||||
|
||||
base::FilePath old_path = icon_file_path_;
|
||||
icon_file_path_ = icon_file_path;
|
||||
|
||||
std::string icon_name =
|
||||
icon_file_path_.BaseName().RemoveExtension().value();
|
||||
std::string icon_dir = icon_file_path_.DirName().value();
|
||||
if (!icon_) {
|
||||
icon_ =
|
||||
app_indicator_new_with_path(id_.c_str(),
|
||||
icon_name.c_str(),
|
||||
APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
|
||||
icon_dir.c_str());
|
||||
app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE);
|
||||
} else {
|
||||
// Currently we are creating a new temp directory every time the icon is
|
||||
// set. So we need to set the directory each time.
|
||||
app_indicator_set_icon_theme_path(icon_, icon_dir.c_str());
|
||||
app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon");
|
||||
|
||||
// Delete previous icon directory.
|
||||
content::BrowserThread::GetBlockingPool()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&DeleteTempImagePath, old_path.DirName()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_
|
||||
#define ATOM_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/tray_icon.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "ui/base/gtk/gtk_signal.h"
|
||||
|
||||
typedef struct _AppIndicator AppIndicator;
|
||||
typedef struct _GtkWidget GtkWidget;
|
||||
|
||||
class MenuGtk;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AppIndicatorIcon : public TrayIcon {
|
||||
public:
|
||||
AppIndicatorIcon();
|
||||
virtual ~AppIndicatorIcon();
|
||||
|
||||
// Indicates whether libappindicator so could be opened.
|
||||
static bool CouldOpen();
|
||||
|
||||
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
|
||||
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
|
||||
|
||||
private:
|
||||
void SetImageFromFile(const base::FilePath& icon_file_path);
|
||||
|
||||
// Gtk status icon wrapper
|
||||
AppIndicator* icon_;
|
||||
|
||||
// The context menu for this icon (if any).
|
||||
scoped_ptr<MenuGtk> menu_;
|
||||
|
||||
std::string id_;
|
||||
base::FilePath icon_file_path_;
|
||||
int icon_change_count_;
|
||||
|
||||
base::WeakPtrFactory<AppIndicatorIcon> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AppIndicatorIcon);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_
|
|
@ -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
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_GTK_STATUS_ICON_H_
|
||||
#define ATOM_BROWSER_UI_GTK_STATUS_ICON_H_
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/tray_icon.h"
|
||||
#include "ui/base/gtk/gtk_signal.h"
|
||||
|
||||
class MenuGtk;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class StatusIcon : public TrayIcon {
|
||||
public:
|
||||
StatusIcon();
|
||||
virtual ~StatusIcon();
|
||||
|
||||
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
|
||||
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Callback invoked when user right-clicks on the status icon.
|
||||
CHROMEGTK_CALLBACK_2(StatusIcon, void, OnPopupMenu, guint, guint);
|
||||
|
||||
// Callback invoked when the icon is clicked.
|
||||
CHROMEGTK_CALLBACK_0(StatusIcon, void, OnActivate);
|
||||
|
||||
// The currently-displayed icon for the window.
|
||||
GtkStatusIcon* icon_;
|
||||
|
||||
// The context menu for this icon (if any).
|
||||
scoped_ptr<MenuGtk> menu_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StatusIcon);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_GTK_STATUS_ICON_H_
|
|
@ -1,135 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "chrome/browser/ui/gtk/gtk_util.h"
|
||||
#include "ui/base/gtk/gtk_signal.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
class MessageBox {
|
||||
public:
|
||||
MessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail)
|
||||
: cancel_id_(0),
|
||||
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
|
||||
GtkWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
dialog_ = gtk_dialog_new_with_buttons(
|
||||
title.c_str(),
|
||||
window,
|
||||
static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
|
||||
NULL);
|
||||
|
||||
for (size_t i = 0; i < buttons.size(); ++i)
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog_),
|
||||
TranslateToStock(i, buttons[i]),
|
||||
i);
|
||||
|
||||
GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_));
|
||||
GtkWidget* message_label = gtk_util::CreateBoldLabel(message);
|
||||
gtk_util::LeftAlignMisc(message_label);
|
||||
gtk_box_pack_start(GTK_BOX(content_area), message_label, FALSE, FALSE, 0);
|
||||
GtkWidget* detail_label = gtk_label_new(detail.c_str());
|
||||
gtk_util::LeftAlignMisc(detail_label);
|
||||
gtk_box_pack_start(GTK_BOX(content_area), detail_label, FALSE, FALSE, 0);
|
||||
|
||||
gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
|
||||
}
|
||||
|
||||
~MessageBox() {
|
||||
gtk_widget_destroy(dialog_);
|
||||
}
|
||||
|
||||
const char* TranslateToStock(int id, const std::string& text) {
|
||||
if (LowerCaseEqualsASCII(text, "cancel")) {
|
||||
cancel_id_ = id;
|
||||
return GTK_STOCK_CANCEL;
|
||||
} else if (LowerCaseEqualsASCII(text, "no")) {
|
||||
cancel_id_ = id;
|
||||
return GTK_STOCK_NO;
|
||||
} else if (LowerCaseEqualsASCII(text, "ok")) {
|
||||
return GTK_STOCK_OK;
|
||||
} else if (LowerCaseEqualsASCII(text, "yes")) {
|
||||
return GTK_STOCK_YES;
|
||||
} else {
|
||||
return text.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
void RunAsynchronous(const MessageBoxCallback& callback) {
|
||||
callback_ = callback;
|
||||
g_signal_connect(dialog_, "delete-event",
|
||||
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
||||
g_signal_connect(dialog_, "response",
|
||||
G_CALLBACK(OnResponseDialogThunk), this);
|
||||
gtk_widget_show_all(dialog_);
|
||||
}
|
||||
|
||||
CHROMEGTK_CALLBACK_1(MessageBox, void, OnResponseDialog, int);
|
||||
|
||||
GtkWidget* dialog() const { return dialog_; }
|
||||
int cancel_id() const { return cancel_id_; }
|
||||
|
||||
private:
|
||||
GtkWidget* dialog_;
|
||||
MessageBoxCallback callback_;
|
||||
|
||||
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
|
||||
|
||||
// The id to return when the dialog is closed without pressing buttons.
|
||||
int cancel_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageBox);
|
||||
};
|
||||
|
||||
void MessageBox::OnResponseDialog(GtkWidget* widget, int response) {
|
||||
gtk_widget_hide_all(dialog_);
|
||||
|
||||
if (response < 0)
|
||||
callback_.Run(cancel_id_);
|
||||
else
|
||||
callback_.Run(response);
|
||||
delete this;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
MessageBox message_box(parent_window, type, buttons, title, message, detail);
|
||||
gtk_widget_show_all(message_box.dialog());
|
||||
int response = gtk_dialog_run(GTK_DIALOG(message_box.dialog()));
|
||||
if (response < 0)
|
||||
return message_box.cancel_id();
|
||||
else
|
||||
return response;
|
||||
}
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const MessageBoxCallback& callback) {
|
||||
MessageBox* message_box = new MessageBox(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
message_box->RunAsynchronous(callback);
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -9,14 +9,18 @@
|
|||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/controls/button/label_button.h"
|
||||
#include "ui/views/controls/message_box_view.h"
|
||||
#include "ui/views/layout/grid_layout.h"
|
||||
#include "ui/views/layout/layout_constants.h"
|
||||
#include "ui/views/bubble/bubble_border.h"
|
||||
#include "ui/views/bubble/bubble_frame_view.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/wm/core/shadow_types.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -26,8 +30,9 @@ namespace {
|
|||
// conflict with other groups that could be in the dialog content.
|
||||
const int kButtonGroup = 1127;
|
||||
|
||||
class MessageDialog : public base::MessageLoop::Dispatcher,
|
||||
public views::WidgetDelegate,
|
||||
class MessageDialogClientView;
|
||||
|
||||
class MessageDialog : public views::WidgetDelegate,
|
||||
public views::View,
|
||||
public views::ButtonListener {
|
||||
public:
|
||||
|
@ -39,7 +44,8 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
|
|||
const std::string& detail);
|
||||
virtual ~MessageDialog();
|
||||
|
||||
void Show();
|
||||
void Show(base::RunLoop* run_loop = NULL);
|
||||
void Close();
|
||||
|
||||
int GetResult() const;
|
||||
|
||||
|
@ -49,17 +55,16 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
|
|||
}
|
||||
|
||||
private:
|
||||
// Overridden from MessageLoop::Dispatcher:
|
||||
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
|
||||
|
||||
// Overridden from views::WidgetDelegate:
|
||||
virtual string16 GetWindowTitle() const;
|
||||
virtual void WindowClosing() OVERRIDE;
|
||||
virtual base::string16 GetWindowTitle() const;
|
||||
virtual views::Widget* GetWidget() OVERRIDE;
|
||||
virtual const views::Widget* GetWidget() const OVERRIDE;
|
||||
virtual views::View* GetContentsView() OVERRIDE;
|
||||
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
|
||||
virtual ui::ModalType GetModalType() const OVERRIDE;
|
||||
virtual views::NonClientFrameView* CreateNonClientFrameView(
|
||||
views::Widget* widget) OVERRIDE;
|
||||
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual gfx::Size GetPreferredSize() OVERRIDE;
|
||||
|
@ -70,19 +75,41 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
|
|||
virtual void ButtonPressed(views::Button* sender,
|
||||
const ui::Event& event) OVERRIDE;
|
||||
|
||||
bool should_close_;
|
||||
bool delete_on_close_;
|
||||
int result_;
|
||||
string16 title_;
|
||||
views::Widget* widget_;
|
||||
base::string16 title_;
|
||||
|
||||
NativeWindow* parent_;
|
||||
scoped_ptr<views::Widget> widget_;
|
||||
views::MessageBoxView* message_box_view_;
|
||||
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
|
||||
std::vector<views::LabelButton*> buttons_;
|
||||
|
||||
base::RunLoop* run_loop_;
|
||||
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
|
||||
MessageBoxCallback callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageDialog);
|
||||
};
|
||||
|
||||
class MessageDialogClientView : public views::ClientView {
|
||||
public:
|
||||
MessageDialogClientView(MessageDialog* dialog, views::Widget* widget)
|
||||
: views::ClientView(widget, dialog),
|
||||
dialog_(dialog) {
|
||||
}
|
||||
|
||||
// views::ClientView:
|
||||
virtual bool CanClose() OVERRIDE {
|
||||
dialog_->Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
MessageDialog* dialog_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageDialogClientView);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MessageDialog, public:
|
||||
|
||||
|
@ -92,27 +119,30 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail)
|
||||
: should_close_(false),
|
||||
delete_on_close_(false),
|
||||
: delete_on_close_(false),
|
||||
result_(-1),
|
||||
title_(UTF8ToUTF16(title)),
|
||||
widget_(NULL),
|
||||
title_(base::UTF8ToUTF16(title)),
|
||||
parent_(parent_window),
|
||||
message_box_view_(NULL),
|
||||
run_loop_(NULL),
|
||||
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
|
||||
DCHECK_GT(buttons.size(), 0u);
|
||||
set_owned_by_client();
|
||||
|
||||
views::MessageBoxView::InitParams params(UTF8ToUTF16(title));
|
||||
params.message = UTF8ToUTF16(message + "\n" + detail);
|
||||
message_box_view_ = new views::MessageBoxView(params);
|
||||
if (!parent_)
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
|
||||
std::string content = message + "\n" + detail;
|
||||
views::MessageBoxView::InitParams box_params(base::UTF8ToUTF16(content));
|
||||
message_box_view_ = new views::MessageBoxView(box_params);
|
||||
AddChildView(message_box_view_);
|
||||
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
views::LabelButton* button = new views::LabelButton(
|
||||
this, UTF8ToUTF16(buttons[i]));
|
||||
this, base::UTF8ToUTF16(buttons[i]));
|
||||
button->set_tag(i);
|
||||
button->set_min_size(gfx::Size(60, 20));
|
||||
button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
|
||||
button->set_min_size(gfx::Size(60, 30));
|
||||
button->SetStyle(views::Button::STYLE_BUTTON);
|
||||
button->SetGroup(kButtonGroup);
|
||||
|
||||
buttons_.push_back(button);
|
||||
|
@ -123,29 +153,48 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
|||
buttons_[0]->SetIsDefault(true);
|
||||
buttons_[0]->AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
|
||||
|
||||
views::Widget::InitParams widget_params;
|
||||
widget_params.delegate = this;
|
||||
widget_params.top_level = true;
|
||||
if (parent_window)
|
||||
widget_params.parent = parent_window->GetNativeWindow();
|
||||
widget_ = new views::Widget;
|
||||
widget_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
|
||||
widget_->Init(widget_params);
|
||||
views::Widget::InitParams params;
|
||||
params.delegate = this;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
params.top_level = true;
|
||||
if (parent_) {
|
||||
params.parent = parent_->GetNativeWindow();
|
||||
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
|
||||
// Use bubble style for dialog has a parent.
|
||||
params.remove_standard_frame = true;
|
||||
}
|
||||
|
||||
#if defined(USE_X11)
|
||||
// In X11 the window frame is drawn by the application.
|
||||
params.remove_standard_frame = true;
|
||||
#endif
|
||||
|
||||
widget_.reset(new views::Widget);
|
||||
widget_->Init(params);
|
||||
|
||||
// Bind to ESC.
|
||||
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
|
||||
|
||||
set_background(views::Background::CreateSolidBackground(
|
||||
skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW))));
|
||||
}
|
||||
|
||||
MessageDialog::~MessageDialog() {
|
||||
}
|
||||
|
||||
void MessageDialog::Show() {
|
||||
void MessageDialog::Show(base::RunLoop* run_loop) {
|
||||
run_loop_ = run_loop;
|
||||
widget_->Show();
|
||||
}
|
||||
|
||||
void MessageDialog::Close() {
|
||||
dialog_scope_.reset();
|
||||
|
||||
if (delete_on_close_) {
|
||||
callback_.Run(GetResult());
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
} else if (run_loop_) {
|
||||
run_loop_->Quit();
|
||||
}
|
||||
}
|
||||
|
||||
int MessageDialog::GetResult() const {
|
||||
// When the dialog is closed without choosing anything, we think the user
|
||||
// chose 'Cancel', otherwise we think the default behavior is chosen.
|
||||
|
@ -164,32 +213,16 @@ int MessageDialog::GetResult() const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MessageDialog, private:
|
||||
|
||||
bool MessageDialog::Dispatch(const base::NativeEvent& event) {
|
||||
TranslateMessage(&event);
|
||||
DispatchMessage(&event);
|
||||
return !should_close_;
|
||||
}
|
||||
|
||||
string16 MessageDialog::GetWindowTitle() const {
|
||||
base::string16 MessageDialog::GetWindowTitle() const {
|
||||
return title_;
|
||||
}
|
||||
|
||||
void MessageDialog::WindowClosing() {
|
||||
should_close_ = true;
|
||||
dialog_scope_.reset();
|
||||
|
||||
if (delete_on_close_) {
|
||||
callback_.Run(GetResult());
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
}
|
||||
}
|
||||
|
||||
views::Widget* MessageDialog::GetWidget() {
|
||||
return widget_;
|
||||
return widget_.get();
|
||||
}
|
||||
|
||||
const views::Widget* MessageDialog::GetWidget() const {
|
||||
return widget_;
|
||||
return widget_.get();
|
||||
}
|
||||
|
||||
views::View* MessageDialog::GetContentsView() {
|
||||
|
@ -204,7 +237,27 @@ views::View* MessageDialog::GetInitiallyFocusedView() {
|
|||
}
|
||||
|
||||
ui::ModalType MessageDialog::GetModalType() const {
|
||||
return ui::MODAL_TYPE_WINDOW;
|
||||
return ui::MODAL_TYPE_SYSTEM;
|
||||
}
|
||||
|
||||
views::NonClientFrameView* MessageDialog::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
if (!parent_)
|
||||
return NULL;
|
||||
|
||||
// Create a bubble style frame like Chrome.
|
||||
views::BubbleFrameView* frame = new views::BubbleFrameView(gfx::Insets());
|
||||
const SkColor color = widget->GetNativeTheme()->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_DialogBackground);
|
||||
scoped_ptr<views::BubbleBorder> border(new views::BubbleBorder(
|
||||
views::BubbleBorder::FLOAT, views::BubbleBorder::SMALL_SHADOW, color));
|
||||
frame->SetBubbleBorder(border.Pass());
|
||||
wm::SetShadowType(widget->GetNativeWindow(), wm::SHADOW_TYPE_NONE);
|
||||
return frame;
|
||||
}
|
||||
|
||||
views::ClientView* MessageDialog::CreateClientView(views::Widget* widget) {
|
||||
return new MessageDialogClientView(this, widget);
|
||||
}
|
||||
|
||||
gfx::Size MessageDialog::GetPreferredSize() {
|
||||
|
@ -269,11 +322,11 @@ int ShowMessageBox(NativeWindow* parent_window,
|
|||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
MessageDialog dialog(parent_window, type, buttons, title, message, detail);
|
||||
dialog.Show();
|
||||
{
|
||||
base::MessageLoop::ScopedNestableTaskAllower allow(
|
||||
base::MessageLoopForUI::current());
|
||||
base::RunLoop run_loop(&dialog);
|
||||
base::RunLoop run_loop;
|
||||
dialog.Show(&run_loop);
|
||||
run_loop.Run();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
43
atom/browser/ui/tray_icon_gtk.h
Normal file
43
atom/browser/ui/tray_icon_gtk.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_TRAY_ICON_GTK_H_
|
||||
#define ATOM_BROWSER_UI_TRAY_ICON_GTK_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/tray_icon.h"
|
||||
#include "ui/views/linux_ui/status_icon_linux.h"
|
||||
|
||||
namespace views {
|
||||
class StatusIconLinux;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class TrayIconGtk : public TrayIcon,
|
||||
public views::StatusIconLinux::Delegate {
|
||||
public:
|
||||
TrayIconGtk();
|
||||
virtual ~TrayIconGtk();
|
||||
|
||||
// TrayIcon:
|
||||
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
|
||||
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
|
||||
|
||||
private:
|
||||
// views::StatusIconLinux::Delegate:
|
||||
virtual void OnClick() OVERRIDE;
|
||||
virtual bool HasClickAction() OVERRIDE;
|
||||
|
||||
scoped_ptr<views::StatusIconLinux> icon_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TrayIconGtk);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_TRAY_ICON_GTK_H_
|
115
atom/browser/ui/views/frameless_view.cc
Normal file
115
atom/browser/ui/views/frameless_view.cc
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/frameless_view.h"
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kResizeInsideBoundsSize = 5;
|
||||
const int kResizeAreaCornerSize = 16;
|
||||
|
||||
const char kViewClassName[] = "FramelessView";
|
||||
|
||||
} // namespace
|
||||
|
||||
FramelessView::FramelessView() : window_(NULL), frame_(NULL) {
|
||||
}
|
||||
|
||||
FramelessView::~FramelessView() {
|
||||
}
|
||||
|
||||
void FramelessView::Init(NativeWindowViews* window, views::Widget* frame) {
|
||||
window_ = window;
|
||||
frame_ = frame;
|
||||
}
|
||||
|
||||
int FramelessView::ResizingBorderHitTest(const gfx::Point& point) {
|
||||
// Check the frame first, as we allow a small area overlapping the contents
|
||||
// to be used for resize handles.
|
||||
bool can_ever_resize = frame_->widget_delegate() ?
|
||||
frame_->widget_delegate()->CanResize() :
|
||||
false;
|
||||
// Don't allow overlapping resize handles when the window is maximized or
|
||||
// fullscreen, as it can't be resized in those states.
|
||||
int resize_border =
|
||||
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
|
||||
kResizeInsideBoundsSize;
|
||||
return GetHTComponentForFrame(point, resize_border, resize_border,
|
||||
kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize);
|
||||
}
|
||||
|
||||
gfx::Rect FramelessView::GetBoundsForClientView() const {
|
||||
return bounds();
|
||||
}
|
||||
|
||||
gfx::Rect FramelessView::GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const {
|
||||
gfx::Rect window_bounds = client_bounds;
|
||||
// Enforce minimum size (1, 1) in case that client_bounds is passed with
|
||||
// empty size. This could occur when the frameless window is being
|
||||
// initialized.
|
||||
if (window_bounds.IsEmpty()) {
|
||||
window_bounds.set_width(1);
|
||||
window_bounds.set_height(1);
|
||||
}
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
int FramelessView::NonClientHitTest(const gfx::Point& cursor) {
|
||||
if (frame_->IsFullscreen())
|
||||
return HTCLIENT;
|
||||
|
||||
// Check for possible draggable region in the client area for the frameless
|
||||
// window.
|
||||
SkRegion* draggable_region = window_->draggable_region();
|
||||
if (draggable_region && draggable_region->contains(cursor.x(), cursor.y()))
|
||||
return HTCAPTION;
|
||||
|
||||
// Support resizing frameless window by dragging the border.
|
||||
int frame_component = ResizingBorderHitTest(cursor);
|
||||
if (frame_component != HTNOWHERE)
|
||||
return frame_component;
|
||||
|
||||
return HTCLIENT;
|
||||
}
|
||||
|
||||
void FramelessView::GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) {
|
||||
}
|
||||
|
||||
void FramelessView::ResetWindowControls() {
|
||||
}
|
||||
|
||||
void FramelessView::UpdateWindowIcon() {
|
||||
}
|
||||
|
||||
void FramelessView::UpdateWindowTitle() {
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetPreferredSize() {
|
||||
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetMinimumSize() {
|
||||
return window_->GetMinimumSize();
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetMaximumSize() {
|
||||
return window_->GetMaximumSize();
|
||||
}
|
||||
|
||||
const char* FramelessView::GetClassName() const {
|
||||
return kViewClassName;
|
||||
}
|
||||
|
||||
} // namespace atom
|
56
atom/browser/ui/views/frameless_view.h
Normal file
56
atom/browser/ui/views/frameless_view.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_
|
||||
|
||||
#include "ui/views/window/non_client_view.h"
|
||||
|
||||
namespace views {
|
||||
class Widget;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowViews;
|
||||
|
||||
class FramelessView : public views::NonClientFrameView {
|
||||
public:
|
||||
FramelessView();
|
||||
virtual ~FramelessView();
|
||||
|
||||
virtual void Init(NativeWindowViews* window, views::Widget* frame);
|
||||
|
||||
// Returns whether the |point| is on frameless window's resizing border.
|
||||
int ResizingBorderHitTest(const gfx::Point& point);
|
||||
|
||||
protected:
|
||||
// views::NonClientFrameView:
|
||||
virtual gfx::Rect GetBoundsForClientView() const OVERRIDE;
|
||||
virtual gfx::Rect GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const OVERRIDE;
|
||||
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
|
||||
virtual void GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) OVERRIDE;
|
||||
virtual void ResetWindowControls() OVERRIDE;
|
||||
virtual void UpdateWindowIcon() OVERRIDE;
|
||||
virtual void UpdateWindowTitle() OVERRIDE;
|
||||
|
||||
// Overridden from View:
|
||||
virtual gfx::Size GetPreferredSize() OVERRIDE;
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE;
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE;
|
||||
virtual const char* GetClassName() const OVERRIDE;
|
||||
|
||||
// Not owned.
|
||||
NativeWindowViews* window_;
|
||||
views::Widget* frame_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(FramelessView);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_
|
311
atom/browser/ui/views/global_menu_bar_x11.cc
Normal file
311
atom/browser/ui/views/global_menu_bar_x11.cc
Normal file
|
@ -0,0 +1,311 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/global_menu_bar_x11.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
// This conflicts with mate::Converter,
|
||||
#undef True
|
||||
#undef False
|
||||
// and V8.
|
||||
#undef None
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
|
||||
|
||||
// libdbusmenu-glib types
|
||||
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);
|
||||
|
||||
typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
|
||||
typedef GList* (*dbusmenu_menuitem_get_children_func)(DbusmenuMenuitem* item);
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
|
||||
DbusmenuMenuitem* parent,
|
||||
DbusmenuMenuitem* child);
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
|
||||
DbusmenuMenuitem* item,
|
||||
const char* property,
|
||||
const char* value);
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)(
|
||||
DbusmenuMenuitem* item,
|
||||
const char* property,
|
||||
GVariant* value);
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)(
|
||||
DbusmenuMenuitem* item,
|
||||
const char* property,
|
||||
bool value);
|
||||
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)(
|
||||
DbusmenuMenuitem* item,
|
||||
const char* property,
|
||||
int value);
|
||||
|
||||
typedef struct _DbusmenuServer DbusmenuServer;
|
||||
typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object);
|
||||
typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self,
|
||||
DbusmenuMenuitem* root);
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Retrieved functions from libdbusmenu-glib.
|
||||
|
||||
// DbusmenuMenuItem methods:
|
||||
dbusmenu_menuitem_new_func menuitem_new = NULL;
|
||||
dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
|
||||
dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
|
||||
dbusmenu_menuitem_get_children_func menuitem_get_children = NULL;
|
||||
dbusmenu_menuitem_get_children_func menuitem_take_children = NULL;
|
||||
dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
|
||||
dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
|
||||
dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
|
||||
NULL;
|
||||
dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL;
|
||||
dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL;
|
||||
|
||||
// DbusmenuServer methods:
|
||||
dbusmenu_server_new_func server_new = NULL;
|
||||
dbusmenu_server_set_root_func server_set_root = NULL;
|
||||
|
||||
// Properties that we set on menu items:
|
||||
const char kPropertyEnabled[] = "enabled";
|
||||
const char kPropertyLabel[] = "label";
|
||||
const char kPropertyShortcut[] = "shortcut";
|
||||
const char kPropertyType[] = "type";
|
||||
const char kPropertyToggleType[] = "toggle-type";
|
||||
const char kPropertyToggleState[] = "toggle-state";
|
||||
const char kPropertyVisible[] = "visible";
|
||||
const char kPropertyChildrenDisplay[] = "children-display";
|
||||
|
||||
const char kToggleCheck[] = "checkmark";
|
||||
const char kToggleRadio[] = "radio";
|
||||
const char kTypeSeparator[] = "separator";
|
||||
const char kDisplaySubmenu[] = "submenu";
|
||||
|
||||
void EnsureMethodsLoaded() {
|
||||
static bool attempted_load = false;
|
||||
if (attempted_load)
|
||||
return;
|
||||
attempted_load = true;
|
||||
|
||||
void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY);
|
||||
if (!dbusmenu_lib)
|
||||
dbusmenu_lib = dlopen("libdbusmenu-glib.so.4", RTLD_LAZY);
|
||||
if (!dbusmenu_lib)
|
||||
return;
|
||||
|
||||
// DbusmenuMenuItem methods.
|
||||
menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
|
||||
menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
|
||||
menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
|
||||
menuitem_get_children = reinterpret_cast<dbusmenu_menuitem_get_children_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children"));
|
||||
menuitem_take_children =
|
||||
reinterpret_cast<dbusmenu_menuitem_get_children_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_take_children"));
|
||||
menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
|
||||
menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
|
||||
menuitem_property_set_variant =
|
||||
reinterpret_cast<dbusmenu_menuitem_property_set_variant_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant"));
|
||||
menuitem_property_set_bool =
|
||||
reinterpret_cast<dbusmenu_menuitem_property_set_bool_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool"));
|
||||
menuitem_property_set_int =
|
||||
reinterpret_cast<dbusmenu_menuitem_property_set_int_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int"));
|
||||
|
||||
// DbusmenuServer methods.
|
||||
server_new = reinterpret_cast<dbusmenu_server_new_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_server_new"));
|
||||
server_set_root = reinterpret_cast<dbusmenu_server_set_root_func>(
|
||||
dlsym(dbusmenu_lib, "dbusmenu_server_set_root"));
|
||||
}
|
||||
|
||||
ui::MenuModel* ModelForMenuItem(DbusmenuMenuitem* item) {
|
||||
return reinterpret_cast<ui::MenuModel*>(
|
||||
g_object_get_data(G_OBJECT(item), "model"));
|
||||
}
|
||||
|
||||
bool GetMenuItemID(DbusmenuMenuitem* item, int *id) {
|
||||
gpointer id_ptr = g_object_get_data(G_OBJECT(item), "menu-id");
|
||||
if (id_ptr != NULL) {
|
||||
*id = GPOINTER_TO_INT(id_ptr) - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetMenuItemID(DbusmenuMenuitem* item, int id) {
|
||||
DCHECK_GE(id, 0);
|
||||
|
||||
// Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
|
||||
g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window)
|
||||
: window_(window),
|
||||
xid_(window_->GetNativeWindow()->GetHost()->GetAcceleratedWidget()),
|
||||
server_(NULL) {
|
||||
EnsureMethodsLoaded();
|
||||
if (server_new)
|
||||
InitServer(xid_);
|
||||
|
||||
GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
|
||||
}
|
||||
|
||||
GlobalMenuBarX11::~GlobalMenuBarX11() {
|
||||
if (IsServerStarted())
|
||||
g_object_unref(server_);
|
||||
|
||||
GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
|
||||
}
|
||||
|
||||
// static
|
||||
std::string GlobalMenuBarX11::GetPathForWindow(gfx::AcceleratedWidget xid) {
|
||||
return base::StringPrintf("/com/canonical/menu/%lX", xid);
|
||||
}
|
||||
|
||||
void GlobalMenuBarX11::SetMenu(ui::MenuModel* menu_model) {
|
||||
if (!IsServerStarted())
|
||||
return;
|
||||
|
||||
DbusmenuMenuitem* root_item = menuitem_new();
|
||||
menuitem_property_set(root_item, kPropertyLabel, "Root");
|
||||
menuitem_property_set_bool(root_item, kPropertyVisible, true);
|
||||
BuildMenuFromModel(menu_model, root_item);
|
||||
|
||||
server_set_root(server_, root_item);
|
||||
g_object_unref(root_item);
|
||||
}
|
||||
|
||||
bool GlobalMenuBarX11::IsServerStarted() const {
|
||||
return server_;
|
||||
}
|
||||
|
||||
void GlobalMenuBarX11::InitServer(gfx::AcceleratedWidget xid) {
|
||||
std::string path = GetPathForWindow(xid);
|
||||
server_ = server_new(path.c_str());
|
||||
}
|
||||
|
||||
void GlobalMenuBarX11::BuildMenuFromModel(ui::MenuModel* model,
|
||||
DbusmenuMenuitem* parent) {
|
||||
for (int i = 0; i < model->GetItemCount(); ++i) {
|
||||
DbusmenuMenuitem* item = menuitem_new();
|
||||
menuitem_property_set_bool(item, kPropertyVisible, model->IsVisibleAt(i));
|
||||
|
||||
ui::MenuModel::ItemType type = model->GetTypeAt(i);
|
||||
if (type == ui::MenuModel::TYPE_SEPARATOR) {
|
||||
menuitem_property_set(item, kPropertyType, kTypeSeparator);
|
||||
} else {
|
||||
std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
|
||||
base::UTF16ToUTF8(model->GetLabelAt(i)));
|
||||
menuitem_property_set(item, kPropertyLabel, label.c_str());
|
||||
menuitem_property_set_bool(item, kPropertyEnabled, model->IsEnabledAt(i));
|
||||
|
||||
g_object_set_data(G_OBJECT(item), "model", model);
|
||||
SetMenuItemID(item, i);
|
||||
|
||||
if (type == ui::MenuModel::TYPE_SUBMENU) {
|
||||
menuitem_property_set(item, kPropertyChildrenDisplay, kDisplaySubmenu);
|
||||
g_signal_connect(item, "about-to-show",
|
||||
G_CALLBACK(OnSubMenuShowThunk), this);
|
||||
} else {
|
||||
ui::Accelerator accelerator;
|
||||
if (model->GetAcceleratorAt(i, &accelerator))
|
||||
RegisterAccelerator(item, accelerator);
|
||||
|
||||
g_signal_connect(item, "item-activated",
|
||||
G_CALLBACK(OnItemActivatedThunk), this);
|
||||
|
||||
if (type == ui::MenuModel::TYPE_CHECK ||
|
||||
type == ui::MenuModel::TYPE_RADIO) {
|
||||
menuitem_property_set(item, kPropertyToggleType,
|
||||
type == ui::MenuModel::TYPE_CHECK ? kToggleCheck : kToggleRadio);
|
||||
menuitem_property_set_int(item, kPropertyToggleState,
|
||||
model->IsItemCheckedAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menuitem_child_append(parent, item);
|
||||
g_object_unref(item);
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
|
||||
const ui::Accelerator& accelerator) {
|
||||
// A translation of libdbusmenu-gtk's menuitem_property_set_shortcut()
|
||||
// translated from GDK types to ui::Accelerator types.
|
||||
GVariantBuilder builder;
|
||||
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
|
||||
|
||||
if (accelerator.IsCtrlDown())
|
||||
g_variant_builder_add(&builder, "s", "Control");
|
||||
if (accelerator.IsAltDown())
|
||||
g_variant_builder_add(&builder, "s", "Alt");
|
||||
if (accelerator.IsShiftDown())
|
||||
g_variant_builder_add(&builder, "s", "Shift");
|
||||
|
||||
char* name = XKeysymToString(XKeysymForWindowsKeyCode(
|
||||
accelerator.key_code(), false));
|
||||
if (!name) {
|
||||
NOTIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
g_variant_builder_add(&builder, "s", name);
|
||||
|
||||
GVariant* inside_array = g_variant_builder_end(&builder);
|
||||
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
|
||||
g_variant_builder_add_value(&builder, inside_array);
|
||||
GVariant* outside_array = g_variant_builder_end(&builder);
|
||||
|
||||
menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
|
||||
}
|
||||
|
||||
void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
|
||||
unsigned int timestamp) {
|
||||
int id;
|
||||
ui::MenuModel* model = ModelForMenuItem(item);
|
||||
if (model && GetMenuItemID(item, &id))
|
||||
model->ActivatedAt(id, 0);
|
||||
}
|
||||
|
||||
void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) {
|
||||
int id;
|
||||
ui::MenuModel* model = ModelForMenuItem(item);
|
||||
if (!model || !GetMenuItemID(item, &id))
|
||||
return;
|
||||
|
||||
// Clear children.
|
||||
GList *children = menuitem_take_children(item);
|
||||
g_list_foreach(children, reinterpret_cast<GFunc>(g_object_unref), NULL);
|
||||
g_list_free(children);
|
||||
|
||||
// Build children.
|
||||
BuildMenuFromModel(model->GetSubmenuModelAt(id), item);
|
||||
}
|
||||
|
||||
} // namespace atom
|
74
atom/browser/ui/views/global_menu_bar_x11.h
Normal file
74
atom/browser/ui/views/global_menu_bar_x11.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "ui/base/glib/glib_signal.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
|
||||
typedef struct _DbusmenuServer DbusmenuServer;
|
||||
|
||||
namespace ui {
|
||||
class Accelerator;
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowViews;
|
||||
|
||||
// Controls the Mac style menu bar on Unity.
|
||||
//
|
||||
// Unity has an Apple-like menu bar at the top of the screen that changes
|
||||
// depending on the active window. In the GTK port, we had a hidden GtkMenuBar
|
||||
// object in each GtkWindow which existed only to be scrapped by the
|
||||
// libdbusmenu-gtk code. Since we don't have GtkWindows anymore, we need to
|
||||
// interface directly with the lower level libdbusmenu-glib, which we
|
||||
// opportunistically dlopen() since not everyone is running Ubuntu.
|
||||
//
|
||||
// This class is like the chrome's corresponding one, but it generates the menu
|
||||
// from menu models instead, and it is also per-window specific.
|
||||
class GlobalMenuBarX11 {
|
||||
public:
|
||||
explicit GlobalMenuBarX11(NativeWindowViews* window);
|
||||
virtual ~GlobalMenuBarX11();
|
||||
|
||||
// Creates the object path for DbusemenuServer which is attached to |xid|.
|
||||
static std::string GetPathForWindow(gfx::AcceleratedWidget xid);
|
||||
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
bool IsServerStarted() const;
|
||||
|
||||
private:
|
||||
// Creates a DbusmenuServer.
|
||||
void InitServer(gfx::AcceleratedWidget xid);
|
||||
|
||||
// Create a menu from menu model.
|
||||
void BuildMenuFromModel(ui::MenuModel* model, DbusmenuMenuitem* parent);
|
||||
|
||||
// Sets the accelerator for |item|.
|
||||
void RegisterAccelerator(DbusmenuMenuitem* item,
|
||||
const ui::Accelerator& accelerator);
|
||||
|
||||
CHROMEG_CALLBACK_1(GlobalMenuBarX11, void, OnItemActivated, DbusmenuMenuitem*,
|
||||
unsigned int);
|
||||
CHROMEG_CALLBACK_0(GlobalMenuBarX11, void, OnSubMenuShow, DbusmenuMenuitem*);
|
||||
|
||||
NativeWindowViews* window_;
|
||||
gfx::AcceleratedWidget xid_;
|
||||
|
||||
DbusmenuServer* server_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarX11);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_
|
596
atom/browser/ui/views/linux_frame_view.cc
Normal file
596
atom/browser/ui/views/linux_frame_view.cc
Normal file
|
@ -0,0 +1,596 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/linux_frame_view.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "ui/gfx/font.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/path.h"
|
||||
#include "ui/views/color_constants.h"
|
||||
#include "ui/views/controls/button/image_button.h"
|
||||
#include "ui/views/views_delegate.h"
|
||||
#include "ui/views/widget/native_widget_aura.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
#include "ui/views/window/frame_background.h"
|
||||
#include "ui/views/window/window_resources.h"
|
||||
#include "ui/views/window/window_shape.h"
|
||||
|
||||
// Workaround for including grit headers.
|
||||
#include "ui/ui_resources/grit/ui_resources.h"
|
||||
#include "ui/ui_strings/grit/ui_strings.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// The frame border is only visible in restored mode and is hardcoded to 4 px on
|
||||
// each side regardless of the system window border size.
|
||||
const int kFrameBorderThickness = 4;
|
||||
// In the window corners, the resize areas don't actually expand bigger, but the
|
||||
// 16 px at the end of each edge triggers diagonal resizing.
|
||||
const int kResizeAreaCornerSize = 16;
|
||||
// The titlebar never shrinks too short to show the caption button plus some
|
||||
// padding below it.
|
||||
const int kCaptionButtonHeightWithPadding = 19;
|
||||
// The titlebar has a 2 px 3D edge along the top and bottom.
|
||||
const int kTitlebarTopAndBottomEdgeThickness = 2;
|
||||
// The icon is inset 2 px from the left frame border.
|
||||
const int kIconLeftSpacing = 2;
|
||||
// The icon never shrinks below 16 px on a side.
|
||||
const int kIconMinimumSize = 16;
|
||||
// The space between the window icon and the title text.
|
||||
const int kTitleIconOffsetX = 4;
|
||||
// The space between the title text and the caption buttons.
|
||||
const int kTitleCaptionSpacing = 5;
|
||||
|
||||
#if defined(OS_CHROMEOS)
|
||||
// Chrome OS uses a dark gray.
|
||||
const SkColor kDefaultColorFrame = SkColorSetRGB(109, 109, 109);
|
||||
const SkColor kDefaultColorFrameInactive = SkColorSetRGB(176, 176, 176);
|
||||
#else
|
||||
// Windows and Linux use a blue.
|
||||
const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201);
|
||||
const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228);
|
||||
#endif
|
||||
|
||||
const gfx::FontList& GetTitleFontList() {
|
||||
static const gfx::FontList title_font_list =
|
||||
views::NativeWidgetAura::GetWindowTitleFontList();
|
||||
return title_font_list;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LinuxFrameView, public:
|
||||
|
||||
LinuxFrameView::LinuxFrameView()
|
||||
: window_icon_(NULL),
|
||||
minimize_button_(NULL),
|
||||
maximize_button_(NULL),
|
||||
restore_button_(NULL),
|
||||
close_button_(NULL),
|
||||
should_show_maximize_button_(false),
|
||||
frame_background_(new views::FrameBackground) {
|
||||
}
|
||||
|
||||
LinuxFrameView::~LinuxFrameView() {
|
||||
}
|
||||
|
||||
void LinuxFrameView::Init(NativeWindowViews* window, views::Widget* frame) {
|
||||
FramelessView::Init(window, frame);
|
||||
|
||||
close_button_ = new views::ImageButton(this);
|
||||
close_button_->SetAccessibleName(
|
||||
l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
|
||||
|
||||
// Close button images will be set in LayoutWindowControls().
|
||||
AddChildView(close_button_);
|
||||
|
||||
minimize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MINIMIZE,
|
||||
IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P);
|
||||
|
||||
maximize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MAXIMIZE,
|
||||
IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P);
|
||||
|
||||
restore_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_RESTORE,
|
||||
IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P);
|
||||
|
||||
should_show_maximize_button_ = frame_->widget_delegate()->CanMaximize();
|
||||
|
||||
if (frame_->widget_delegate()->ShouldShowWindowIcon()) {
|
||||
window_icon_ = new views::ImageButton(this);
|
||||
AddChildView(window_icon_);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LinuxFrameView, NonClientFrameView implementation:
|
||||
|
||||
gfx::Rect LinuxFrameView::GetBoundsForClientView() const {
|
||||
return client_view_bounds_;
|
||||
}
|
||||
|
||||
gfx::Rect LinuxFrameView::GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const {
|
||||
int top_height = NonClientTopBorderHeight();
|
||||
int border_thickness = NonClientBorderThickness();
|
||||
return gfx::Rect(client_bounds.x() - border_thickness,
|
||||
client_bounds.y() - top_height,
|
||||
client_bounds.width() + (2 * border_thickness),
|
||||
client_bounds.height() + top_height + border_thickness);
|
||||
}
|
||||
|
||||
int LinuxFrameView::NonClientHitTest(const gfx::Point& point) {
|
||||
if (!window_->has_frame())
|
||||
return FramelessView::NonClientHitTest(point);
|
||||
|
||||
// Sanity check.
|
||||
if (!bounds().Contains(point))
|
||||
return HTNOWHERE;
|
||||
|
||||
int frame_component = frame_->client_view()->NonClientHitTest(point);
|
||||
|
||||
// See if we're in the sysmenu region. (We check the ClientView first to be
|
||||
// consistent with OpaqueBrowserFrameView; it's not really necessary here.)
|
||||
gfx::Rect sysmenu_rect(IconBounds());
|
||||
// In maximized mode we extend the rect to the screen corner to take advantage
|
||||
// of Fitts' Law.
|
||||
if (frame_->IsMaximized())
|
||||
sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom());
|
||||
sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect));
|
||||
if (sysmenu_rect.Contains(point))
|
||||
return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;
|
||||
|
||||
if (frame_component != HTNOWHERE)
|
||||
return frame_component;
|
||||
|
||||
// Then see if the point is within any of the window controls.
|
||||
if (close_button_->GetMirroredBounds().Contains(point))
|
||||
return HTCLOSE;
|
||||
if (restore_button_->GetMirroredBounds().Contains(point))
|
||||
return HTMAXBUTTON;
|
||||
if (maximize_button_->GetMirroredBounds().Contains(point))
|
||||
return HTMAXBUTTON;
|
||||
if (minimize_button_->GetMirroredBounds().Contains(point))
|
||||
return HTMINBUTTON;
|
||||
if (window_icon_ && window_icon_->GetMirroredBounds().Contains(point))
|
||||
return HTSYSMENU;
|
||||
|
||||
int window_component = GetHTComponentForFrame(point, FrameBorderThickness(),
|
||||
NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize,
|
||||
frame_->widget_delegate()->CanResize());
|
||||
// Fall back to the caption if no other component matches.
|
||||
return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
|
||||
}
|
||||
|
||||
void LinuxFrameView::GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) {
|
||||
DCHECK(window_mask);
|
||||
if (frame_->IsMaximized() || !ShouldShowTitleBarAndBorder())
|
||||
return;
|
||||
|
||||
views::GetDefaultWindowMask(size, window_mask);
|
||||
}
|
||||
|
||||
void LinuxFrameView::ResetWindowControls() {
|
||||
restore_button_->SetState(views::CustomButton::STATE_NORMAL);
|
||||
minimize_button_->SetState(views::CustomButton::STATE_NORMAL);
|
||||
maximize_button_->SetState(views::CustomButton::STATE_NORMAL);
|
||||
// The close button isn't affected by this constraint.
|
||||
}
|
||||
|
||||
void LinuxFrameView::UpdateWindowIcon() {
|
||||
if (window_icon_)
|
||||
window_icon_->SchedulePaint();
|
||||
}
|
||||
|
||||
void LinuxFrameView::UpdateWindowTitle() {
|
||||
SchedulePaintInRect(title_bounds_);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LinuxFrameView, View overrides:
|
||||
|
||||
void LinuxFrameView::OnPaint(gfx::Canvas* canvas) {
|
||||
if (!ShouldShowTitleBarAndBorder())
|
||||
return;
|
||||
|
||||
if (frame_->IsMaximized())
|
||||
PaintMaximizedFrameBorder(canvas);
|
||||
else
|
||||
PaintRestoredFrameBorder(canvas);
|
||||
PaintTitleBar(canvas);
|
||||
if (ShouldShowClientEdge())
|
||||
PaintRestoredClientEdge(canvas);
|
||||
}
|
||||
|
||||
void LinuxFrameView::Layout() {
|
||||
if (ShouldShowTitleBarAndBorder()) {
|
||||
LayoutWindowControls();
|
||||
LayoutTitleBar();
|
||||
}
|
||||
|
||||
LayoutClientView();
|
||||
}
|
||||
|
||||
gfx::Size LinuxFrameView::GetPreferredSize() {
|
||||
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();
|
||||
}
|
||||
|
||||
gfx::Size LinuxFrameView::GetMinimumSize() {
|
||||
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
gfx::Rect(frame_->client_view()->GetMinimumSize())).size();
|
||||
}
|
||||
|
||||
gfx::Size LinuxFrameView::GetMaximumSize() {
|
||||
gfx::Size max_size = frame_->client_view()->GetMaximumSize();
|
||||
gfx::Size converted_size =
|
||||
frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
gfx::Rect(max_size)).size();
|
||||
return gfx::Size(max_size.width() == 0 ? 0 : converted_size.width(),
|
||||
max_size.height() == 0 ? 0 : converted_size.height());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LinuxFrameView, ButtonListener implementation:
|
||||
|
||||
void LinuxFrameView::ButtonPressed(views::Button* sender,
|
||||
const ui::Event& event) {
|
||||
if (sender == close_button_)
|
||||
frame_->Close();
|
||||
else if (sender == minimize_button_)
|
||||
frame_->Minimize();
|
||||
else if (sender == maximize_button_)
|
||||
frame_->Maximize();
|
||||
else if (sender == restore_button_)
|
||||
frame_->Restore();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LinuxFrameView, private:
|
||||
|
||||
int LinuxFrameView::FrameBorderThickness() const {
|
||||
return frame_->IsMaximized() ? 0 : kFrameBorderThickness;
|
||||
}
|
||||
|
||||
int LinuxFrameView::NonClientBorderThickness() const {
|
||||
// In maximized mode, we don't show a client edge.
|
||||
return FrameBorderThickness() +
|
||||
(ShouldShowClientEdge() ? kClientEdgeThickness : 0);
|
||||
}
|
||||
|
||||
int LinuxFrameView::NonClientTopBorderHeight() const {
|
||||
return std::max(FrameBorderThickness() + IconSize(),
|
||||
CaptionButtonY() + kCaptionButtonHeightWithPadding) +
|
||||
TitlebarBottomThickness();
|
||||
}
|
||||
|
||||
int LinuxFrameView::CaptionButtonY() const {
|
||||
// Maximized buttons start at window top so that even if their images aren't
|
||||
// drawn flush with the screen edge, they still obey Fitts' Law.
|
||||
return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness;
|
||||
}
|
||||
|
||||
int LinuxFrameView::TitlebarBottomThickness() const {
|
||||
return kTitlebarTopAndBottomEdgeThickness +
|
||||
(ShouldShowClientEdge() ? kClientEdgeThickness : 0);
|
||||
}
|
||||
|
||||
int LinuxFrameView::IconSize() const {
|
||||
#if defined(OS_WIN)
|
||||
// This metric scales up if either the titlebar height or the titlebar font
|
||||
// size are increased.
|
||||
return GetSystemMetrics(SM_CYSMICON);
|
||||
#else
|
||||
return std::max(GetTitleFontList().GetHeight(), kIconMinimumSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Rect LinuxFrameView::IconBounds() const {
|
||||
int size = IconSize();
|
||||
int frame_thickness = FrameBorderThickness();
|
||||
// Our frame border has a different "3D look" than Windows'. Theirs has a
|
||||
// more complex gradient on the top that they push their icon/title below;
|
||||
// then the maximized window cuts this off and the icon/title are centered
|
||||
// in the remaining space. Because the apparent shape of our border is
|
||||
// simpler, using the same positioning makes things look slightly uncentered
|
||||
// with restored windows, so when the window is restored, instead of
|
||||
// calculating the remaining space from below the frame border, we calculate
|
||||
// from below the 3D edge.
|
||||
int unavailable_px_at_top = frame_->IsMaximized() ?
|
||||
frame_thickness : kTitlebarTopAndBottomEdgeThickness;
|
||||
// When the icon is shorter than the minimum space we reserve for the caption
|
||||
// button, we vertically center it. We want to bias rounding to put extra
|
||||
// space above the icon, since the 3D edge (+ client edge, for restored
|
||||
// windows) below looks (to the eye) more like additional space than does the
|
||||
// 3D edge (or nothing at all, for maximized windows) above; hence the +1.
|
||||
int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
|
||||
unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
|
||||
return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
|
||||
}
|
||||
|
||||
bool LinuxFrameView::ShouldShowTitleBarAndBorder() const {
|
||||
if (!window_->has_frame())
|
||||
return false;
|
||||
|
||||
if (frame_->IsFullscreen())
|
||||
return false;
|
||||
|
||||
if (views::ViewsDelegate::views_delegate) {
|
||||
return !views::ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar(
|
||||
frame_->IsMaximized());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxFrameView::ShouldShowClientEdge() const {
|
||||
return !frame_->IsMaximized() && ShouldShowTitleBarAndBorder();
|
||||
}
|
||||
|
||||
void LinuxFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
|
||||
frame_background_->set_frame_color(GetFrameColor());
|
||||
const gfx::ImageSkia* frame_image = GetFrameImage();
|
||||
frame_background_->set_theme_image(frame_image);
|
||||
frame_background_->set_top_area_height(frame_image->height());
|
||||
|
||||
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
|
||||
frame_background_->SetCornerImages(
|
||||
rb.GetImageNamed(IDR_WINDOW_TOP_LEFT_CORNER).ToImageSkia(),
|
||||
rb.GetImageNamed(IDR_WINDOW_TOP_RIGHT_CORNER).ToImageSkia(),
|
||||
rb.GetImageNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER).ToImageSkia(),
|
||||
rb.GetImageNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER).ToImageSkia());
|
||||
frame_background_->SetSideImages(
|
||||
rb.GetImageNamed(IDR_WINDOW_LEFT_SIDE).ToImageSkia(),
|
||||
rb.GetImageNamed(IDR_WINDOW_TOP_CENTER).ToImageSkia(),
|
||||
rb.GetImageNamed(IDR_WINDOW_RIGHT_SIDE).ToImageSkia(),
|
||||
rb.GetImageNamed(IDR_WINDOW_BOTTOM_CENTER).ToImageSkia());
|
||||
|
||||
frame_background_->PaintRestored(canvas, this);
|
||||
}
|
||||
|
||||
void LinuxFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
|
||||
const gfx::ImageSkia* frame_image = GetFrameImage();
|
||||
frame_background_->set_theme_image(frame_image);
|
||||
frame_background_->set_top_area_height(frame_image->height());
|
||||
frame_background_->PaintMaximized(canvas, this);
|
||||
|
||||
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
|
||||
// TODO(jamescook): Migrate this into FrameBackground.
|
||||
// The bottom of the titlebar actually comes from the top of the Client Edge
|
||||
// graphic, with the actual client edge clipped off the bottom.
|
||||
const gfx::ImageSkia* titlebar_bottom = rb.GetImageNamed(
|
||||
IDR_APP_TOP_CENTER).ToImageSkia();
|
||||
int edge_height = titlebar_bottom->height() -
|
||||
(ShouldShowClientEdge() ? kClientEdgeThickness : 0);
|
||||
canvas->TileImageInt(*titlebar_bottom, 0,
|
||||
frame_->client_view()->y() - edge_height, width(), edge_height);
|
||||
}
|
||||
|
||||
void LinuxFrameView::PaintTitleBar(gfx::Canvas* canvas) {
|
||||
views::WidgetDelegate* delegate = frame_->widget_delegate();
|
||||
|
||||
// It seems like in some conditions we can be asked to paint after the window
|
||||
// that contains us is WM_DESTROYed. At this point, our delegate is NULL. The
|
||||
// correct long term fix may be to shut down the RootView in WM_DESTROY.
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
gfx::Rect rect = title_bounds_;
|
||||
rect.set_x(GetMirroredXForRect(title_bounds_));
|
||||
canvas->DrawStringRect(delegate->GetWindowTitle(), GetTitleFontList(),
|
||||
SK_ColorWHITE, rect);
|
||||
}
|
||||
|
||||
void LinuxFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
|
||||
gfx::Rect client_area_bounds = frame_->client_view()->bounds();
|
||||
int client_area_top = client_area_bounds.y();
|
||||
|
||||
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
|
||||
// Top: left, center, right sides.
|
||||
const gfx::ImageSkia* top_left = rb.GetImageSkiaNamed(IDR_APP_TOP_LEFT);
|
||||
const gfx::ImageSkia* top_center = rb.GetImageSkiaNamed(IDR_APP_TOP_CENTER);
|
||||
const gfx::ImageSkia* top_right = rb.GetImageSkiaNamed(IDR_APP_TOP_RIGHT);
|
||||
int top_edge_y = client_area_top - top_center->height();
|
||||
canvas->DrawImageInt(*top_left,
|
||||
client_area_bounds.x() - top_left->width(),
|
||||
top_edge_y);
|
||||
canvas->TileImageInt(*top_center,
|
||||
client_area_bounds.x(),
|
||||
top_edge_y,
|
||||
client_area_bounds.width(),
|
||||
top_center->height());
|
||||
canvas->DrawImageInt(*top_right, client_area_bounds.right(), top_edge_y);
|
||||
|
||||
// Right side.
|
||||
const gfx::ImageSkia* right = rb.GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
|
||||
int client_area_bottom =
|
||||
std::max(client_area_top, client_area_bounds.bottom());
|
||||
int client_area_height = client_area_bottom - client_area_top;
|
||||
canvas->TileImageInt(*right,
|
||||
client_area_bounds.right(),
|
||||
client_area_top,
|
||||
right->width(),
|
||||
client_area_height);
|
||||
|
||||
// Bottom: left, center, right sides.
|
||||
const gfx::ImageSkia* bottom_left =
|
||||
rb.GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
|
||||
const gfx::ImageSkia* bottom_center =
|
||||
rb.GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
|
||||
const gfx::ImageSkia* bottom_right =
|
||||
rb.GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER);
|
||||
|
||||
canvas->DrawImageInt(*bottom_left,
|
||||
client_area_bounds.x() - bottom_left->width(),
|
||||
client_area_bottom);
|
||||
|
||||
canvas->TileImageInt(*bottom_center,
|
||||
client_area_bounds.x(),
|
||||
client_area_bottom,
|
||||
client_area_bounds.width(),
|
||||
bottom_right->height());
|
||||
|
||||
canvas->DrawImageInt(*bottom_right,
|
||||
client_area_bounds.right(),
|
||||
client_area_bottom);
|
||||
// Left side.
|
||||
const gfx::ImageSkia* left = rb.GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE);
|
||||
canvas->TileImageInt(*left,
|
||||
client_area_bounds.x() - left->width(),
|
||||
client_area_top,
|
||||
left->width(),
|
||||
client_area_height);
|
||||
|
||||
// Draw the color to fill in the edges.
|
||||
canvas->FillRect(gfx::Rect(client_area_bounds.x() - 1,
|
||||
client_area_top - 1,
|
||||
client_area_bounds.width() + 1,
|
||||
client_area_bottom - client_area_top + 1),
|
||||
views::kClientEdgeColor);
|
||||
}
|
||||
|
||||
SkColor LinuxFrameView::GetFrameColor() const {
|
||||
return frame_->IsActive() ? kDefaultColorFrame : kDefaultColorFrameInactive;
|
||||
}
|
||||
|
||||
const gfx::ImageSkia* LinuxFrameView::GetFrameImage() const {
|
||||
return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
|
||||
frame_->IsActive() ? IDR_FRAME : IDR_FRAME_INACTIVE).ToImageSkia();
|
||||
}
|
||||
|
||||
void LinuxFrameView::LayoutWindowControls() {
|
||||
close_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
|
||||
views::ImageButton::ALIGN_BOTTOM);
|
||||
int caption_y = CaptionButtonY();
|
||||
bool is_maximized = frame_->IsMaximized();
|
||||
// There should always be the same number of non-shadow pixels visible to the
|
||||
// side of the caption buttons. In maximized mode we extend the rightmost
|
||||
// button to the screen corner to obey Fitts' Law.
|
||||
int right_extra_width = is_maximized ?
|
||||
(kFrameBorderThickness - kFrameShadowThickness) : 0;
|
||||
gfx::Size close_button_size = close_button_->GetPreferredSize();
|
||||
close_button_->SetBounds(width() - FrameBorderThickness() -
|
||||
right_extra_width - close_button_size.width(), caption_y,
|
||||
close_button_size.width() + right_extra_width,
|
||||
close_button_size.height());
|
||||
|
||||
// When the window is restored, we show a maximized button; otherwise, we show
|
||||
// a restore button.
|
||||
bool is_restored = !is_maximized && !frame_->IsMinimized();
|
||||
views::ImageButton* invisible_button = is_restored ? restore_button_
|
||||
: maximize_button_;
|
||||
invisible_button->SetVisible(false);
|
||||
|
||||
views::ImageButton* visible_button = is_restored ? maximize_button_
|
||||
: restore_button_;
|
||||
views::FramePartImage normal_part, hot_part, pushed_part;
|
||||
int next_button_x;
|
||||
if (should_show_maximize_button_) {
|
||||
visible_button->SetVisible(true);
|
||||
visible_button->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
|
||||
views::ImageButton::ALIGN_BOTTOM);
|
||||
gfx::Size visible_button_size = visible_button->GetPreferredSize();
|
||||
visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
|
||||
caption_y, visible_button_size.width(),
|
||||
visible_button_size.height());
|
||||
next_button_x = visible_button->x();
|
||||
} else {
|
||||
visible_button->SetVisible(false);
|
||||
next_button_x = close_button_->x();
|
||||
}
|
||||
|
||||
minimize_button_->SetVisible(true);
|
||||
minimize_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
|
||||
views::ImageButton::ALIGN_BOTTOM);
|
||||
gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
|
||||
minimize_button_->SetBounds(
|
||||
next_button_x - minimize_button_size.width(), caption_y,
|
||||
minimize_button_size.width(),
|
||||
minimize_button_size.height());
|
||||
|
||||
normal_part = IDR_CLOSE;
|
||||
hot_part = IDR_CLOSE_H;
|
||||
pushed_part = IDR_CLOSE_P;
|
||||
|
||||
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
|
||||
close_button_->SetImage(views::CustomButton::STATE_NORMAL,
|
||||
rb.GetImageNamed(normal_part).ToImageSkia());
|
||||
close_button_->SetImage(views::CustomButton::STATE_HOVERED,
|
||||
rb.GetImageNamed(hot_part).ToImageSkia());
|
||||
close_button_->SetImage(views::CustomButton::STATE_PRESSED,
|
||||
rb.GetImageNamed(pushed_part).ToImageSkia());
|
||||
}
|
||||
|
||||
void LinuxFrameView::LayoutTitleBar() {
|
||||
// The window title position is calculated based on the icon position, even
|
||||
// when there is no icon.
|
||||
gfx::Rect icon_bounds(IconBounds());
|
||||
bool show_window_icon = window_icon_ != NULL;
|
||||
if (show_window_icon)
|
||||
window_icon_->SetBoundsRect(icon_bounds);
|
||||
|
||||
// The offset between the window left edge and the title text.
|
||||
int title_x = show_window_icon ? icon_bounds.right() + kTitleIconOffsetX
|
||||
: icon_bounds.x();
|
||||
int title_height = GetTitleFontList().GetHeight();
|
||||
// We bias the title position so that when the difference between the icon and
|
||||
// title heights is odd, the extra pixel of the title is above the vertical
|
||||
// midline rather than below. This compensates for how the icon is already
|
||||
// biased downwards (see IconBounds()) and helps prevent descenders on the
|
||||
// title from overlapping the 3D edge at the bottom of the titlebar.
|
||||
title_bounds_.SetRect(title_x,
|
||||
icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
|
||||
std::max(0, minimize_button_->x() - kTitleCaptionSpacing -
|
||||
title_x), title_height);
|
||||
}
|
||||
|
||||
void LinuxFrameView::LayoutClientView() {
|
||||
if (!ShouldShowTitleBarAndBorder()) {
|
||||
client_view_bounds_ = bounds();
|
||||
return;
|
||||
}
|
||||
|
||||
int top_height = NonClientTopBorderHeight();
|
||||
int border_thickness = NonClientBorderThickness();
|
||||
client_view_bounds_.SetRect(border_thickness, top_height,
|
||||
std::max(0, width() - (2 * border_thickness)),
|
||||
std::max(0, height() - top_height - border_thickness));
|
||||
}
|
||||
|
||||
views::ImageButton* LinuxFrameView::InitWindowCaptionButton(
|
||||
int accessibility_string_id,
|
||||
int normal_image_id,
|
||||
int hot_image_id,
|
||||
int pushed_image_id) {
|
||||
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
views::ImageButton* button = new views::ImageButton(this);
|
||||
button->SetAccessibleName(l10n_util::GetStringUTF16(accessibility_string_id));
|
||||
button->SetImage(views::CustomButton::STATE_NORMAL,
|
||||
rb.GetImageNamed(normal_image_id).ToImageSkia());
|
||||
button->SetImage(views::CustomButton::STATE_HOVERED,
|
||||
rb.GetImageNamed(hot_image_id).ToImageSkia());
|
||||
button->SetImage(views::CustomButton::STATE_PRESSED,
|
||||
rb.GetImageNamed(pushed_image_id).ToImageSkia());
|
||||
AddChildView(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
} // namespace atom
|
138
atom/browser/ui/views/linux_frame_view.h
Normal file
138
atom/browser/ui/views/linux_frame_view.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_
|
||||
|
||||
#include "atom/browser/ui/views/frameless_view.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/views/controls/button/button.h"
|
||||
#include "ui/views/window/frame_buttons.h"
|
||||
|
||||
namespace gfx {
|
||||
class ImageSkia;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class FrameBackground;
|
||||
class ImageButton;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class LinuxFrameView : public FramelessView,
|
||||
public views::ButtonListener {
|
||||
public:
|
||||
LinuxFrameView();
|
||||
virtual ~LinuxFrameView();
|
||||
|
||||
void Init(NativeWindowViews* window, views::Widget* frame) OVERRIDE;
|
||||
|
||||
// Overridden from NonClientFrameView:
|
||||
virtual gfx::Rect GetBoundsForClientView() const OVERRIDE;
|
||||
virtual gfx::Rect GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const OVERRIDE;
|
||||
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
|
||||
virtual void GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) OVERRIDE;
|
||||
virtual void ResetWindowControls() OVERRIDE;
|
||||
virtual void UpdateWindowIcon() OVERRIDE;
|
||||
virtual void UpdateWindowTitle() OVERRIDE;
|
||||
|
||||
// Overridden from View:
|
||||
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
|
||||
virtual void Layout() OVERRIDE;
|
||||
virtual gfx::Size GetPreferredSize() OVERRIDE;
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE;
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE;
|
||||
|
||||
// Overridden from ButtonListener:
|
||||
virtual void ButtonPressed(views::Button* sender,
|
||||
const ui::Event& event) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Returns the thickness of the border that makes up the window frame edges.
|
||||
// This does not include any client edge.
|
||||
int FrameBorderThickness() const;
|
||||
|
||||
// Returns the thickness of the entire nonclient left, right, and bottom
|
||||
// borders, including both the window frame and any client edge.
|
||||
int NonClientBorderThickness() const;
|
||||
|
||||
// Returns the height of the entire nonclient top border, including the window
|
||||
// frame, any title area, and any connected client edge.
|
||||
int NonClientTopBorderHeight() const;
|
||||
|
||||
// Returns the y-coordinate of the caption buttons.
|
||||
int CaptionButtonY() const;
|
||||
|
||||
// Returns the thickness of the nonclient portion of the 3D edge along the
|
||||
// bottom of the titlebar.
|
||||
int TitlebarBottomThickness() const;
|
||||
|
||||
// Returns the size of the titlebar icon. This is used even when the icon is
|
||||
// not shown, e.g. to set the titlebar height.
|
||||
int IconSize() const;
|
||||
|
||||
// Returns the bounds of the titlebar icon (or where the icon would be if
|
||||
// there was one).
|
||||
gfx::Rect IconBounds() const;
|
||||
|
||||
// Returns true if the title bar, caption buttons, and frame border should be
|
||||
// drawn. If false, the client view occupies the full area of this view.
|
||||
bool ShouldShowTitleBarAndBorder() const;
|
||||
|
||||
// Returns true if the client edge should be drawn. This is true if
|
||||
// the window is not maximized.
|
||||
bool ShouldShowClientEdge() const;
|
||||
|
||||
// Paint various sub-components of this view.
|
||||
void PaintRestoredFrameBorder(gfx::Canvas* canvas);
|
||||
void PaintMaximizedFrameBorder(gfx::Canvas* canvas);
|
||||
void PaintTitleBar(gfx::Canvas* canvas);
|
||||
void PaintRestoredClientEdge(gfx::Canvas* canvas);
|
||||
|
||||
// Compute aspects of the frame needed to paint the frame background.
|
||||
SkColor GetFrameColor() const;
|
||||
const gfx::ImageSkia* GetFrameImage() const;
|
||||
|
||||
// Layout various sub-components of this view.
|
||||
void LayoutWindowControls();
|
||||
void LayoutTitleBar();
|
||||
void LayoutClientView();
|
||||
|
||||
// Creates, adds and returns a new window caption button (e.g, minimize,
|
||||
// maximize, restore).
|
||||
views::ImageButton* InitWindowCaptionButton(int accessibility_string_id,
|
||||
int normal_image_id,
|
||||
int hot_image_id,
|
||||
int pushed_image_id);
|
||||
|
||||
// The bounds of the client view, in this view's coordinates.
|
||||
gfx::Rect client_view_bounds_;
|
||||
|
||||
// The layout rect of the title, if visible.
|
||||
gfx::Rect title_bounds_;
|
||||
|
||||
// The icon of this window. May be NULL.
|
||||
views::ImageButton* window_icon_;
|
||||
|
||||
// Window caption buttons.
|
||||
views::ImageButton* minimize_button_;
|
||||
views::ImageButton* maximize_button_;
|
||||
views::ImageButton* restore_button_;
|
||||
views::ImageButton* close_button_;
|
||||
|
||||
// Should maximize button be shown?
|
||||
bool should_show_maximize_button_;
|
||||
|
||||
// Background painter for the window frame.
|
||||
scoped_ptr<views::FrameBackground> frame_background_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LinuxFrameView);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_
|
95
atom/browser/ui/views/menu_bar.cc
Normal file
95
atom/browser/ui/views/menu_bar.cc
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
|
||||
#include "atom/browser/ui/views/menu_delegate.h"
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/controls/button/menu_button.h"
|
||||
#include "ui/views/layout/box_layout.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kViewClassName[] = "AtomMenuBar";
|
||||
|
||||
// Default color of the menu bar.
|
||||
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);
|
||||
|
||||
} // namespace
|
||||
|
||||
MenuBar::MenuBar()
|
||||
: menu_model_(NULL) {
|
||||
set_background(views::Background::CreateSolidBackground(kDefaultColor));
|
||||
SetLayoutManager(new views::BoxLayout(
|
||||
views::BoxLayout::kHorizontal, 0, 0, 0));
|
||||
}
|
||||
|
||||
MenuBar::~MenuBar() {
|
||||
}
|
||||
|
||||
void MenuBar::SetMenu(ui::MenuModel* model) {
|
||||
menu_model_ = model;
|
||||
RemoveAllChildViews(true);
|
||||
|
||||
for (int i = 0; i < model->GetItemCount(); ++i) {
|
||||
views::MenuButton* button =
|
||||
new views::MenuButton(this, model->GetLabelAt(i), this, false);
|
||||
button->set_tag(i);
|
||||
AddChildView(button);
|
||||
}
|
||||
}
|
||||
|
||||
int MenuBar::GetItemCount() const {
|
||||
return menu_model_->GetItemCount();
|
||||
}
|
||||
|
||||
bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
|
||||
ui::MenuModel** menu_model,
|
||||
views::MenuButton** button) {
|
||||
gfx::Point location(point);
|
||||
views::View::ConvertPointFromScreen(this, &location);
|
||||
|
||||
if (location.x() < 0 || location.x() >= width() || location.y() < 0 ||
|
||||
location.y() >= height())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < child_count(); ++i) {
|
||||
views::View* view = child_at(i);
|
||||
if (view->bounds().Contains(location) &&
|
||||
(menu_model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) {
|
||||
*menu_model = menu_model_->GetSubmenuModelAt(i);
|
||||
*button = static_cast<views::MenuButton*>(view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* MenuBar::GetClassName() const {
|
||||
return kViewClassName;
|
||||
}
|
||||
|
||||
void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) {
|
||||
}
|
||||
|
||||
void MenuBar::OnMenuButtonClicked(views::View* source,
|
||||
const gfx::Point& point) {
|
||||
if (!menu_model_)
|
||||
return;
|
||||
|
||||
views::MenuButton* button = static_cast<views::MenuButton*>(source);
|
||||
int id = button->tag();
|
||||
ui::MenuModel::ItemType type = menu_model_->GetTypeAt(id);
|
||||
if (type != ui::MenuModel::TYPE_SUBMENU)
|
||||
return;
|
||||
|
||||
menu_delegate_.reset(new MenuDelegate(this));
|
||||
menu_delegate_->RunMenu(menu_model_->GetSubmenuModelAt(id), button);
|
||||
}
|
||||
|
||||
} // namespace atom
|
63
atom/browser/ui/views/menu_bar.h
Normal file
63
atom/browser/ui/views/menu_bar.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_
|
||||
|
||||
#include "ui/views/controls/button/button.h"
|
||||
#include "ui/views/controls/button/menu_button_listener.h"
|
||||
#include "ui/views/view.h"
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class MenuButton;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class MenuDelegate;
|
||||
|
||||
class MenuBar : public views::View,
|
||||
public views::ButtonListener,
|
||||
public views::MenuButtonListener {
|
||||
public:
|
||||
MenuBar();
|
||||
virtual ~MenuBar();
|
||||
|
||||
// Replaces current menu with a new one.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
|
||||
// Returns there are how many items in the root menu.
|
||||
int GetItemCount() const;
|
||||
|
||||
// Get the menu under specified screen point.
|
||||
bool GetMenuButtonFromScreenPoint(const gfx::Point& point,
|
||||
ui::MenuModel** menu_model,
|
||||
views::MenuButton** button);
|
||||
|
||||
protected:
|
||||
// views::View:
|
||||
virtual const char* GetClassName() const OVERRIDE;
|
||||
|
||||
// views::ButtonListener:
|
||||
virtual void ButtonPressed(views::Button* sender,
|
||||
const ui::Event& event) OVERRIDE;
|
||||
|
||||
// views::MenuButtonListener:
|
||||
virtual void OnMenuButtonClicked(views::View* source,
|
||||
const gfx::Point& point) OVERRIDE;
|
||||
|
||||
private:
|
||||
ui::MenuModel* menu_model_;
|
||||
scoped_ptr<MenuDelegate> menu_delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuBar);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_
|
124
atom/browser/ui/views/menu_delegate.cc
Normal file
124
atom/browser/ui/views/menu_delegate.cc
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/menu_delegate.h"
|
||||
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "ui/views/controls/button/menu_button.h"
|
||||
#include "ui/views/controls/menu/menu_model_adapter.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
MenuDelegate::MenuDelegate(MenuBar* menu_bar)
|
||||
: menu_bar_(menu_bar),
|
||||
id_(-1),
|
||||
items_(menu_bar_->GetItemCount()),
|
||||
delegates_(menu_bar_->GetItemCount()) {
|
||||
}
|
||||
|
||||
MenuDelegate::~MenuDelegate() {
|
||||
STLDeleteElements(&delegates_);
|
||||
}
|
||||
|
||||
void MenuDelegate::RunMenu(ui::MenuModel* model, views::MenuButton* button) {
|
||||
gfx::Point screen_loc;
|
||||
views::View::ConvertPointToScreen(button, &screen_loc);
|
||||
// Subtract 1 from the height to make the popup flush with the button border.
|
||||
gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(),
|
||||
button->height() - 1);
|
||||
|
||||
id_ = button->tag();
|
||||
views::MenuItemView* item = BuildMenu(model);
|
||||
|
||||
views::MenuRunner menu_runner(item);
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
button->GetWidget()->GetTopLevelWidget(),
|
||||
button,
|
||||
bounds,
|
||||
views::MenuItemView::TOPRIGHT,
|
||||
ui::MENU_SOURCE_MOUSE,
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
|
||||
}
|
||||
|
||||
views::MenuItemView* MenuDelegate::BuildMenu(ui::MenuModel* model) {
|
||||
DCHECK_GE(id_, 0);
|
||||
|
||||
if (!items_[id_]) {
|
||||
views::MenuModelAdapter* delegate = new views::MenuModelAdapter(model);
|
||||
delegates_[id_] = delegate;
|
||||
|
||||
views::MenuItemView* item = new views::MenuItemView(this);
|
||||
delegate->BuildMenu(item);
|
||||
items_[id_] = item;
|
||||
}
|
||||
|
||||
return items_[id_];
|
||||
}
|
||||
|
||||
void MenuDelegate::ExecuteCommand(int id) {
|
||||
delegate()->ExecuteCommand(id);
|
||||
}
|
||||
|
||||
void MenuDelegate::ExecuteCommand(int id, int mouse_event_flags) {
|
||||
delegate()->ExecuteCommand(id, mouse_event_flags);
|
||||
}
|
||||
|
||||
bool MenuDelegate::IsTriggerableEvent(views::MenuItemView* source,
|
||||
const ui::Event& e) {
|
||||
return delegate()->IsTriggerableEvent(source, e);
|
||||
}
|
||||
|
||||
bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) {
|
||||
return delegate()->GetAccelerator(id, accelerator);
|
||||
}
|
||||
|
||||
base::string16 MenuDelegate::GetLabel(int id) const {
|
||||
return delegate()->GetLabel(id);
|
||||
}
|
||||
|
||||
const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const {
|
||||
return delegate()->GetLabelFontList(id);
|
||||
}
|
||||
|
||||
bool MenuDelegate::IsCommandEnabled(int id) const {
|
||||
return delegate()->IsCommandEnabled(id);
|
||||
}
|
||||
|
||||
bool MenuDelegate::IsItemChecked(int id) const {
|
||||
return delegate()->IsItemChecked(id);
|
||||
}
|
||||
|
||||
void MenuDelegate::SelectionChanged(views::MenuItemView* menu) {
|
||||
delegate()->SelectionChanged(menu);
|
||||
}
|
||||
|
||||
void MenuDelegate::WillShowMenu(views::MenuItemView* menu) {
|
||||
delegate()->WillShowMenu(menu);
|
||||
}
|
||||
|
||||
void MenuDelegate::WillHideMenu(views::MenuItemView* menu) {
|
||||
delegate()->WillHideMenu(menu);
|
||||
}
|
||||
|
||||
views::MenuItemView* MenuDelegate::GetSiblingMenu(
|
||||
views::MenuItemView* menu,
|
||||
const gfx::Point& screen_point,
|
||||
views::MenuItemView::AnchorPosition* anchor,
|
||||
bool* has_mnemonics,
|
||||
views::MenuButton** button) {
|
||||
ui::MenuModel* model;
|
||||
if (!menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, button))
|
||||
return NULL;
|
||||
|
||||
*anchor = views::MenuItemView::TOPLEFT;
|
||||
*has_mnemonics = true;
|
||||
|
||||
id_ = (*button)->tag();
|
||||
return BuildMenu(model);
|
||||
}
|
||||
|
||||
} // namespace atom
|
74
atom/browser/ui/views/menu_delegate.h
Normal file
74
atom/browser/ui/views/menu_delegate.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ui/views/controls/menu/menu_delegate.h"
|
||||
|
||||
namespace views {
|
||||
class MenuModelAdapter;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class MenuBar;
|
||||
|
||||
class MenuDelegate : public views::MenuDelegate {
|
||||
public:
|
||||
explicit MenuDelegate(MenuBar* menu_bar);
|
||||
virtual ~MenuDelegate();
|
||||
|
||||
void RunMenu(ui::MenuModel* model, views::MenuButton* button);
|
||||
|
||||
protected:
|
||||
// views::MenuDelegate:
|
||||
virtual void ExecuteCommand(int id) OVERRIDE;
|
||||
virtual void ExecuteCommand(int id, int mouse_event_flags) OVERRIDE;
|
||||
virtual bool IsTriggerableEvent(views::MenuItemView* source,
|
||||
const ui::Event& e) OVERRIDE;
|
||||
virtual bool GetAccelerator(int id,
|
||||
ui::Accelerator* accelerator) OVERRIDE;
|
||||
virtual base::string16 GetLabel(int id) const OVERRIDE;
|
||||
virtual const gfx::FontList* GetLabelFontList(int id) const OVERRIDE;
|
||||
virtual bool IsCommandEnabled(int id) const OVERRIDE;
|
||||
virtual bool IsItemChecked(int id) const OVERRIDE;
|
||||
virtual void SelectionChanged(views::MenuItemView* menu) OVERRIDE;
|
||||
virtual void WillShowMenu(views::MenuItemView* menu) OVERRIDE;
|
||||
virtual void WillHideMenu(views::MenuItemView* menu) OVERRIDE;
|
||||
virtual views::MenuItemView* GetSiblingMenu(
|
||||
views::MenuItemView* menu,
|
||||
const gfx::Point& screen_point,
|
||||
views::MenuItemView::AnchorPosition* anchor,
|
||||
bool* has_mnemonics,
|
||||
views::MenuButton** button);
|
||||
|
||||
private:
|
||||
// Gets the cached menu item view from the model.
|
||||
views::MenuItemView* BuildMenu(ui::MenuModel* model);
|
||||
|
||||
// Returns delegate for current item.
|
||||
views::MenuDelegate* delegate() const { return delegates_[id_]; }
|
||||
|
||||
MenuBar* menu_bar_;
|
||||
|
||||
// Current item's id.
|
||||
int id_;
|
||||
// Cached menu items, managed by MenuRunner.
|
||||
std::vector<views::MenuItemView*> items_;
|
||||
// Cached menu delegates for each menu item, managed by us.
|
||||
std::vector<views::MenuDelegate*> delegates_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_
|
54
atom/browser/ui/views/menu_layout.cc
Normal file
54
atom/browser/ui/views/menu_layout.cc
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/menu_layout.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
MenuLayout::MenuLayout(int menu_height)
|
||||
: menu_height_(menu_height) {
|
||||
}
|
||||
|
||||
MenuLayout::~MenuLayout() {
|
||||
}
|
||||
|
||||
void MenuLayout::Layout(views::View* host) {
|
||||
if (!HasMenu(host)) {
|
||||
views::FillLayout::Layout(host);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::Size size = host->GetContentsBounds().size();
|
||||
gfx::Rect menu_Bar_bounds = gfx::Rect(0, 0, size.width(), menu_height_);
|
||||
gfx::Rect web_view_bounds = gfx::Rect(
|
||||
0, menu_height_, size.width(), size.height() - menu_height_);
|
||||
|
||||
views::View* menu_bar = host->child_at(0);
|
||||
views::View* web_view = host->child_at(1);
|
||||
menu_bar->SetBoundsRect(menu_Bar_bounds);
|
||||
web_view->SetBoundsRect(web_view_bounds);
|
||||
}
|
||||
|
||||
gfx::Size MenuLayout::GetPreferredSize(views::View* host) {
|
||||
gfx::Size size = views::FillLayout::GetPreferredSize(host);
|
||||
if (!HasMenu(host))
|
||||
return size;
|
||||
|
||||
size.set_height(size.height() + menu_height_);
|
||||
return size;
|
||||
}
|
||||
|
||||
int MenuLayout::GetPreferredHeightForWidth(views::View* host, int width) {
|
||||
int height = views::FillLayout::GetPreferredHeightForWidth(host, width);
|
||||
if (!HasMenu(host))
|
||||
return height;
|
||||
|
||||
return height + menu_height_;
|
||||
}
|
||||
|
||||
bool MenuLayout::HasMenu(const views::View* host) const {
|
||||
return host->child_count() == 2;
|
||||
}
|
||||
|
||||
} // namespace atom
|
32
atom/browser/ui/views/menu_layout.h
Normal file
32
atom/browser/ui/views/menu_layout.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_
|
||||
|
||||
#include "ui/views/layout/fill_layout.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class MenuLayout : public views::FillLayout {
|
||||
public:
|
||||
explicit MenuLayout(int menu_height);
|
||||
virtual ~MenuLayout();
|
||||
|
||||
// views::LayoutManager:
|
||||
virtual void Layout(views::View* host) OVERRIDE;
|
||||
virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE;
|
||||
virtual int GetPreferredHeightForWidth(views::View* host, int width) OVERRIDE;
|
||||
|
||||
private:
|
||||
bool HasMenu(const views::View* host) const;
|
||||
|
||||
int menu_height_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuLayout);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_
|
64
atom/browser/ui/views/win_frame_view.cc
Normal file
64
atom/browser/ui/views/win_frame_view.cc
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/win/hwnd_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kViewClassName[] = "WinFrameView";
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
WinFrameView::WinFrameView() {
|
||||
}
|
||||
|
||||
WinFrameView::~WinFrameView() {
|
||||
}
|
||||
|
||||
|
||||
gfx::Rect WinFrameView::GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const {
|
||||
gfx::Size size(client_bounds.size());
|
||||
ClientAreaSizeToWindowSize(&size);
|
||||
return gfx::Rect(client_bounds.origin(), size);
|
||||
}
|
||||
|
||||
int WinFrameView::NonClientHitTest(const gfx::Point& point) {
|
||||
if (window_->has_frame())
|
||||
return frame_->client_view()->NonClientHitTest(point);
|
||||
else
|
||||
return FramelessView::NonClientHitTest(point);
|
||||
}
|
||||
|
||||
gfx::Size WinFrameView::GetMinimumSize() {
|
||||
gfx::Size size = FramelessView::GetMinimumSize();
|
||||
return gfx::win::DIPToScreenSize(size);
|
||||
}
|
||||
|
||||
gfx::Size WinFrameView::GetMaximumSize() {
|
||||
gfx::Size size = FramelessView::GetMaximumSize();
|
||||
return gfx::win::DIPToScreenSize(size);
|
||||
}
|
||||
|
||||
const char* WinFrameView::GetClassName() const {
|
||||
return kViewClassName;
|
||||
}
|
||||
|
||||
void WinFrameView::ClientAreaSizeToWindowSize(gfx::Size* size) const {
|
||||
// AdjustWindowRect seems to return a wrong window size.
|
||||
gfx::Size window = frame_->GetWindowBoundsInScreen().size();
|
||||
gfx::Size client = frame_->GetClientAreaBoundsInScreen().size();
|
||||
size->set_width(size->width() + window.width() - client.width());
|
||||
size->set_height(size->height() + window.height() - client.height());
|
||||
}
|
||||
|
||||
} // namespace atom
|
35
atom/browser/ui/views/win_frame_view.h
Normal file
35
atom/browser/ui/views/win_frame_view.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_
|
||||
|
||||
#include "atom/browser/ui/views/frameless_view.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class WinFrameView : public FramelessView {
|
||||
public:
|
||||
WinFrameView();
|
||||
virtual ~WinFrameView();
|
||||
|
||||
// views::NonClientFrameView:
|
||||
virtual gfx::Rect GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const OVERRIDE;
|
||||
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
|
||||
|
||||
// views::View:
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE;
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE;
|
||||
virtual const char* GetClassName() const OVERRIDE;
|
||||
|
||||
private:
|
||||
void ClientAreaSizeToWindowSize(gfx::Size* size) const;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WinFrameView);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_
|
|
@ -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
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_WIN_MENU_2_H_
|
||||
#define ATOM_BROWSER_UI_WIN_MENU_2_H_
|
||||
|
||||
#include "atom/browser/ui/win/native_menu_win.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
namespace gfx {
|
||||
class Point;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
// A menu. Populated from a model, and relies on a delegate to execute commands.
|
||||
//
|
||||
// WARNING: do NOT create and use Menu2 on the stack. Menu2 notifies the model
|
||||
// of selection AFTER a delay. This means that if use a Menu2 on the stack
|
||||
// ActivatedAt is never invoked.
|
||||
class Menu2 {
|
||||
public:
|
||||
// How the menu is aligned relative to the point it is shown at.
|
||||
// The alignment is reversed by menu if text direction is right to left.
|
||||
enum Alignment {
|
||||
ALIGN_TOPLEFT,
|
||||
ALIGN_TOPRIGHT
|
||||
};
|
||||
|
||||
// Creates a new menu populated with the contents of |model|.
|
||||
// WARNING: this populates the menu on construction by invoking methods on
|
||||
// the model. As such, it is typically not safe to use this as the model
|
||||
// from the constructor. EG:
|
||||
// MyClass : menu_(this) {}
|
||||
// is likely to have problems.
|
||||
explicit Menu2(ui::MenuModel* model, bool as_window_menu = false);
|
||||
virtual ~Menu2();
|
||||
|
||||
// Runs the menu at the specified point. This method blocks until done.
|
||||
// RunContextMenuAt is the same, but the alignment is the default for a
|
||||
// context menu.
|
||||
void RunMenuAt(const gfx::Point& point, Alignment alignment);
|
||||
void RunContextMenuAt(const gfx::Point& point);
|
||||
|
||||
// Cancels the active menu.
|
||||
void CancelMenu();
|
||||
|
||||
// Called when the model supplying data to this menu has changed, and the menu
|
||||
// must be rebuilt.
|
||||
void Rebuild();
|
||||
|
||||
// Called when the states of the menu items in the menu should be refreshed
|
||||
// from the model.
|
||||
void UpdateStates();
|
||||
|
||||
// For submenus.
|
||||
HMENU GetNativeMenu() const;
|
||||
|
||||
// Get the result of the last call to RunMenuAt to determine whether an
|
||||
// item was selected, the user navigated to a next or previous menu, or
|
||||
// nothing.
|
||||
NativeMenuWin::MenuAction GetMenuAction() const;
|
||||
|
||||
// Add a listener to receive a callback when the menu opens.
|
||||
void AddMenuListener(views::MenuListener* listener);
|
||||
|
||||
// Remove a menu listener.
|
||||
void RemoveMenuListener(views::MenuListener* listener);
|
||||
|
||||
// Accessors.
|
||||
ui::MenuModel* model() const { return model_; }
|
||||
NativeMenuWin* wrapper() const { return wrapper_.get(); }
|
||||
|
||||
// Sets the minimum width of the menu.
|
||||
void SetMinimumWidth(int width);
|
||||
|
||||
private:
|
||||
ui::MenuModel* model_;
|
||||
|
||||
// The object that actually implements the menu.
|
||||
scoped_ptr<NativeMenuWin> wrapper_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Menu2);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_WIN_MENU_2_H_
|
|
@ -1,765 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/win/native_menu_win.h"
|
||||
|
||||
#include <Windowsx.h>
|
||||
|
||||
#include "atom/browser/ui/win/menu_2.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/win/wrapped_window_proc.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/l10n/l10n_util_win.h"
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "ui/gfx/font.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
#include "ui/native_theme/native_theme.h"
|
||||
#include "ui/native_theme/native_theme_win.h"
|
||||
#include "ui/views/controls/menu/menu_config.h"
|
||||
#include "ui/views/controls/menu/menu_insertion_delegate_win.h"
|
||||
#include "ui/views/controls/menu/menu_listener.h"
|
||||
|
||||
using ui::NativeTheme;
|
||||
|
||||
// Really bad hack here, renaming all class names would be too much work.
|
||||
using namespace views; // NOLINT
|
||||
|
||||
namespace atom {
|
||||
|
||||
// The width of an icon, including the pixels between the icon and
|
||||
// the item label.
|
||||
static const int kIconWidth = 23;
|
||||
// Margins between the top of the item and the label.
|
||||
static const int kItemTopMargin = 3;
|
||||
// Margins between the bottom of the item and the label.
|
||||
static const int kItemBottomMargin = 4;
|
||||
// Margins between the left of the item and the icon.
|
||||
static const int kItemLeftMargin = 4;
|
||||
// Margins between the right of the item and the label.
|
||||
static const int kItemRightMargin = 10;
|
||||
// The width for displaying the sub-menu arrow.
|
||||
static const int kArrowWidth = 10;
|
||||
|
||||
struct NativeMenuWin::ItemData {
|
||||
// The Windows API requires that whoever creates the menus must own the
|
||||
// strings used for labels, and keep them around for the lifetime of the
|
||||
// created menu. So be it.
|
||||
string16 label;
|
||||
|
||||
// Someone needs to own submenus, it may as well be us.
|
||||
scoped_ptr<Menu2> submenu;
|
||||
|
||||
// We need a pointer back to the containing menu in various circumstances.
|
||||
NativeMenuWin* native_menu_win;
|
||||
|
||||
// The index of the item within the menu's model.
|
||||
int model_index;
|
||||
};
|
||||
|
||||
// Returns the NativeMenuWin for a particular HMENU.
|
||||
static NativeMenuWin* GetNativeMenuWinFromHMENU(HMENU hmenu) {
|
||||
MENUINFO mi = {0};
|
||||
mi.cbSize = sizeof(mi);
|
||||
mi.fMask = MIM_MENUDATA | MIM_STYLE;
|
||||
GetMenuInfo(hmenu, &mi);
|
||||
return reinterpret_cast<NativeMenuWin*>(mi.dwMenuData);
|
||||
}
|
||||
|
||||
// A window that receives messages from Windows relevant to the native menu
|
||||
// structure we have constructed in NativeMenuWin.
|
||||
class NativeMenuWin::MenuHostWindow {
|
||||
public:
|
||||
explicit MenuHostWindow(NativeMenuWin* parent) : parent_(parent) {
|
||||
RegisterClass();
|
||||
hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
|
||||
L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
gfx::CheckWindowCreated(hwnd_);
|
||||
gfx::SetWindowUserData(hwnd_, this);
|
||||
}
|
||||
|
||||
~MenuHostWindow() {
|
||||
DestroyWindow(hwnd_);
|
||||
}
|
||||
|
||||
// Called when the user selects a specific item.
|
||||
void OnMenuCommand(int position, HMENU menu) {
|
||||
NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
|
||||
ui::MenuModel* model = menu_win->model_;
|
||||
NativeMenuWin* root_menu = menu_win;
|
||||
while (root_menu->parent_)
|
||||
root_menu = root_menu->parent_;
|
||||
|
||||
// Only notify the model if it didn't already send out notification.
|
||||
// See comment in MenuMessageHook for details.
|
||||
if (root_menu->menu_action_ == MENU_ACTION_NONE)
|
||||
model->ActivatedAt(position);
|
||||
}
|
||||
|
||||
HWND hwnd() const { return hwnd_; }
|
||||
|
||||
private:
|
||||
static const wchar_t* kWindowClassName;
|
||||
|
||||
void RegisterClass() {
|
||||
static bool registered = false;
|
||||
if (registered)
|
||||
return;
|
||||
|
||||
WNDCLASSEX window_class;
|
||||
base::win::InitializeWindowClass(
|
||||
kWindowClassName,
|
||||
&base::win::WrappedWindowProc<MenuHostWindowProc>,
|
||||
CS_DBLCLKS,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&window_class);
|
||||
ATOM clazz = RegisterClassEx(&window_class);
|
||||
CHECK(clazz);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
// Converts the WPARAM value passed to WM_MENUSELECT into an index
|
||||
// corresponding to the menu item that was selected.
|
||||
int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const {
|
||||
int count = GetMenuItemCount(menu);
|
||||
// For normal command menu items, Windows passes a command id as the LOWORD
|
||||
// of WPARAM for WM_MENUSELECT. We need to walk forward through the menu
|
||||
// items to find an item with a matching ID. Ugh!
|
||||
for (int i = 0; i < count; ++i) {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_ID;
|
||||
GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii);
|
||||
if (mii.wID == w_param)
|
||||
return i;
|
||||
}
|
||||
// If we didn't find a matching command ID, this means a submenu has been
|
||||
// selected instead, and rather than passing a command ID in
|
||||
// LOWORD(w_param), Windows has actually passed us a position, so we just
|
||||
// return it.
|
||||
return w_param;
|
||||
}
|
||||
|
||||
NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) {
|
||||
return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
|
||||
}
|
||||
|
||||
// Called as the user moves their mouse or arrows through the contents of the
|
||||
// menu.
|
||||
void OnMenuSelect(WPARAM w_param, HMENU menu) {
|
||||
if (!menu)
|
||||
return; // menu is null when closing on XP.
|
||||
|
||||
int position = GetMenuItemIndexFromWPARAM(menu, w_param);
|
||||
if (position >= 0)
|
||||
GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
|
||||
}
|
||||
|
||||
// Called by Windows to measure the size of an owner-drawn menu item.
|
||||
void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
|
||||
NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
|
||||
if (data) {
|
||||
gfx::Font font;
|
||||
measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
|
||||
kIconWidth + kItemLeftMargin + kItemRightMargin -
|
||||
GetSystemMetrics(SM_CXMENUCHECK);
|
||||
if (data->submenu.get())
|
||||
measure_item_struct->itemWidth += kArrowWidth;
|
||||
// If the label contains an accelerator, make room for tab.
|
||||
if (data->label.find(L'\t') != string16::npos)
|
||||
measure_item_struct->itemWidth += font.GetStringWidth(L" ");
|
||||
measure_item_struct->itemHeight =
|
||||
font.GetHeight() + kItemBottomMargin + kItemTopMargin;
|
||||
} else {
|
||||
// Measure separator size.
|
||||
measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
|
||||
measure_item_struct->itemWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Windows to paint an owner-drawn menu item.
|
||||
void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
|
||||
HDC dc = draw_item_struct->hDC;
|
||||
COLORREF prev_bg_color, prev_text_color;
|
||||
|
||||
// Set background color and text color
|
||||
if (draw_item_struct->itemState & ODS_SELECTED) {
|
||||
prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
|
||||
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
} else {
|
||||
prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
|
||||
if (draw_item_struct->itemState & ODS_DISABLED)
|
||||
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
|
||||
else
|
||||
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
|
||||
}
|
||||
|
||||
if (draw_item_struct->itemData) {
|
||||
NativeMenuWin::ItemData* data = GetItemData(draw_item_struct->itemData);
|
||||
// Draw the background.
|
||||
HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
|
||||
FillRect(dc, &draw_item_struct->rcItem, hbr);
|
||||
DeleteObject(hbr);
|
||||
|
||||
// Draw the label.
|
||||
RECT rect = draw_item_struct->rcItem;
|
||||
rect.top += kItemTopMargin;
|
||||
// Should we add kIconWidth only when icon.width() != 0 ?
|
||||
rect.left += kItemLeftMargin + kIconWidth;
|
||||
rect.right -= kItemRightMargin;
|
||||
UINT format = DT_TOP | DT_SINGLELINE;
|
||||
// Check whether the mnemonics should be underlined.
|
||||
BOOL underline_mnemonics;
|
||||
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
|
||||
if (!underline_mnemonics)
|
||||
format |= DT_HIDEPREFIX;
|
||||
gfx::Font font;
|
||||
HGDIOBJ old_font =
|
||||
static_cast<HFONT>(SelectObject(dc, font.GetNativeFont()));
|
||||
|
||||
// If an accelerator is specified (with a tab delimiting the rest of the
|
||||
// label from the accelerator), we have to justify the fist part on the
|
||||
// left and the accelerator on the right.
|
||||
// TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
|
||||
// window system UI font and will not hit here.
|
||||
string16 label = data->label;
|
||||
string16 accel;
|
||||
string16::size_type tab_pos = label.find(L'\t');
|
||||
if (tab_pos != string16::npos) {
|
||||
accel = label.substr(tab_pos);
|
||||
label = label.substr(0, tab_pos);
|
||||
}
|
||||
DrawTextEx(dc, const_cast<wchar_t*>(label.data()),
|
||||
static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
|
||||
if (!accel.empty())
|
||||
DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
|
||||
static_cast<int>(accel.size()), &rect,
|
||||
format | DT_RIGHT, NULL);
|
||||
SelectObject(dc, old_font);
|
||||
|
||||
ui::MenuModel::ItemType type =
|
||||
data->native_menu_win->model_->GetTypeAt(data->model_index);
|
||||
|
||||
// Draw the icon after the label, otherwise it would be covered
|
||||
// by the label.
|
||||
gfx::Image icon;
|
||||
if (data->native_menu_win->model_->GetIconAt(data->model_index, &icon)) {
|
||||
// We currently don't support items with both icons and checkboxes.
|
||||
const gfx::ImageSkia* skia_icon = icon.ToImageSkia();
|
||||
DCHECK(type != ui::MenuModel::TYPE_CHECK);
|
||||
gfx::Canvas canvas(
|
||||
skia_icon->GetRepresentation(ui::SCALE_FACTOR_100P),
|
||||
false);
|
||||
skia::DrawToNativeContext(
|
||||
canvas.sk_canvas(), dc,
|
||||
draw_item_struct->rcItem.left + kItemLeftMargin,
|
||||
draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
|
||||
draw_item_struct->rcItem.top - skia_icon->height()) / 2, NULL);
|
||||
} else if (type == ui::MenuModel::TYPE_CHECK &&
|
||||
data->native_menu_win->model_->IsItemCheckedAt(
|
||||
data->model_index)) {
|
||||
// Manually render a checkbox.
|
||||
ui::NativeThemeWin* native_theme = ui::NativeThemeWin::instance();
|
||||
const MenuConfig& config = MenuConfig::instance(native_theme);
|
||||
NativeTheme::State state;
|
||||
if (draw_item_struct->itemState & ODS_DISABLED) {
|
||||
state = NativeTheme::kDisabled;
|
||||
} else {
|
||||
state = draw_item_struct->itemState & ODS_SELECTED ?
|
||||
NativeTheme::kHovered : NativeTheme::kNormal;
|
||||
}
|
||||
int height =
|
||||
draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top;
|
||||
int icon_y = kItemTopMargin +
|
||||
(height - kItemTopMargin - kItemBottomMargin -
|
||||
config.check_height) / 2;
|
||||
gfx::Canvas canvas(gfx::Size(config.check_width, config.check_height),
|
||||
ui::SCALE_FACTOR_100P,
|
||||
false);
|
||||
NativeTheme::ExtraParams extra;
|
||||
extra.menu_check.is_radio = false;
|
||||
gfx::Rect bounds(0, 0, config.check_width, config.check_height);
|
||||
|
||||
// Draw the background and the check.
|
||||
native_theme->Paint(
|
||||
canvas.sk_canvas(), NativeTheme::kMenuCheckBackground,
|
||||
state, bounds, extra);
|
||||
native_theme->Paint(
|
||||
canvas.sk_canvas(), NativeTheme::kMenuCheck, state, bounds, extra);
|
||||
|
||||
// Draw checkbox to menu.
|
||||
skia::DrawToNativeContext(canvas.sk_canvas(), dc,
|
||||
draw_item_struct->rcItem.left + kItemLeftMargin,
|
||||
draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
|
||||
draw_item_struct->rcItem.top - config.check_height) / 2, NULL);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Draw the separator
|
||||
draw_item_struct->rcItem.top +=
|
||||
(draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
|
||||
DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
|
||||
}
|
||||
|
||||
SetBkColor(dc, prev_bg_color);
|
||||
SetTextColor(dc, prev_text_color);
|
||||
}
|
||||
|
||||
bool ProcessWindowMessage(HWND window,
|
||||
UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param,
|
||||
LRESULT* l_result) {
|
||||
switch (message) {
|
||||
case WM_MENUCOMMAND:
|
||||
OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
case WM_MENUSELECT:
|
||||
OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
case WM_MEASUREITEM:
|
||||
OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
case WM_DRAWITEM:
|
||||
OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
// TODO(beng): bring over owner draw from old menu system.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK MenuHostWindowProc(HWND window,
|
||||
UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param) {
|
||||
MenuHostWindow* host =
|
||||
reinterpret_cast<MenuHostWindow*>(gfx::GetWindowUserData(window));
|
||||
// host is null during initial construction.
|
||||
LRESULT l_result = 0;
|
||||
if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param,
|
||||
&l_result)) {
|
||||
return DefWindowProc(window, message, w_param, l_param);
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
HWND hwnd_;
|
||||
NativeMenuWin* parent_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
|
||||
};
|
||||
|
||||
struct NativeMenuWin::HighlightedMenuItemInfo {
|
||||
HighlightedMenuItemInfo()
|
||||
: has_parent(false),
|
||||
has_submenu(false),
|
||||
menu(NULL),
|
||||
position(-1) {
|
||||
}
|
||||
|
||||
bool has_parent;
|
||||
bool has_submenu;
|
||||
|
||||
// The menu and position. These are only set for non-disabled menu items.
|
||||
NativeMenuWin* menu;
|
||||
int position;
|
||||
};
|
||||
|
||||
// static
|
||||
const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName =
|
||||
L"ViewsMenuHostWindow";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, public:
|
||||
|
||||
NativeMenuWin::NativeMenuWin(ui::MenuModel* model, HWND system_menu_for)
|
||||
: model_(model),
|
||||
menu_(NULL),
|
||||
owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL) &&
|
||||
!system_menu_for),
|
||||
system_menu_for_(system_menu_for),
|
||||
first_item_index_(0),
|
||||
menu_action_(MENU_ACTION_NONE),
|
||||
menu_to_select_(NULL),
|
||||
position_to_select_(-1),
|
||||
menu_to_select_factory_(this),
|
||||
parent_(NULL),
|
||||
destroyed_flag_(NULL),
|
||||
create_as_window_menu_(false) {
|
||||
}
|
||||
|
||||
NativeMenuWin::~NativeMenuWin() {
|
||||
if (destroyed_flag_)
|
||||
*destroyed_flag_ = true;
|
||||
STLDeleteContainerPointers(items_.begin(), items_.end());
|
||||
DestroyMenu(menu_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, MenuWrapper implementation:
|
||||
|
||||
void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
|
||||
CreateHostWindow();
|
||||
UpdateStates();
|
||||
UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RECURSE;
|
||||
flags |= GetAlignmentFlags(alignment);
|
||||
menu_action_ = MENU_ACTION_NONE;
|
||||
|
||||
// Set a hook function so we can listen for keyboard events while the
|
||||
// menu is open, and store a pointer to this object in a static
|
||||
// variable so the hook has access to it (ugly, but it's the
|
||||
// only way).
|
||||
open_native_menu_win_ = this;
|
||||
HHOOK hhook = SetWindowsHookEx(WH_MSGFILTER, MenuMessageHook,
|
||||
GetModuleHandle(NULL), ::GetCurrentThreadId());
|
||||
|
||||
// Mark that any registered listeners have not been called for this particular
|
||||
// opening of the menu.
|
||||
listeners_called_ = false;
|
||||
|
||||
// Command dispatch is done through WM_MENUCOMMAND, handled by the host
|
||||
// window.
|
||||
HWND hwnd = host_window_->hwnd();
|
||||
menu_to_select_ = NULL;
|
||||
position_to_select_ = -1;
|
||||
menu_to_select_factory_.InvalidateWeakPtrs();
|
||||
bool destroyed = false;
|
||||
destroyed_flag_ = &destroyed;
|
||||
model_->MenuWillShow();
|
||||
TrackPopupMenu(menu_, flags, point.x(), point.y(), 0, host_window_->hwnd(),
|
||||
NULL);
|
||||
UnhookWindowsHookEx(hhook);
|
||||
open_native_menu_win_ = NULL;
|
||||
if (destroyed)
|
||||
return;
|
||||
destroyed_flag_ = NULL;
|
||||
if (menu_to_select_) {
|
||||
// Folks aren't too happy if we notify immediately. In particular, notifying
|
||||
// the delegate can cause destruction leaving the stack in a weird
|
||||
// state. Instead post a task, then notify. This mirrors what WM_MENUCOMMAND
|
||||
// does.
|
||||
menu_to_select_factory_.InvalidateWeakPtrs();
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&NativeMenuWin::DelayedSelect,
|
||||
menu_to_select_factory_.GetWeakPtr()));
|
||||
menu_action_ = MENU_ACTION_SELECTED;
|
||||
}
|
||||
// Send MenuClosed after we schedule the select, otherwise MenuClosed is
|
||||
// processed after the select (MenuClosed posts a delayed task too).
|
||||
model_->MenuClosed();
|
||||
}
|
||||
|
||||
void NativeMenuWin::CancelMenu() {
|
||||
EndMenu();
|
||||
}
|
||||
|
||||
void NativeMenuWin::Rebuild(MenuInsertionDelegateWin* delegate) {
|
||||
ResetNativeMenu();
|
||||
items_.clear();
|
||||
|
||||
owner_draw_ = model_->HasIcons() || owner_draw_;
|
||||
first_item_index_ = delegate ? delegate->GetInsertionIndex(menu_) : 0;
|
||||
for (int menu_index = first_item_index_;
|
||||
menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) {
|
||||
int model_index = menu_index - first_item_index_;
|
||||
if (model_->GetTypeAt(model_index) == ui::MenuModel::TYPE_SEPARATOR)
|
||||
AddSeparatorItemAt(menu_index, model_index);
|
||||
else
|
||||
AddMenuItemAt(menu_index, model_index);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMenuWin::UpdateStates() {
|
||||
// A depth-first walk of the menu items, updating states.
|
||||
int model_index = 0;
|
||||
std::vector<ItemData*>::const_iterator it;
|
||||
for (it = items_.begin(); it != items_.end(); ++it, ++model_index) {
|
||||
int menu_index = model_index + first_item_index_;
|
||||
SetMenuItemState(menu_index, model_->IsEnabledAt(model_index),
|
||||
model_->IsItemCheckedAt(model_index), false);
|
||||
if (model_->IsItemDynamicAt(model_index)) {
|
||||
// TODO(atwilson): Update the icon as well (http://crbug.com/66508).
|
||||
SetMenuItemLabel(menu_index, model_index,
|
||||
model_->GetLabelAt(model_index));
|
||||
}
|
||||
Menu2* submenu = (*it)->submenu.get();
|
||||
if (submenu)
|
||||
submenu->UpdateStates();
|
||||
}
|
||||
}
|
||||
|
||||
HMENU NativeMenuWin::GetNativeMenu() const {
|
||||
return menu_;
|
||||
}
|
||||
|
||||
NativeMenuWin::MenuAction NativeMenuWin::GetMenuAction() const {
|
||||
return menu_action_;
|
||||
}
|
||||
|
||||
void NativeMenuWin::AddMenuListener(MenuListener* listener) {
|
||||
listeners_.AddObserver(listener);
|
||||
}
|
||||
|
||||
void NativeMenuWin::RemoveMenuListener(MenuListener* listener) {
|
||||
listeners_.RemoveObserver(listener);
|
||||
}
|
||||
|
||||
void NativeMenuWin::SetMinimumWidth(int width) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void NativeMenuWin::OnMenuCommand(int position, HMENU menu) {
|
||||
host_window_->OnMenuCommand(position, menu);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, private:
|
||||
|
||||
// static
|
||||
NativeMenuWin* NativeMenuWin::open_native_menu_win_ = NULL;
|
||||
|
||||
void NativeMenuWin::DelayedSelect() {
|
||||
if (menu_to_select_)
|
||||
menu_to_select_->model_->ActivatedAt(position_to_select_);
|
||||
}
|
||||
|
||||
// static
|
||||
bool NativeMenuWin::GetHighlightedMenuItemInfo(
|
||||
HMENU menu,
|
||||
HighlightedMenuItemInfo* info) {
|
||||
for (int i = 0; i < ::GetMenuItemCount(menu); i++) {
|
||||
UINT state = ::GetMenuState(menu, i, MF_BYPOSITION);
|
||||
if (state & MF_HILITE) {
|
||||
if (state & MF_POPUP) {
|
||||
HMENU submenu = GetSubMenu(menu, i);
|
||||
if (GetHighlightedMenuItemInfo(submenu, info))
|
||||
info->has_parent = true;
|
||||
else
|
||||
info->has_submenu = true;
|
||||
} else if (!(state & MF_SEPARATOR) && !(state & MF_DISABLED)) {
|
||||
info->menu = GetNativeMenuWinFromHMENU(menu);
|
||||
info->position = i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK NativeMenuWin::MenuMessageHook(
|
||||
int n_code, WPARAM w_param, LPARAM l_param) {
|
||||
LRESULT result = CallNextHookEx(NULL, n_code, w_param, l_param);
|
||||
|
||||
NativeMenuWin* this_ptr = open_native_menu_win_;
|
||||
if (!this_ptr)
|
||||
return result;
|
||||
|
||||
// The first time this hook is called, that means the menu has successfully
|
||||
// opened, so call the callback function on all of our listeners.
|
||||
if (!this_ptr->listeners_called_) {
|
||||
FOR_EACH_OBSERVER(MenuListener, this_ptr->listeners_, OnMenuOpened());
|
||||
this_ptr->listeners_called_ = true;
|
||||
}
|
||||
|
||||
MSG* msg = reinterpret_cast<MSG*>(l_param);
|
||||
if (msg->message == WM_LBUTTONUP || msg->message == WM_RBUTTONUP) {
|
||||
HighlightedMenuItemInfo info;
|
||||
if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info) && info.menu) {
|
||||
// It appears that when running a menu by way of TrackPopupMenu(Ex) win32
|
||||
// gets confused if the underlying window paints itself. As its very easy
|
||||
// for the underlying window to repaint itself (especially since some menu
|
||||
// items trigger painting of the tabstrip on mouse over) we have this
|
||||
// workaround. When the mouse is released on a menu item we remember the
|
||||
// menu item and end the menu. When the nested message loop returns we
|
||||
// schedule a task to notify the model. It's still possible to get a
|
||||
// WM_MENUCOMMAND, so we have to be careful that we don't notify the model
|
||||
// twice.
|
||||
this_ptr->menu_to_select_ = info.menu;
|
||||
this_ptr->position_to_select_ = info.position;
|
||||
EndMenu();
|
||||
}
|
||||
} else if (msg->message == WM_KEYDOWN) {
|
||||
HighlightedMenuItemInfo info;
|
||||
if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info)) {
|
||||
if (msg->wParam == VK_LEFT && !info.has_parent) {
|
||||
this_ptr->menu_action_ = MENU_ACTION_PREVIOUS;
|
||||
::EndMenu();
|
||||
} else if (msg->wParam == VK_RIGHT && !info.has_parent &&
|
||||
!info.has_submenu) {
|
||||
this_ptr->menu_action_ = MENU_ACTION_NEXT;
|
||||
::EndMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_FTYPE;
|
||||
GetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
|
||||
return !!(mii.fType & MF_SEPARATOR);
|
||||
}
|
||||
|
||||
void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA;
|
||||
if (!owner_draw_)
|
||||
mii.fType = MFT_STRING;
|
||||
else
|
||||
mii.fType = MFT_OWNERDRAW;
|
||||
|
||||
ItemData* item_data = new ItemData;
|
||||
item_data->label = string16();
|
||||
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
|
||||
if (type == ui::MenuModel::TYPE_SUBMENU) {
|
||||
item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
|
||||
mii.fMask |= MIIM_SUBMENU;
|
||||
mii.hSubMenu = item_data->submenu->GetNativeMenu();
|
||||
GetNativeMenuWinFromHMENU(mii.hSubMenu)->parent_ = this;
|
||||
} else {
|
||||
if (type == ui::MenuModel::TYPE_RADIO)
|
||||
mii.fType |= MFT_RADIOCHECK;
|
||||
mii.wID = model_->GetCommandIdAt(model_index);
|
||||
}
|
||||
item_data->native_menu_win = this;
|
||||
item_data->model_index = model_index;
|
||||
items_.insert(items_.begin() + model_index, item_data);
|
||||
mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data);
|
||||
UpdateMenuItemInfoForString(&mii, model_index,
|
||||
model_->GetLabelAt(model_index));
|
||||
InsertMenuItem(menu_, menu_index, TRUE, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::AddSeparatorItemAt(int menu_index, int model_index) {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_FTYPE;
|
||||
mii.fType = MFT_SEPARATOR;
|
||||
// Insert a dummy entry into our label list so we can index directly into it
|
||||
// using item indices if need be.
|
||||
items_.insert(items_.begin() + model_index, new ItemData);
|
||||
InsertMenuItem(menu_, menu_index, TRUE, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::SetMenuItemState(int menu_index, bool enabled, bool checked,
|
||||
bool is_default) {
|
||||
if (IsSeparatorItemAt(menu_index))
|
||||
return;
|
||||
|
||||
UINT state = enabled ? MFS_ENABLED : MFS_DISABLED;
|
||||
if (checked)
|
||||
state |= MFS_CHECKED;
|
||||
if (is_default)
|
||||
state |= MFS_DEFAULT;
|
||||
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_STATE;
|
||||
mii.fState = state;
|
||||
SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::SetMenuItemLabel(int menu_index,
|
||||
int model_index,
|
||||
const string16& label) {
|
||||
if (IsSeparatorItemAt(menu_index))
|
||||
return;
|
||||
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
UpdateMenuItemInfoForString(&mii, model_index, label);
|
||||
SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
|
||||
int model_index,
|
||||
const string16& label) {
|
||||
string16 formatted = label;
|
||||
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
|
||||
// Strip out any tabs, otherwise they get interpreted as accelerators and can
|
||||
// lead to weird behavior.
|
||||
ReplaceSubstringsAfterOffset(&formatted, 0, L"\t", L" ");
|
||||
if (type != ui::MenuModel::TYPE_SUBMENU) {
|
||||
// Add accelerator details to the label if provided.
|
||||
ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE);
|
||||
if (model_->GetAcceleratorAt(model_index, &accelerator)) {
|
||||
formatted += L"\t";
|
||||
formatted += accelerator.GetShortcutText();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the owned string, since Windows will want us to keep this new
|
||||
// version around.
|
||||
items_[model_index]->label = formatted;
|
||||
|
||||
// Give Windows a pointer to the label string.
|
||||
mii->fMask |= MIIM_STRING;
|
||||
mii->dwTypeData =
|
||||
const_cast<wchar_t*>(items_[model_index]->label.c_str());
|
||||
}
|
||||
|
||||
UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
|
||||
UINT alignment_flags = TPM_TOPALIGN;
|
||||
if (alignment == Menu2::ALIGN_TOPLEFT)
|
||||
alignment_flags |= TPM_LEFTALIGN;
|
||||
else if (alignment == Menu2::ALIGN_TOPRIGHT)
|
||||
alignment_flags |= TPM_RIGHTALIGN;
|
||||
return alignment_flags;
|
||||
}
|
||||
|
||||
void NativeMenuWin::ResetNativeMenu() {
|
||||
if (IsWindow(system_menu_for_)) {
|
||||
if (menu_)
|
||||
GetSystemMenu(system_menu_for_, TRUE);
|
||||
menu_ = GetSystemMenu(system_menu_for_, FALSE);
|
||||
} else {
|
||||
if (menu_)
|
||||
DestroyMenu(menu_);
|
||||
menu_ = create_as_window_menu_ ? CreateMenu() : CreatePopupMenu();
|
||||
// Rather than relying on the return value of TrackPopupMenuEx, which is
|
||||
// always a command identifier, instead we tell the menu to notify us via
|
||||
// our host window and the WM_MENUCOMMAND message.
|
||||
MENUINFO mi = {0};
|
||||
mi.cbSize = sizeof(mi);
|
||||
mi.fMask = MIM_STYLE | MIM_MENUDATA;
|
||||
mi.dwStyle = MNS_NOTIFYBYPOS;
|
||||
mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this);
|
||||
SetMenuInfo(menu_, &mi);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMenuWin::CreateHostWindow() {
|
||||
// This only gets called from RunMenuAt, and as such there is only ever one
|
||||
// host window per menu hierarchy, no matter how many NativeMenuWin objects
|
||||
// exist wrapping submenus.
|
||||
if (!host_window_.get())
|
||||
host_window_.reset(new MenuHostWindow(this));
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -1,192 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
|
||||
#define ATOM_BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace gfx {
|
||||
class Point;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class MenuInsertionDelegateWin;
|
||||
class MenuListener;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeMenuWin {
|
||||
public:
|
||||
// All of the possible actions that can result from RunMenuAt.
|
||||
enum MenuAction {
|
||||
MENU_ACTION_NONE, // Menu cancelled, or never opened.
|
||||
MENU_ACTION_SELECTED, // An item was selected.
|
||||
MENU_ACTION_PREVIOUS, // User wants to navigate to the previous menu.
|
||||
MENU_ACTION_NEXT, // User wants to navigate to the next menu.
|
||||
};
|
||||
|
||||
// Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
|
||||
// is non-NULL, the NativeMenuWin wraps the system menu for that window.
|
||||
// The caller owns the model and the delegate.
|
||||
NativeMenuWin(ui::MenuModel* model, HWND system_menu_for);
|
||||
virtual ~NativeMenuWin();
|
||||
|
||||
void RunMenuAt(const gfx::Point& point, int alignment);
|
||||
void CancelMenu();
|
||||
void Rebuild(views::MenuInsertionDelegateWin* delegate);
|
||||
void UpdateStates();
|
||||
HMENU GetNativeMenu() const;
|
||||
MenuAction GetMenuAction() const;
|
||||
void AddMenuListener(views::MenuListener* listener);
|
||||
void RemoveMenuListener(views::MenuListener* listener);
|
||||
void SetMinimumWidth(int width);
|
||||
|
||||
// Called by user to generate a menu command event.
|
||||
void OnMenuCommand(int position, HMENU menu);
|
||||
|
||||
// Flag to create a window menu instead of popup menu.
|
||||
void set_create_as_window_menu(bool flag) { create_as_window_menu_ = flag; }
|
||||
bool create_as_window_menu() const { return create_as_window_menu_; }
|
||||
|
||||
private:
|
||||
// IMPORTANT: Note about indices.
|
||||
// Functions in this class deal in two index spaces:
|
||||
// 1. menu_index - the index of an item within the actual Windows
|
||||
// native menu.
|
||||
// 2. model_index - the index of the item within our model.
|
||||
// These two are most often but not always the same value! The
|
||||
// notable exception is when this object is used to wrap the
|
||||
// Windows System Menu. In this instance, the model indices start
|
||||
// at 0, but the insertion index into the existing menu is not.
|
||||
// It is important to take this into consideration when editing the
|
||||
// code in the functions in this class.
|
||||
|
||||
struct HighlightedMenuItemInfo;
|
||||
|
||||
// Returns true if the item at the specified index is a separator.
|
||||
bool IsSeparatorItemAt(int menu_index) const;
|
||||
|
||||
// Add items. See note above about indices.
|
||||
void AddMenuItemAt(int menu_index, int model_index);
|
||||
void AddSeparatorItemAt(int menu_index, int model_index);
|
||||
|
||||
// Sets the state of the item at the specified index.
|
||||
void SetMenuItemState(int menu_index,
|
||||
bool enabled,
|
||||
bool checked,
|
||||
bool is_default);
|
||||
|
||||
// Sets the label of the item at the specified index.
|
||||
void SetMenuItemLabel(int menu_index,
|
||||
int model_index,
|
||||
const string16& label);
|
||||
|
||||
// Updates the local data structure with the correctly formatted version of
|
||||
// |label| at the specified model_index, and adds string data to |mii| if
|
||||
// the menu is not owner-draw. That's a mouthful. This function exists because
|
||||
// of the peculiarities of the Windows menu API.
|
||||
void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
|
||||
int model_index,
|
||||
const string16& label);
|
||||
|
||||
// Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
|
||||
// supplied alignment and the UI text direction.
|
||||
UINT GetAlignmentFlags(int alignment) const;
|
||||
|
||||
// Resets the native menu stored in |menu_| by destroying any old menu then
|
||||
// creating a new empty one.
|
||||
void ResetNativeMenu();
|
||||
|
||||
// Creates the host window that receives notifications from the menu.
|
||||
void CreateHostWindow();
|
||||
|
||||
// Callback from task to notify menu it was selected.
|
||||
void DelayedSelect();
|
||||
|
||||
// Given a menu that's currently popped-up, find the currently highlighted
|
||||
// item. Returns true if a highlighted item was found.
|
||||
static bool GetHighlightedMenuItemInfo(HMENU menu,
|
||||
HighlightedMenuItemInfo* info);
|
||||
|
||||
// Hook to receive keyboard events while the menu is open.
|
||||
static LRESULT CALLBACK MenuMessageHook(
|
||||
int n_code, WPARAM w_param, LPARAM l_param);
|
||||
|
||||
// Our attached model and delegate.
|
||||
ui::MenuModel* model_;
|
||||
|
||||
HMENU menu_;
|
||||
|
||||
// True if the contents of menu items in this menu are drawn by the menu host
|
||||
// window, rather than Windows.
|
||||
bool owner_draw_;
|
||||
|
||||
// An object that collects all of the data associated with an individual menu
|
||||
// item.
|
||||
struct ItemData;
|
||||
std::vector<ItemData*> items_;
|
||||
|
||||
// The window that receives notifications from the menu.
|
||||
class MenuHostWindow;
|
||||
friend MenuHostWindow;
|
||||
scoped_ptr<MenuHostWindow> host_window_;
|
||||
|
||||
// The HWND this menu is the system menu for, or NULL if the menu is not a
|
||||
// system menu.
|
||||
HWND system_menu_for_;
|
||||
|
||||
// The index of the first item in the model in the menu.
|
||||
int first_item_index_;
|
||||
|
||||
// The action that took place during the call to RunMenuAt.
|
||||
MenuAction menu_action_;
|
||||
|
||||
// A list of listeners to call when the menu opens.
|
||||
ObserverList<views::MenuListener> listeners_;
|
||||
|
||||
// Keep track of whether the listeners have already been called at least
|
||||
// once.
|
||||
bool listeners_called_;
|
||||
|
||||
// See comment in MenuMessageHook for details on these.
|
||||
NativeMenuWin* menu_to_select_;
|
||||
int position_to_select_;
|
||||
base::WeakPtrFactory<NativeMenuWin> menu_to_select_factory_;
|
||||
|
||||
// If we're a submenu, this is our parent.
|
||||
NativeMenuWin* parent_;
|
||||
|
||||
// If non-null the destructor sets this to true. This is set to non-null while
|
||||
// the menu is showing. It is used to detect if the menu was deleted while
|
||||
// running.
|
||||
bool* destroyed_flag_;
|
||||
|
||||
// Ugly: a static pointer to the instance of this class that currently
|
||||
// has a menu open, because our hook function that receives keyboard
|
||||
// events doesn't have a mechanism to get a user data pointer.
|
||||
static NativeMenuWin* open_native_menu_win_;
|
||||
|
||||
// Create as window menu.
|
||||
bool create_as_window_menu_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
|
|
@ -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";
|
||||
|
|
|
@ -20,9 +20,12 @@ namespace gfx {
|
|||
class Point;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class MenuRunner;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
class NotifyIconHost;
|
||||
|
||||
class NotifyIcon : public TrayIcon {
|
||||
|
@ -69,7 +72,7 @@ class NotifyIcon : public TrayIcon {
|
|||
|
||||
// The context menu.
|
||||
ui::SimpleMenuModel* menu_model_;
|
||||
scoped_ptr<atom::Menu2> menu_;
|
||||
scoped_ptr<views::MenuRunner> menu_runner_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -8,24 +8,25 @@
|
|||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/base/clipboard/clipboard.h"
|
||||
#include "ui/base/clipboard/scoped_clipboard_writer.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<ui::Clipboard::Buffer> {
|
||||
struct Converter<ui::ClipboardType> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
ui::Clipboard::Buffer* out) {
|
||||
ui::ClipboardType* out) {
|
||||
std::string type;
|
||||
if (!Converter<std::string>::FromV8(isolate, val, &type))
|
||||
return false;
|
||||
|
||||
if (type == "selection")
|
||||
*out = ui::Clipboard::BUFFER_SELECTION;
|
||||
*out = ui::CLIPBOARD_TYPE_SELECTION;
|
||||
else
|
||||
*out = ui::Clipboard::BUFFER_STANDARD;
|
||||
*out = ui::CLIPBOARD_TYPE_COPY_PASTE;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -34,14 +35,14 @@ struct Converter<ui::Clipboard::Buffer> {
|
|||
|
||||
namespace {
|
||||
|
||||
bool Has(const std::string& format_string, ui::Clipboard::Buffer buffer) {
|
||||
bool Has(const std::string& format_string, ui::ClipboardType type) {
|
||||
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
|
||||
ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string));
|
||||
return clipboard->IsFormatAvailable(format, buffer);
|
||||
return clipboard->IsFormatAvailable(format, type);
|
||||
}
|
||||
|
||||
std::string Read(const std::string& format_string,
|
||||
ui::Clipboard::Buffer buffer) {
|
||||
ui::ClipboardType type) {
|
||||
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
|
||||
ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string));
|
||||
|
||||
|
@ -50,27 +51,25 @@ std::string Read(const std::string& format_string,
|
|||
return data;
|
||||
}
|
||||
|
||||
string16 ReadText(ui::Clipboard::Buffer buffer) {
|
||||
string16 data;
|
||||
ui::Clipboard::GetForCurrentThread()->ReadText(buffer, &data);
|
||||
base::string16 ReadText(ui::ClipboardType type) {
|
||||
base::string16 data;
|
||||
ui::Clipboard::GetForCurrentThread()->ReadText(type, &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void WriteText(const std::string text, ui::Clipboard::Buffer buffer) {
|
||||
ui::Clipboard::ObjectMap object_map;
|
||||
object_map[ui::Clipboard::CBF_TEXT].push_back(
|
||||
std::vector<char>(text.begin(), text.end()));
|
||||
|
||||
void WriteText(const base::string16& text, ui::ClipboardType type) {
|
||||
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
|
||||
clipboard->WriteObjects(buffer, object_map);
|
||||
ui::ScopedClipboardWriter writer(clipboard, type);
|
||||
writer.WriteText(text);
|
||||
}
|
||||
|
||||
void Clear(ui::Clipboard::Buffer buffer) {
|
||||
ui::Clipboard::GetForCurrentThread()->Clear(buffer);
|
||||
void Clear(ui::ClipboardType type) {
|
||||
ui::Clipboard::GetForCurrentThread()->Clear(type);
|
||||
}
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("_has", &Has);
|
||||
dict.SetMethod("_read", &Read);
|
||||
dict.SetMethod("_readText", &ReadText);
|
||||
|
@ -80,4 +79,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_common_clipboard, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_clipboard, Initialize)
|
||||
|
|
|
@ -35,9 +35,10 @@ struct Converter<std::map<std::string, std::string> > {
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
using crash_reporter::CrashReporter;
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("start",
|
||||
base::Bind(&CrashReporter::Start,
|
||||
base::Unretained(CrashReporter::GetInstance())));
|
||||
|
@ -45,4 +46,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_common_crash_reporter, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_crash_reporter, Initialize)
|
||||
|
|
|
@ -29,14 +29,14 @@ int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Handle<v8::Object> object) {
|
|||
mate::Converter<int32_t>::ToV8(isolate, key));
|
||||
|
||||
map_[key] = new mate::RefCountedPersistent<v8::Object>(object);
|
||||
map_[key]->MakeWeak(this, WeakCallback);
|
||||
map_[key]->SetWeak(this, WeakCallback);
|
||||
return key;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> IDWeakMap::Get(int32_t key) {
|
||||
v8::Handle<v8::Value> IDWeakMap::Get(v8::Isolate* isolate, int32_t key) {
|
||||
if (!Has(key)) {
|
||||
node::ThrowError("Invalid key");
|
||||
return v8::Undefined();
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
return map_[key]->NewHandle();
|
||||
|
@ -77,14 +77,11 @@ void IDWeakMap::BuildPrototype(v8::Isolate* isolate,
|
|||
}
|
||||
|
||||
// static
|
||||
void IDWeakMap::WeakCallback(v8::Isolate* isolate,
|
||||
v8::Persistent<v8::Object>* value,
|
||||
IDWeakMap* self) {
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Object> object = v8::Local<v8::Object>::New(isolate, *value);
|
||||
int32_t key = object->GetHiddenValue(
|
||||
mate::StringToV8(isolate, "IDWeakMapKey"))->Int32Value();
|
||||
self->Remove(key);
|
||||
void IDWeakMap::WeakCallback(
|
||||
const v8::WeakCallbackData<v8::Object, IDWeakMap>& data) {
|
||||
int32_t key = data.GetValue()->GetHiddenValue(
|
||||
mate::StringToV8(data.GetIsolate(), "IDWeakMapKey"))->Int32Value();
|
||||
data.GetParameter()->Remove(key);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
@ -94,10 +91,10 @@ void IDWeakMap::WeakCallback(v8::Isolate* isolate,
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
using atom::api::IDWeakMap;
|
||||
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Function> constructor = mate::CreateConstructor<IDWeakMap>(
|
||||
isolate,
|
||||
"IDWeakMap",
|
||||
|
@ -107,4 +104,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_common_id_weak_map, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize)
|
||||
|
|
|
@ -29,15 +29,14 @@ class IDWeakMap : public mate::Wrappable {
|
|||
virtual ~IDWeakMap();
|
||||
|
||||
int32_t Add(v8::Isolate* isolate, v8::Handle<v8::Object> object);
|
||||
v8::Handle<v8::Value> Get(int32_t key);
|
||||
v8::Handle<v8::Value> Get(v8::Isolate* isolate, int32_t key);
|
||||
bool Has(int32_t key) const;
|
||||
std::vector<int32_t> Keys() const;
|
||||
void Remove(int32_t key);
|
||||
int GetNextID();
|
||||
|
||||
static void WeakCallback(v8::Isolate* isolate,
|
||||
v8::Persistent<v8::Object>* value,
|
||||
IDWeakMap* self);
|
||||
static void WeakCallback(
|
||||
const v8::WeakCallbackData<v8::Object, IDWeakMap>& data);
|
||||
|
||||
int32_t next_id_;
|
||||
|
||||
|
|
|
@ -7,34 +7,8 @@
|
|||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
#if defined(TOOLKIT_GTK)
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "ui/gfx/gtk_util.h"
|
||||
#endif
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace {
|
||||
|
||||
gfx::Display AdaptToWindowManager(const gfx::Display& display) {
|
||||
gfx::Display changed(display);
|
||||
#if defined(TOOLKIT_GTK)
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
base::nix::DesktopEnvironment de(base::nix::GetDesktopEnvironment(env.get()));
|
||||
if (de == base::nix::DESKTOP_ENVIRONMENT_UNITY) {
|
||||
// Unity's 24px global menu bar should not be included in the work area.
|
||||
gfx::Rect rect(changed.work_area());
|
||||
rect.set_height(rect.height() - 24);
|
||||
changed.set_work_area(rect);
|
||||
}
|
||||
#endif
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct Converter<gfx::Point> {
|
||||
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
|
@ -70,8 +44,7 @@ struct Converter<gfx::Rect> {
|
|||
template<>
|
||||
struct Converter<gfx::Display> {
|
||||
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const gfx::Display& val) {
|
||||
gfx::Display display(AdaptToWindowManager(val));
|
||||
const gfx::Display& display) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetValue("bounds", display.bounds())
|
||||
.SetValue("workArea", display.work_area())
|
||||
|
@ -86,13 +59,10 @@ struct Converter<gfx::Display> {
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
#if defined(TOOLKIT_GTK)
|
||||
gfx::GdkInitFromCommandLine(*CommandLine::ForCurrentProcess());
|
||||
#endif
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("getCursorScreenPoint",
|
||||
base::Bind(&gfx::Screen::GetCursorScreenPoint,
|
||||
base::Unretained(screen)));
|
||||
|
@ -103,4 +73,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_common_screen, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_screen, Initialize)
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder);
|
||||
dict.SetMethod("openItem", &platform_util::OpenItem);
|
||||
dict.SetMethod("openExternal", &platform_util::OpenExternal);
|
||||
|
@ -24,4 +25,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_common_shell, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_shell, Initialize)
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
namespace {
|
||||
|
||||
v8::Handle<v8::Object> CreateObjectWithName(v8::Handle<v8::String> name) {
|
||||
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
|
||||
v8::Handle<v8::Object> CreateObjectWithName(v8::Isolate* isolate,
|
||||
v8::Handle<v8::String> name) {
|
||||
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
|
||||
t->SetClassName(name);
|
||||
return t->GetFunction()->NewInstance();
|
||||
}
|
||||
|
@ -31,18 +32,20 @@ int32_t GetObjectHash(v8::Handle<v8::Object> object) {
|
|||
return object->GetIdentityHash();
|
||||
}
|
||||
|
||||
void SetDestructor(v8::Handle<v8::Object> object,
|
||||
void SetDestructor(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Object> object,
|
||||
v8::Handle<v8::Function> callback) {
|
||||
atom::ObjectLifeMonitor::BindTo(object, callback);
|
||||
atom::ObjectLifeMonitor::BindTo(isolate, object, callback);
|
||||
}
|
||||
|
||||
void TakeHeapSnapshot() {
|
||||
node::node_isolate->GetHeapProfiler()->TakeHeapSnapshot(
|
||||
v8::String::New("test"));
|
||||
void TakeHeapSnapshot(v8::Isolate* isolate) {
|
||||
isolate->GetHeapProfiler()->TakeHeapSnapshot(
|
||||
mate::StringToV8(isolate, "test"));
|
||||
}
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports) {
|
||||
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("createObjectWithName", &CreateObjectWithName);
|
||||
dict.SetMethod("getHiddenValue", &GetHiddenValue);
|
||||
dict.SetMethod("setHiddenValue", &SetHiddenValue);
|
||||
|
@ -53,4 +56,4 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
|||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE(atom_common_v8_util, Initialize)
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_v8_util, Initialize)
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
|
||||
namespace atom {
|
||||
|
||||
// Defined in atom_extensions.cc.
|
||||
node::node_module_struct* GetBuiltinModule(const char *name, bool is_browser);
|
||||
|
||||
namespace {
|
||||
|
||||
// Async handle to wake up uv loop.
|
||||
|
@ -35,8 +32,9 @@ base::Closure g_v8_callback;
|
|||
struct DummyClass { bool crash; };
|
||||
|
||||
// Async handler to call next process.nextTick callbacks.
|
||||
void UvCallNextTick(uv_async_t* handle, int status) {
|
||||
node::Environment* env = node::Environment::GetCurrent(node_isolate);
|
||||
void UvCallNextTick(uv_async_t* handle) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
node::Environment* env = node::Environment::GetCurrent(isolate);
|
||||
node::Environment::TickInfo* tick_info = env->tick_info();
|
||||
|
||||
if (tick_info->in_tick())
|
||||
|
@ -53,7 +51,7 @@ void UvCallNextTick(uv_async_t* handle, int status) {
|
|||
}
|
||||
|
||||
// Async handler to execute the stored v8 callback.
|
||||
void UvOnCallback(uv_async_t* handle, int status) {
|
||||
void UvOnCallback(uv_async_t* handle) {
|
||||
g_v8_callback.Run();
|
||||
}
|
||||
|
||||
|
@ -72,45 +70,6 @@ v8::Handle<v8::Value> DumpStackFrame(v8::Isolate* isolate,
|
|||
return mate::ConvertToV8(isolate, frame_dict);;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Binding(v8::Handle<v8::String> module) {
|
||||
v8::String::Utf8Value module_v(module);
|
||||
node::node_module_struct* modp;
|
||||
|
||||
v8::Local<v8::Object> process = v8::Context::GetCurrent()->Global()->
|
||||
Get(v8::String::New("process"))->ToObject();
|
||||
DCHECK(!process.IsEmpty());
|
||||
|
||||
// is_browser = process.type == 'browser'.
|
||||
bool is_browser = std::string("browser") == *v8::String::Utf8Value(
|
||||
process->Get(v8::String::New("type")));
|
||||
|
||||
// Cached in process.__atom_binding_cache.
|
||||
v8::Local<v8::Object> binding_cache;
|
||||
v8::Local<v8::String> bc_name = v8::String::New("__atomBindingCache");
|
||||
if (process->Has(bc_name)) {
|
||||
binding_cache = process->Get(bc_name)->ToObject();
|
||||
DCHECK(!binding_cache.IsEmpty());
|
||||
} else {
|
||||
binding_cache = v8::Object::New();
|
||||
process->Set(bc_name, binding_cache);
|
||||
}
|
||||
|
||||
if (binding_cache->Has(module))
|
||||
return binding_cache->Get(module)->ToObject();
|
||||
|
||||
if ((modp = GetBuiltinModule(*module_v, is_browser)) != NULL) {
|
||||
v8::Local<v8::Object> exports = v8::Object::New();
|
||||
// Internal bindings don't have a "module" object,
|
||||
// only exports.
|
||||
modp->register_func(exports, v8::Undefined());
|
||||
binding_cache->Set(module, exports);
|
||||
return exports;
|
||||
}
|
||||
|
||||
node::ThrowError("No such module");
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
void Crash() {
|
||||
static_cast<DummyClass*>(NULL)->crash = true;
|
||||
}
|
||||
|
@ -119,17 +78,17 @@ void ActivateUVLoop() {
|
|||
uv_async_send(&g_next_tick_uv_handle);
|
||||
}
|
||||
|
||||
void Log(const string16& message) {
|
||||
void Log(const base::string16& message) {
|
||||
logging::LogMessage("CONSOLE", 0, 0).stream() << message;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> GetCurrentStackTrace(v8::Isolate* isolate,
|
||||
int stack_limit) {
|
||||
v8::Local<v8::StackTrace> stack_trace = v8::StackTrace::CurrentStackTrace(
|
||||
stack_limit, v8::StackTrace::kDetailed);
|
||||
isolate, stack_limit, v8::StackTrace::kDetailed);
|
||||
|
||||
int frame_count = stack_trace->GetFrameCount();
|
||||
v8::Local<v8::Array> result = v8::Array::New(frame_count);
|
||||
v8::Local<v8::Array> result = v8::Array::New(isolate, frame_count);
|
||||
for (int i = 0; i < frame_count; ++i)
|
||||
result->Set(i, DumpStackFrame(isolate, stack_trace->GetFrame(i)));
|
||||
|
||||
|
@ -153,10 +112,9 @@ AtomBindings::AtomBindings() {
|
|||
AtomBindings::~AtomBindings() {
|
||||
}
|
||||
|
||||
void AtomBindings::BindTo(v8::Handle<v8::Object> process) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
void AtomBindings::BindTo(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Object> process) {
|
||||
mate::Dictionary dict(isolate, process);
|
||||
dict.SetMethod("atomBinding", &Binding);
|
||||
dict.SetMethod("crash", &Crash);
|
||||
dict.SetMethod("activateUvLoop", &ActivateUVLoop);
|
||||
dict.SetMethod("log", &Log);
|
||||
|
|
|
@ -17,9 +17,9 @@ class AtomBindings {
|
|||
AtomBindings();
|
||||
virtual ~AtomBindings();
|
||||
|
||||
// Add process.atom_binding function, which behaves like process.binding but
|
||||
// Add process.atomBinding function, which behaves like process.binding but
|
||||
// load native code from atom-shell instead.
|
||||
virtual void BindTo(v8::Handle<v8::Object> process);
|
||||
virtual void BindTo(v8::Isolate* isolate, v8::Handle<v8::Object> process);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBindings);
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "base/strings/string_util.h"
|
||||
#include "vendor/node/src/node_version.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
#undef NODE_EXT_LIST_START
|
||||
#undef NODE_EXT_LIST_ITEM
|
||||
#undef NODE_EXT_LIST_END
|
||||
|
||||
#define NODE_EXT_LIST_START
|
||||
#define NODE_EXT_LIST_ITEM NODE_MODULE_DECL
|
||||
#define NODE_EXT_LIST_END
|
||||
|
||||
#include "atom/common/api/atom_extensions.h"
|
||||
|
||||
#undef NODE_EXT_LIST_START
|
||||
#undef NODE_EXT_LIST_ITEM
|
||||
#undef NODE_EXT_LIST_END
|
||||
|
||||
#define NODE_EXT_STRING(x) &x ## _module,
|
||||
#define NODE_EXT_LIST_START node::node_module_struct *node_module_list[] = {
|
||||
#define NODE_EXT_LIST_ITEM NODE_EXT_STRING
|
||||
#define NODE_EXT_LIST_END NULL};
|
||||
|
||||
#include "atom/common/api/atom_extensions.h" // NOLINT
|
||||
|
||||
node::node_module_struct* GetBuiltinModule(const char *name, bool is_browser) {
|
||||
char common[128];
|
||||
char spec[128];
|
||||
node::node_module_struct *cur = NULL;
|
||||
base::snprintf(common, sizeof(common), "atom_common_%s", name);
|
||||
base::snprintf(spec, sizeof(spec),
|
||||
(is_browser ? "atom_browser_%s": "atom_renderer_%s"),
|
||||
name);
|
||||
/* TODO: you could look these up in a hash, but there are only
|
||||
* a few, and once loaded they are cached. */
|
||||
for (int i = 0; node_module_list[i] != NULL; i++) {
|
||||
cur = node_module_list[i];
|
||||
if (strcmp(cur->modname, common) == 0 || strcmp(cur->modname, spec) == 0) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -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
|
|
@ -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'
|
||||
|
|
|
@ -5,34 +5,32 @@
|
|||
|
||||
#include "atom/common/api/object_life_monitor.h"
|
||||
|
||||
#include "native_mate/compat.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
void ObjectLifeMonitor::BindTo(v8::Handle<v8::Object> target,
|
||||
void ObjectLifeMonitor::BindTo(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Object> target,
|
||||
v8::Handle<v8::Value> destructor) {
|
||||
target->SetHiddenValue(v8::String::New("destructor"), destructor);
|
||||
target->SetHiddenValue(MATE_STRING_NEW(isolate, "destructor"), destructor);
|
||||
|
||||
ObjectLifeMonitor* olm = new ObjectLifeMonitor();
|
||||
olm->handle_.reset(target);
|
||||
olm->handle_.MakeWeak(olm, WeakCallback);
|
||||
olm->handle_.SetWeak(olm, WeakCallback);
|
||||
}
|
||||
|
||||
ObjectLifeMonitor::ObjectLifeMonitor() {
|
||||
}
|
||||
|
||||
// static
|
||||
void ObjectLifeMonitor::WeakCallback(v8::Isolate* isolate,
|
||||
v8::Persistent<v8::Object>* value,
|
||||
ObjectLifeMonitor* self) {
|
||||
void ObjectLifeMonitor::WeakCallback(
|
||||
const v8::WeakCallbackData<v8::Object, ObjectLifeMonitor>& data) {
|
||||
// destructor.call(object, object);
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Object> obj = self->handle_.NewHandle();
|
||||
v8::Local<v8::Function>::Cast(obj->GetHiddenValue(
|
||||
v8::String::New("destructor")))->Call(obj, 0, NULL);
|
||||
}
|
||||
|
||||
delete self;
|
||||
v8::Local<v8::Object> obj = data.GetValue();
|
||||
v8::Local<v8::Function>::Cast(obj->GetHiddenValue(
|
||||
MATE_STRING_NEW(data.GetIsolate(), "destructor")))->Call(obj, 0, NULL);
|
||||
delete data.GetParameter();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -12,15 +12,15 @@ namespace atom {
|
|||
|
||||
class ObjectLifeMonitor {
|
||||
public:
|
||||
static void BindTo(v8::Handle<v8::Object> target,
|
||||
static void BindTo(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Object> target,
|
||||
v8::Handle<v8::Value> destructor);
|
||||
|
||||
private:
|
||||
ObjectLifeMonitor();
|
||||
|
||||
static void WeakCallback(v8::Isolate* isolate,
|
||||
v8::Persistent<v8::Object>* value,
|
||||
ObjectLifeMonitor* self);
|
||||
static void WeakCallback(
|
||||
const v8::WeakCallbackData<v8::Object, ObjectLifeMonitor>& data);
|
||||
|
||||
mate::ScopedPersistent<v8::Object> handle_;
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -11,17 +11,20 @@
|
|||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<string16> {
|
||||
struct Converter<base::string16> {
|
||||
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const string16& val) {
|
||||
return v8::String::New(reinterpret_cast<const uint16_t*>(val.data()),
|
||||
val.size());
|
||||
const base::string16& val) {
|
||||
return MATE_STRING_NEW_FROM_UTF16(
|
||||
isolate, reinterpret_cast<const uint16_t*>(val.data()), val.size());
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
string16* out) {
|
||||
base::string16* out) {
|
||||
if (!val->IsString())
|
||||
return false;
|
||||
|
||||
v8::String::Value s(val);
|
||||
out->assign(reinterpret_cast<const char16*>(*s), s.length());
|
||||
out->assign(reinterpret_cast<const base::char16*>(*s), s.length());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue