mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
214 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
740e7fbf1a | ||
|
|
be5789b483 | ||
|
|
1c415b0666 | ||
|
|
8dd7f81175 | ||
|
|
87019a1a70 | ||
|
|
10c52bd6a6 | ||
|
|
c23c667c2d | ||
|
|
ec4275ca13 | ||
|
|
143bde007a | ||
|
|
a6ede12cd7 | ||
|
|
7a89a08534 | ||
|
|
5ad203ad99 | ||
|
|
82dcdc6314 | ||
|
|
371e38198f | ||
|
|
472a95e433 | ||
|
|
b84226244d | ||
|
|
e4290393af | ||
|
|
cab00a1450 | ||
|
|
ce50b38a75 | ||
|
|
e8d59c4326 | ||
|
|
b9d64784bb | ||
|
|
ad3eac2e38 | ||
|
|
e11c8a07ea | ||
|
|
a04cb08715 | ||
|
|
b9fc5474c5 | ||
|
|
709670be8e | ||
|
|
2afd3a85a9 | ||
|
|
92a0a4cf6c | ||
|
|
32c6f4cfe8 | ||
|
|
dbf19a5734 | ||
|
|
f7a9b56e93 | ||
|
|
53c73c0631 | ||
|
|
6c866ea909 | ||
|
|
8fcd39f621 | ||
|
|
ef352a69b4 | ||
|
|
99ef165884 | ||
|
|
77627c0d2d | ||
|
|
c91f0c575c | ||
|
|
1a5c0ab1ae | ||
|
|
11634740d3 | ||
|
|
640ac43059 | ||
|
|
6f231d5860 | ||
|
|
acb8b7771e | ||
|
|
301706b7d6 | ||
|
|
17cf6ffbd4 | ||
|
|
e803d3cc7a | ||
|
|
e4484f0c3e | ||
|
|
dd404fb785 | ||
|
|
a15ee1871a | ||
|
|
9b8ee42f79 | ||
|
|
939ead3aee | ||
|
|
026c85508a | ||
|
|
e6998dfd4b | ||
|
|
21949e2f0c | ||
|
|
1a79093378 | ||
|
|
ffad6fe884 | ||
|
|
0ca33dc6b8 | ||
|
|
a0bf74b9df | ||
|
|
b29ab48032 | ||
|
|
42afc5603d | ||
|
|
fab11950ee | ||
|
|
365638f1d5 | ||
|
|
73df08ebbf | ||
|
|
9c9e0d92f4 | ||
|
|
66aea0c3e8 | ||
|
|
a1c2adda3d | ||
|
|
0f18d63f7f | ||
|
|
2ee7caccfe | ||
|
|
2a2fc4903d | ||
|
|
9afc2daf75 | ||
|
|
8f94d5886d | ||
|
|
6de595f036 | ||
|
|
db6c37bfbc | ||
|
|
6bfa69ceda | ||
|
|
00467b53c7 | ||
|
|
adec718503 | ||
|
|
7c8a0ae2a3 | ||
|
|
add45b564e | ||
|
|
643a47cf7d | ||
|
|
2f967149fc | ||
|
|
5c99dff36d | ||
|
|
b2839b08cd | ||
|
|
cc29f43a35 | ||
|
|
b2afe7b3bf | ||
|
|
b4ba149662 | ||
|
|
43e8ecb118 | ||
|
|
ea60a04280 | ||
|
|
3c11bc5f98 | ||
|
|
8d4211bd3a | ||
|
|
497174bbe4 | ||
|
|
1c62211d99 | ||
|
|
7e86e53593 | ||
|
|
3349b8e6c7 | ||
|
|
49160819d2 | ||
|
|
83ff00dc29 | ||
|
|
e150a3e3b2 | ||
|
|
dd6f8669a1 | ||
|
|
fcf55df874 | ||
|
|
d81a34d3dd | ||
|
|
7b93a19e9b | ||
|
|
2312f84ec9 | ||
|
|
4e4227aef8 | ||
|
|
ee5312fff9 | ||
|
|
b99262af32 | ||
|
|
3d36a6a793 | ||
|
|
db98a3842f | ||
|
|
a5e2ea2899 | ||
|
|
e7feafb2cc | ||
|
|
4609a8d2be | ||
|
|
66ab127389 | ||
|
|
cb08f35c7f | ||
|
|
c511933cfc | ||
|
|
b3bccd2e1e | ||
|
|
3c892b8591 | ||
|
|
0a38f3321e | ||
|
|
61db17412c | ||
|
|
1965a5ee50 | ||
|
|
970b82c314 | ||
|
|
84878c4c77 | ||
|
|
949821f255 | ||
|
|
2cc2fd03fa | ||
|
|
2ed46e6f7f | ||
|
|
116e4c877e | ||
|
|
ffb0c22a80 | ||
|
|
721a40ba82 | ||
|
|
9031dcbb2f | ||
|
|
d0abc38afe | ||
|
|
6a891be0e4 | ||
|
|
1d359cb8aa | ||
|
|
2736b5dab3 | ||
|
|
d5b2a5af26 | ||
|
|
e0f263950e | ||
|
|
750148f7b4 | ||
|
|
6ddb8c00dc | ||
|
|
ba46f2c820 | ||
|
|
c3301a197e | ||
|
|
69adff19fe | ||
|
|
64bf1bcb9f | ||
|
|
1f99a97544 | ||
|
|
f4b6ca70a9 | ||
|
|
e5c10f29de | ||
|
|
436deddf68 | ||
|
|
ad19381217 | ||
|
|
cd4c5d976b | ||
|
|
58ccb27792 | ||
|
|
e0e1d45859 | ||
|
|
c713deb1e8 | ||
|
|
91c7458ab8 | ||
|
|
5f3fa341b2 | ||
|
|
066d129536 | ||
|
|
348dc8365b | ||
|
|
dad7aa6a20 | ||
|
|
5d4f1e3c00 | ||
|
|
2d073e78ef | ||
|
|
72d6778894 | ||
|
|
0440c59d18 | ||
|
|
8ecc4061a8 | ||
|
|
3eecd664b4 | ||
|
|
4c5a306733 | ||
|
|
79c3377cd7 | ||
|
|
32c881bde9 | ||
|
|
27d73b362a | ||
|
|
ab1670ff03 | ||
|
|
d3c76d6998 | ||
|
|
a2c897aa9f | ||
|
|
a8de615034 | ||
|
|
1a0d8a4aa9 | ||
|
|
2ff4d56d6d | ||
|
|
ca1d2a32b0 | ||
|
|
b92e6e97ea | ||
|
|
84e2c35611 | ||
|
|
0349fdfd67 | ||
|
|
11e4111f25 | ||
|
|
6cac69238c | ||
|
|
17842e06aa | ||
|
|
fe6eac6c7d | ||
|
|
ae3958c997 | ||
|
|
9c84f92f3e | ||
|
|
48224a6455 | ||
|
|
41b9add5d6 | ||
|
|
716c7ee6f4 | ||
|
|
3d89181e96 | ||
|
|
32323a0006 | ||
|
|
6493bc4c8c | ||
|
|
6d404d1cc4 | ||
|
|
edc043c924 | ||
|
|
dca50fcec3 | ||
|
|
f0e297ba77 | ||
|
|
8a8ffbebf9 | ||
|
|
f4aadcbbfc | ||
|
|
81eedd4faf | ||
|
|
74fe964f75 | ||
|
|
a138b5ec8b | ||
|
|
054daadc33 | ||
|
|
05f079fa5b | ||
|
|
0bc8251e1b | ||
|
|
8c264b9a07 | ||
|
|
accfabf569 | ||
|
|
4a7a417423 | ||
|
|
386ef9197c | ||
|
|
d4e9518ec6 | ||
|
|
70d3365414 | ||
|
|
a8cb839734 | ||
|
|
5270eab512 | ||
|
|
bf5fc2db9b | ||
|
|
c97e849610 | ||
|
|
2cdcb45d16 | ||
|
|
df8b9f69b1 | ||
|
|
b431566421 | ||
|
|
4aa217970e | ||
|
|
444fe8bf1f | ||
|
|
f063a63b69 | ||
|
|
1d6b02f304 | ||
|
|
7d38fe61d2 |
79
atom.gyp
79
atom.gyp
@@ -41,6 +41,7 @@
|
||||
'atom/renderer/lib/override.coffee',
|
||||
'atom/renderer/api/lib/ipc.coffee',
|
||||
'atom/renderer/api/lib/remote.coffee',
|
||||
'atom/renderer/api/lib/web-view.coffee',
|
||||
],
|
||||
'lib_sources': [
|
||||
'atom/app/atom_main_delegate.cc',
|
||||
@@ -53,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',
|
||||
@@ -94,20 +93,18 @@
|
||||
'atom/browser/browser_mac.mm',
|
||||
'atom/browser/browser_win.cc',
|
||||
'atom/browser/browser_observer.h',
|
||||
'atom/browser/devtools_delegate.cc',
|
||||
'atom/browser/devtools_delegate.h',
|
||||
'atom/browser/javascript_environment.cc',
|
||||
'atom/browser/javascript_environment.h',
|
||||
'atom/browser/mac/atom_application.h',
|
||||
'atom/browser/mac/atom_application.mm',
|
||||
'atom/browser/mac/atom_application_delegate.h',
|
||||
'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',
|
||||
@@ -119,9 +116,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',
|
||||
@@ -130,25 +126,29 @@
|
||||
'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/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',
|
||||
@@ -168,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',
|
||||
@@ -219,24 +217,20 @@
|
||||
'atom/renderer/api/atom_api_renderer_ipc.cc',
|
||||
'atom/renderer/api/atom_renderer_bindings.cc',
|
||||
'atom/renderer/api/atom_renderer_bindings.h',
|
||||
'atom/renderer/api/atom_api_web_view.cc',
|
||||
'atom/renderer/api/atom_api_web_view.h',
|
||||
'atom/renderer/atom_render_view_observer.cc',
|
||||
'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': [
|
||||
@@ -378,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',
|
||||
],
|
||||
@@ -401,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',
|
||||
],
|
||||
},
|
||||
@@ -426,6 +423,7 @@
|
||||
],
|
||||
'include_dirs': [
|
||||
'.',
|
||||
'chromium_src',
|
||||
'vendor/brightray',
|
||||
'vendor/native_mate',
|
||||
# Include directories for uv and node.
|
||||
@@ -453,7 +451,6 @@
|
||||
'-loleacc.lib',
|
||||
'-lComdlg32.lib',
|
||||
'-lWininet.lib',
|
||||
'<(atom_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
|
||||
],
|
||||
},
|
||||
'dependencies': [
|
||||
@@ -653,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',
|
||||
@@ -662,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();
|
||||
|
||||
@@ -131,9 +132,13 @@ void Initialize(v8::Handle<v8::Object> exports) {
|
||||
dict.SetMethod("dockGetBadgeText",
|
||||
base::Bind(&Browser::DockGetBadgeText,
|
||||
base::Unretained(browser)));
|
||||
dict.SetMethod("dockHide",
|
||||
base::Bind(&Browser::DockHide, base::Unretained(browser)));
|
||||
dict.SetMethod("dockShow",
|
||||
base::Bind(&Browser::DockShow, base::Unretained(browser)));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // 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_
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -44,7 +43,7 @@ void MenuMac::Popup(Window* window) {
|
||||
// Show the menu.
|
||||
[NSMenu popUpContextMenu:[menu_controller menu]
|
||||
withEvent:clickEvent
|
||||
forView:web_contents->GetView()->GetContentNativeView()];
|
||||
forView:web_contents->GetContentNativeView()];
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
37
atom/browser/api/atom_api_menu_views.cc
Normal file
37
atom/browser/api/atom_api_menu_views.cc
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
MenuViews::MenuViews() {
|
||||
}
|
||||
|
||||
void MenuViews::Popup(Window* window) {
|
||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
views::MenuRunner menu_runner(model());
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
static_cast<NativeWindowViews*>(window->window())->widget(),
|
||||
NULL,
|
||||
gfx::Rect(cursor, gfx::Size()),
|
||||
views::MENU_ANCHOR_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)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/strings/utf_string_conversions.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/web_contents.h"
|
||||
@@ -38,7 +39,12 @@ void WebContents::DidFinishLoad(int64 frame_id,
|
||||
const GURL& validated_url,
|
||||
bool is_main_frame,
|
||||
content::RenderViewHost* render_view_host) {
|
||||
Emit("did-finish-load");
|
||||
base::ListValue args;
|
||||
args.AppendBoolean(is_main_frame);
|
||||
Emit("did-frame-finish-load", args);
|
||||
|
||||
if (is_main_frame)
|
||||
Emit("did-finish-load");
|
||||
}
|
||||
|
||||
void WebContents::DidStartLoading(content::RenderViewHost* render_view_host) {
|
||||
@@ -61,7 +67,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||
return handled;
|
||||
}
|
||||
|
||||
void WebContents::WebContentsDestroyed(content::WebContents*) {
|
||||
void WebContents::WebContentsDestroyed() {
|
||||
// The RenderViewDeleted was not called when the WebContents is destroyed.
|
||||
RenderViewDeleted(web_contents_->GetRenderViewHost());
|
||||
Emit("destroyed");
|
||||
@@ -82,7 +88,7 @@ GURL WebContents::GetURL() const {
|
||||
return web_contents()->GetURL();
|
||||
}
|
||||
|
||||
string16 WebContents::GetTitle() const {
|
||||
base::string16 WebContents::GetTitle() const {
|
||||
return web_contents()->GetTitle();
|
||||
}
|
||||
|
||||
@@ -149,12 +155,11 @@ bool WebContents::IsCrashed() const {
|
||||
return web_contents()->IsCrashed();
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const string16& code) {
|
||||
web_contents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
|
||||
string16(), code);
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code) {
|
||||
web_contents()->GetMainFrame()->ExecuteJavaScript(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));
|
||||
}
|
||||
@@ -181,21 +186,21 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("getRoutingId", &WebContents::GetRoutingID)
|
||||
.SetMethod("getProcessId", &WebContents::GetProcessID)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
.SetMethod("executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.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);
|
||||
@@ -61,14 +62,15 @@ class WebContents : public mate::EventEmitter,
|
||||
virtual void DidStopLoading(
|
||||
content::RenderViewHost* render_view_host) OVERRIDE;
|
||||
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
|
||||
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
|
||||
virtual void WebContentsDestroyed() OVERRIDE;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/common/native_mate_converters/function_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
@@ -47,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()),
|
||||
@@ -61,7 +61,7 @@ void OnCapturePageDone(
|
||||
} // namespace
|
||||
|
||||
|
||||
Window::Window(base::DictionaryValue* options)
|
||||
Window::Window(const mate::Dictionary& options)
|
||||
: window_(NativeWindow::Create(options)) {
|
||||
window_->InitFromOptions(options);
|
||||
window_->AddObserver(this);
|
||||
@@ -108,10 +108,8 @@ void Window::OnRendererResponsive() {
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Window::New(mate::Arguments* args,
|
||||
const base::DictionaryValue& options) {
|
||||
scoped_ptr<base::DictionaryValue> copied_options(options.DeepCopy());
|
||||
return new Window(copied_options.get());
|
||||
mate::Wrappable* Window::New(const mate::Dictionary& options) {
|
||||
return new Window(options);
|
||||
}
|
||||
|
||||
void Window::Destroy() {
|
||||
@@ -151,6 +149,10 @@ void Window::Unmaximize() {
|
||||
window_->Unmaximize();
|
||||
}
|
||||
|
||||
bool Window::IsMaximized() {
|
||||
return window_->IsMaximized();
|
||||
}
|
||||
|
||||
void Window::Minimize() {
|
||||
window_->Minimize();
|
||||
}
|
||||
@@ -159,6 +161,10 @@ void Window::Restore() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool Window::IsMinimized() {
|
||||
return window_->IsMinimized();
|
||||
}
|
||||
|
||||
void Window::SetFullscreen(bool fullscreen) {
|
||||
window_->SetFullscreen(fullscreen);
|
||||
}
|
||||
@@ -259,6 +265,10 @@ void Window::FlashFrame(bool flash) {
|
||||
window_->FlashFrame(flash);
|
||||
}
|
||||
|
||||
void Window::SetSkipTaskbar(bool skip) {
|
||||
window_->SetSkipTaskbar(skip);
|
||||
}
|
||||
|
||||
void Window::SetKiosk(bool kiosk) {
|
||||
window_->SetKiosk(kiosk);
|
||||
}
|
||||
@@ -283,11 +293,6 @@ void Window::InspectElement(int x, int y) {
|
||||
window_->InspectElement(x, y);
|
||||
}
|
||||
|
||||
void Window::DebugDevTools() {
|
||||
if (window_->IsDevToolsOpened())
|
||||
NativeWindow::Debug(window_->GetDevToolsWebContents());
|
||||
}
|
||||
|
||||
void Window::FocusOnWebView() {
|
||||
window_->FocusOnWebView();
|
||||
}
|
||||
@@ -311,17 +316,26 @@ 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) {
|
||||
window_->SetRepresentedFilename(filename);
|
||||
}
|
||||
|
||||
std::string Window::GetRepresentedFilename() {
|
||||
return window_->GetRepresentedFilename();
|
||||
}
|
||||
|
||||
void Window::SetDocumentEdited(bool edited) {
|
||||
window_->SetDocumentEdited(edited);
|
||||
}
|
||||
|
||||
bool Window::IsDocumentEdited() {
|
||||
return window_->IsDocumentEdited();
|
||||
}
|
||||
|
||||
mate::Handle<WebContents> Window::GetWebContents(v8::Isolate* isolate) const {
|
||||
return WebContents::Create(isolate, window_->GetWebContents());
|
||||
}
|
||||
@@ -344,8 +358,10 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("isVisible", &Window::IsVisible)
|
||||
.SetMethod("maximize", &Window::Maximize)
|
||||
.SetMethod("unmaximize", &Window::Unmaximize)
|
||||
.SetMethod("isMaximized", &Window::IsMaximized)
|
||||
.SetMethod("minimize", &Window::Minimize)
|
||||
.SetMethod("restore", &Window::Restore)
|
||||
.SetMethod("isMinimized", &Window::IsMinimized)
|
||||
.SetMethod("setFullScreen", &Window::SetFullscreen)
|
||||
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
||||
.SetMethod("getSize", &Window::GetSize)
|
||||
@@ -366,15 +382,17 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setTitle", &Window::SetTitle)
|
||||
.SetMethod("getTitle", &Window::GetTitle)
|
||||
.SetMethod("flashFrame", &Window::FlashFrame)
|
||||
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
|
||||
.SetMethod("setKiosk", &Window::SetKiosk)
|
||||
.SetMethod("isKiosk", &Window::IsKiosk)
|
||||
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
|
||||
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
||||
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
||||
.SetMethod("IsDocumentEdited", &Window::IsDocumentEdited)
|
||||
.SetMethod("_openDevTools", &Window::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &Window::CloseDevTools)
|
||||
.SetMethod("isDevToolsOpened", &Window::IsDevToolsOpened)
|
||||
.SetMethod("inspectElement", &Window::InspectElement)
|
||||
.SetMethod("debugDevTools", &Window::DebugDevTools)
|
||||
.SetMethod("focusOnWebView", &Window::FocusOnWebView)
|
||||
.SetMethod("blurWebView", &Window::BlurWebView)
|
||||
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
|
||||
@@ -390,14 +408,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)
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
|
||||
class GURL;
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Arguments;
|
||||
class Dictionary;
|
||||
@@ -35,8 +31,7 @@ class WebContents;
|
||||
class Window : public mate::EventEmitter,
|
||||
public NativeWindowObserver {
|
||||
public:
|
||||
static mate::Wrappable* New(mate::Arguments* args,
|
||||
const base::DictionaryValue& options);
|
||||
static mate::Wrappable* New(const mate::Dictionary& options);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Handle<v8::ObjectTemplate> prototype);
|
||||
@@ -44,7 +39,7 @@ class Window : public mate::EventEmitter,
|
||||
NativeWindow* window() const { return window_.get(); }
|
||||
|
||||
protected:
|
||||
explicit Window(base::DictionaryValue* options);
|
||||
explicit Window(const mate::Dictionary& options);
|
||||
virtual ~Window();
|
||||
|
||||
// Implementations of NativeWindowObserver:
|
||||
@@ -68,8 +63,10 @@ class Window : public mate::EventEmitter,
|
||||
bool IsVisible();
|
||||
void Maximize();
|
||||
void Unmaximize();
|
||||
bool IsMaximized();
|
||||
void Minimize();
|
||||
void Restore();
|
||||
bool IsMinimized();
|
||||
void SetFullscreen(bool fullscreen);
|
||||
bool IsFullscreen();
|
||||
void SetSize(int width, int height);
|
||||
@@ -90,19 +87,21 @@ class Window : public mate::EventEmitter,
|
||||
void SetTitle(const std::string& title);
|
||||
std::string GetTitle();
|
||||
void FlashFrame(bool flash);
|
||||
void SetSkipTaskbar(bool skip);
|
||||
void SetKiosk(bool kiosk);
|
||||
bool IsKiosk();
|
||||
void OpenDevTools();
|
||||
void CloseDevTools();
|
||||
bool IsDevToolsOpened();
|
||||
void InspectElement(int x, int y);
|
||||
void DebugDevTools();
|
||||
void FocusOnWebView();
|
||||
void BlurWebView();
|
||||
bool IsWebViewFocused();
|
||||
void CapturePage(mate::Arguments* args);
|
||||
void SetRepresentedFilename(const std::string& filename);
|
||||
std::string GetRepresentedFilename();
|
||||
void SetDocumentEdited(bool edited);
|
||||
bool IsDocumentEdited();
|
||||
|
||||
// APIs for WebContents.
|
||||
mate::Handle<WebContents> GetWebContents(v8::Isolate* isolate) const;
|
||||
|
||||
@@ -36,7 +36,7 @@ void Event::SetSenderAndMessage(content::WebContents* sender,
|
||||
Observe(sender);
|
||||
}
|
||||
|
||||
void Event::WebContentsDestroyed(content::WebContents* web_contents) {
|
||||
void Event::WebContentsDestroyed() {
|
||||
sender_ = NULL;
|
||||
message_ = NULL;
|
||||
}
|
||||
@@ -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_; }
|
||||
@@ -40,7 +40,7 @@ class Event : public Wrappable,
|
||||
virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
|
||||
|
||||
// content::WebContentsObserver implementations:
|
||||
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
|
||||
virtual void WebContentsDestroyed() OVERRIDE;
|
||||
|
||||
private:
|
||||
// Replyer for the synchronous messages.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ if process.platform is 'darwin'
|
||||
cancelBounce: bindings.dockCancelBounce
|
||||
setBadge: bindings.dockSetBadgeText
|
||||
getBadge: bindings.dockGetBadgeText
|
||||
hide: bindings.hide
|
||||
show: bindings.show
|
||||
|
||||
# Be compatible with old API.
|
||||
app.once 'ready', -> app.emit 'finish-launching'
|
||||
|
||||
@@ -26,11 +26,17 @@ module.exports =
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
|
||||
wrappedCallback =
|
||||
if typeof callback is 'function'
|
||||
(success, result) -> callback(if success then result)
|
||||
else
|
||||
null
|
||||
|
||||
binding.showOpenDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
properties,
|
||||
window,
|
||||
(success, result) -> callback if success then result
|
||||
wrappedCallback
|
||||
|
||||
showSaveDialog: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
@@ -43,10 +49,16 @@ module.exports =
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
|
||||
wrappedCallback =
|
||||
if typeof callback is 'function'
|
||||
(success, result) -> callback(if success then result)
|
||||
else
|
||||
null
|
||||
|
||||
binding.showSaveDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
window,
|
||||
(success, result) -> callback if success then result
|
||||
wrappedCallback
|
||||
|
||||
showMessageBox: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -11,6 +11,16 @@ module.exports.wrap = (webContents) ->
|
||||
webContents.send = (args...) ->
|
||||
@_send 'ATOM_INTERNAL_MESSAGE', [args...]
|
||||
|
||||
# Make sure webContents.executeJavaScript would run the code only when the
|
||||
# web contents has been loaded.
|
||||
webContents.loaded = false
|
||||
webContents.once 'did-finish-load', -> @loaded = true
|
||||
webContents.executeJavaScript = (code) ->
|
||||
if @loaded
|
||||
@_executeJavaScript code
|
||||
else
|
||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code)
|
||||
|
||||
# The processId and routingId and identify a webContents.
|
||||
webContents.getId = -> "#{@getProcessId()}-#{@getRoutingId()}"
|
||||
webContents.equal = (other) -> @getId() is other.getId()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,18 +17,20 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
virtual ~AtomBrowserClient();
|
||||
|
||||
protected:
|
||||
// content::ContentBrowserClient:
|
||||
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:
|
||||
|
||||
@@ -7,14 +7,19 @@
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "net/proxy/proxy_resolver_v8.h"
|
||||
#include "base/command_line.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 {
|
||||
@@ -23,9 +28,9 @@ namespace atom {
|
||||
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
||||
|
||||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: atom_bindings_(new AtomBindings),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)) {
|
||||
: browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
atom_bindings_(new AtomBindings) {
|
||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||
self_ = this;
|
||||
}
|
||||
@@ -46,28 +51,26 @@ brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
|
||||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
// The ProxyResolverV8 has setup a complete V8 environment, in order to avoid
|
||||
// conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
|
||||
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(js_env_->context());
|
||||
|
||||
// Add atom-shell extended APIs.
|
||||
atom_bindings_->BindTo(global_env->process_object());
|
||||
atom_bindings_->BindTo(js_env_->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 +86,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
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace atom {
|
||||
|
||||
class AtomBindings;
|
||||
class Browser;
|
||||
class JavascriptEnvironment;
|
||||
class NodeBindings;
|
||||
|
||||
class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
@@ -29,16 +30,16 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
// 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;
|
||||
#endif
|
||||
|
||||
private:
|
||||
scoped_ptr<AtomBindings> atom_bindings_;
|
||||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<JavascriptEnvironment> js_env_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
scoped_ptr<AtomBindings> atom_bindings_;
|
||||
|
||||
static AtomBrowserMainParts* self_;
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -56,6 +56,10 @@ class Browser : public WindowListObserver {
|
||||
// Set/Get dock's badge text.
|
||||
void DockSetBadgeText(const std::string& label);
|
||||
std::string DockGetBadgeText();
|
||||
|
||||
// Hide/Show dock.
|
||||
void DockHide();
|
||||
void DockShow();
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
// Tell the application to open a file.
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
|
||||
#import "atom/browser/mac/atom_application.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#import "base/mac/bundle_locations.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#import "atom/browser/mac/atom_application.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -44,4 +46,18 @@ std::string Browser::DockGetBadgeText() {
|
||||
return base::SysNSStringToUTF8([tile badgeLabel]);
|
||||
}
|
||||
|
||||
void Browser::DockHide() {
|
||||
WindowList* list = WindowList::GetInstance();
|
||||
for (WindowList::iterator it = list->begin(); it != list->end(); ++it)
|
||||
[(*it)->GetNativeWindow() setCanHide:NO];
|
||||
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||
TransformProcessType(&psn, kProcessTransformToUIElementApplication);
|
||||
}
|
||||
|
||||
void Browser::DockShow() {
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -106,7 +106,7 @@ app.on('ready', function() {
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { mainWindow.setFullscreen(true); }
|
||||
click: function() { mainWindow.setFullScreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -30,10 +30,11 @@ if (argv._.length > 0) {
|
||||
}
|
||||
|
||||
// Run the app.
|
||||
require(packagePath);
|
||||
require('module')._load(packagePath, module, true);
|
||||
} catch(e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND') {
|
||||
app.focus();
|
||||
console.error(e.stack);
|
||||
dialog.showMessageBox({
|
||||
type: 'warning',
|
||||
buttons: ['OK'],
|
||||
|
||||
@@ -1,124 +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/devtools_delegate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/values.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/devtools_client_host.h"
|
||||
#include "content/public/browser/devtools_http_handler.h"
|
||||
#include "content/public/browser/devtools_manager.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "ui/gfx/point.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
DevToolsDelegate::DevToolsDelegate(NativeWindow* window,
|
||||
content::WebContents* target_web_contents)
|
||||
: content::WebContentsObserver(window->GetWebContents()),
|
||||
owner_window_(window),
|
||||
delegate_(NULL),
|
||||
embedder_message_dispatcher_(
|
||||
new DevToolsEmbedderMessageDispatcher(this)) {
|
||||
content::WebContents* web_contents = window->GetWebContents();
|
||||
|
||||
// Setup devtools.
|
||||
devtools_agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(
|
||||
target_web_contents->GetRenderViewHost());
|
||||
devtools_client_host_.reset(
|
||||
content::DevToolsClientHost::CreateDevToolsFrontendHost(web_contents,
|
||||
this));
|
||||
content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
|
||||
devtools_agent_host_.get(), devtools_client_host_.get());
|
||||
|
||||
// Go!
|
||||
base::DictionaryValue options;
|
||||
options.SetString("title", "DevTools Debugger");
|
||||
window->InitFromOptions(&options);
|
||||
window->AddObserver(this);
|
||||
web_contents->GetController().LoadURL(
|
||||
GURL("chrome-devtools://devtools/devtools.html?dockSide=undocked"),
|
||||
content::Referrer(),
|
||||
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
|
||||
std::string());
|
||||
}
|
||||
|
||||
DevToolsDelegate::~DevToolsDelegate() {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::DispatchOnEmbedder(const std::string& message) {
|
||||
embedder_message_dispatcher_->Dispatch(message);
|
||||
}
|
||||
|
||||
void DevToolsDelegate::InspectedContentsClosing() {
|
||||
owner_window_->Close();
|
||||
}
|
||||
|
||||
void DevToolsDelegate::AboutToNavigateRenderView(
|
||||
content::RenderViewHost* render_view_host) {
|
||||
content::DevToolsClientHost::SetupDevToolsFrontendClient(
|
||||
owner_window_->GetWebContents()->GetRenderViewHost());
|
||||
}
|
||||
|
||||
void DevToolsDelegate::OnWindowClosed() {
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, owner_window_);
|
||||
}
|
||||
|
||||
void DevToolsDelegate::ActivateWindow() {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::CloseWindow() {
|
||||
owner_window_->Close();
|
||||
}
|
||||
|
||||
void DevToolsDelegate::MoveWindow(int x, int y) {
|
||||
owner_window_->SetPosition(gfx::Point(x, y));
|
||||
}
|
||||
|
||||
void DevToolsDelegate::SetDockSide(const std::string& dock_side) {
|
||||
bool succeed = true;
|
||||
if (delegate_ &&
|
||||
delegate_->DevToolsSetDockSide("attach-back", &succeed) &&
|
||||
succeed)
|
||||
owner_window_->Close();
|
||||
}
|
||||
|
||||
void DevToolsDelegate::OpenInNewTab(const std::string& url) {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::SaveToFile(
|
||||
const std::string& url, const std::string& content, bool save_as) {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::AppendToFile(
|
||||
const std::string& url, const std::string& content) {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::RequestFileSystems() {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::AddFileSystem() {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::RemoveFileSystem(const std::string& file_system_path) {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::IndexPath(
|
||||
int request_id, const std::string& file_system_path) {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::StopIndexing(int request_id) {
|
||||
}
|
||||
|
||||
void DevToolsDelegate::SearchInPath(
|
||||
int request_id,
|
||||
const std::string& file_system_path,
|
||||
const std::string& query) {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,87 +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_DEVTOOLS_DELEGATE_H_
|
||||
#define ATOM_BROWSER_DEVTOOLS_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "atom/browser/native_window_observer.h"
|
||||
#include "content/public/browser/devtools_frontend_host_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "vendor/brightray/browser/devtools_embedder_message_dispatcher.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_delegate.h"
|
||||
|
||||
namespace content {
|
||||
class DevToolsAgentHost;
|
||||
class DevToolsClientHost;
|
||||
}
|
||||
|
||||
using brightray::DevToolsEmbedderMessageDispatcher;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindow;
|
||||
|
||||
class DevToolsDelegate : public content::DevToolsFrontendHostDelegate,
|
||||
public content::WebContentsObserver,
|
||||
public NativeWindowObserver,
|
||||
public DevToolsEmbedderMessageDispatcher::Delegate {
|
||||
public:
|
||||
DevToolsDelegate(NativeWindow* window,
|
||||
content::WebContents* target_web_contents);
|
||||
virtual ~DevToolsDelegate();
|
||||
|
||||
void SetDelegate(brightray::InspectableWebContentsDelegate* delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Implementations of content::DevToolsFrontendHostDelegate.
|
||||
virtual void DispatchOnEmbedder(const std::string& message) OVERRIDE;
|
||||
virtual void InspectedContentsClosing() OVERRIDE;
|
||||
|
||||
// Implementations of content::WebContentsObserver.
|
||||
virtual void AboutToNavigateRenderView(
|
||||
content::RenderViewHost* render_view_host) OVERRIDE;
|
||||
|
||||
// Implementations of NativeWindowObserver.
|
||||
virtual void OnWindowClosed() OVERRIDE;
|
||||
|
||||
// Implementations of DevToolsEmbedderMessageDispatcher::Delegate.
|
||||
virtual void ActivateWindow() OVERRIDE;
|
||||
virtual void CloseWindow() OVERRIDE;
|
||||
virtual void MoveWindow(int x, int y) OVERRIDE;
|
||||
virtual void SetDockSide(const std::string& dock_side) OVERRIDE;
|
||||
virtual void OpenInNewTab(const std::string& url) OVERRIDE;
|
||||
virtual void SaveToFile(const std::string& url,
|
||||
const std::string& content,
|
||||
bool save_as) OVERRIDE;
|
||||
virtual void AppendToFile(const std::string& url,
|
||||
const std::string& content) OVERRIDE;
|
||||
virtual void RequestFileSystems() OVERRIDE;
|
||||
virtual void AddFileSystem() OVERRIDE;
|
||||
virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE;
|
||||
virtual void IndexPath(int request_id,
|
||||
const std::string& file_system_path) OVERRIDE;
|
||||
virtual void StopIndexing(int request_id) OVERRIDE;
|
||||
virtual void SearchInPath(int request_id,
|
||||
const std::string& file_system_path,
|
||||
const std::string& query) OVERRIDE;
|
||||
|
||||
private:
|
||||
NativeWindow* owner_window_;
|
||||
brightray::InspectableWebContentsDelegate* delegate_;
|
||||
|
||||
scoped_refptr<content::DevToolsAgentHost> devtools_agent_host_;
|
||||
scoped_ptr<content::DevToolsClientHost> devtools_client_host_;
|
||||
scoped_ptr<DevToolsEmbedderMessageDispatcher> embedder_message_dispatcher_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DevToolsDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_DEVTOOLS_DELEGATE_H_
|
||||
17
atom/browser/javascript_environment.cc
Normal file
17
atom/browser/javascript_environment.cc
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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/javascript_environment.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
JavascriptEnvironment::JavascriptEnvironment()
|
||||
: isolate_(v8::Isolate::GetCurrent()),
|
||||
locker_(isolate_),
|
||||
handle_scope_(isolate_),
|
||||
context_(isolate_, v8::Context::New(isolate_)),
|
||||
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
34
atom/browser/javascript_environment.h
Normal file
34
atom/browser/javascript_environment.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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_JAVASCRIPT_ENVIRONMENT_H_
|
||||
#define ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class JavascriptEnvironment {
|
||||
public:
|
||||
JavascriptEnvironment();
|
||||
|
||||
v8::Isolate* isolate() const { return isolate_; }
|
||||
v8::Local<v8::Context> context() const {
|
||||
return v8::Local<v8::Context>::New(isolate_, context_);
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
v8::Locker locker_;
|
||||
v8::HandleScope handle_scope_;
|
||||
v8::UniquePersistent<v8::Context> context_;
|
||||
v8::Context::Scope context_scope_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
|
||||
@@ -1,6 +1,7 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
util = require 'util'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
module = require 'module'
|
||||
util = require 'util'
|
||||
|
||||
# Expose information of current process.
|
||||
process.type = 'browser'
|
||||
@@ -17,7 +18,7 @@ process.execArgv = process.argv.splice startMark, endMark - startMark + 1
|
||||
|
||||
# Add browser/api/lib to require's search paths,
|
||||
# which contains javascript part of Atom's built-in libraries.
|
||||
globalPaths = require('module').globalPaths
|
||||
globalPaths = module.globalPaths
|
||||
globalPaths.push path.join process.resourcesPath, 'atom', 'browser', 'api', 'lib'
|
||||
|
||||
# Do loading in next tick since we still need some initialize work before
|
||||
@@ -77,4 +78,4 @@ setImmediate ->
|
||||
app.setName packageJson.name
|
||||
|
||||
# Finally load app's main.js and transfer control to C++.
|
||||
require path.join(packagePath, packageJson.main)
|
||||
module._load path.join(packagePath, packageJson.main), module, true
|
||||
|
||||
@@ -84,7 +84,7 @@ process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
|
||||
|
||||
ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, require(module)
|
||||
event.returnValue = valueToMeta event.sender, process.mainModule.require(module)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
|
||||
@@ -11,20 +11,22 @@
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/devtools_delegate.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/json/json_writer.h"
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/invalidate_type.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
@@ -32,19 +34,22 @@
|
||||
#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"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#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;
|
||||
@@ -52,35 +57,31 @@ using content::NavigationEntry;
|
||||
namespace atom {
|
||||
|
||||
NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options)
|
||||
const mate::Dictionary& options)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
has_frame_(true),
|
||||
is_closed_(false),
|
||||
node_integration_("except-iframe"),
|
||||
has_dialog_attached_(false),
|
||||
zoom_factor_(1.0),
|
||||
weak_factory_(this),
|
||||
inspectable_web_contents_(
|
||||
brightray::InspectableWebContents::Create(web_contents)) {
|
||||
options->GetBoolean(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
|
||||
options.Get(switches::kFrame, &has_frame_);
|
||||
|
||||
// Read icon before window is created.
|
||||
std::string icon;
|
||||
if (options->GetString(switches::kIcon, &icon) && !SetIcon(icon))
|
||||
LOG(ERROR) << "Failed to set icon to " << icon;
|
||||
gfx::ImageSkia icon;
|
||||
if (options.Get(switches::kIcon, &icon))
|
||||
icon_.reset(new gfx::Image(icon));
|
||||
|
||||
// Read iframe security before any navigation.
|
||||
options->GetString(switches::kNodeIntegration, &node_integration_);
|
||||
options.Get(switches::kNodeIntegration, &node_integration_);
|
||||
|
||||
// Read the web preferences.
|
||||
base::DictionaryValue* web_preferences;
|
||||
if (options->GetDictionary(switches::kWebPreferences, &web_preferences))
|
||||
web_preferences_.reset(web_preferences->DeepCopy());
|
||||
options.Get(switches::kWebPreferences, &web_preferences_);
|
||||
|
||||
// Read the zoom factor before any navigation.
|
||||
options.Get(switches::kZoomFactor, &zoom_factor_);
|
||||
|
||||
web_contents->SetDelegate(this);
|
||||
inspectable_web_contents()->SetDelegate(this);
|
||||
@@ -90,11 +91,12 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
// Override the user agent to contain application and atom-shell's version.
|
||||
Browser* browser = Browser::Get();
|
||||
std::string product_name = base::StringPrintf(
|
||||
"%s/%s Atom-Shell/" ATOM_VERSION_STRING,
|
||||
"%s/%s Chrome/%s Atom-Shell/" ATOM_VERSION_STRING,
|
||||
browser->GetName().c_str(),
|
||||
browser->GetVersion().c_str());
|
||||
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,
|
||||
@@ -102,29 +104,17 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
}
|
||||
|
||||
NativeWindow::~NativeWindow() {
|
||||
// Make sure we have the OnRenderViewDeleted message sent even when the window
|
||||
// is destroyed directly.
|
||||
DestroyWebContents();
|
||||
|
||||
// It's possible that the windows gets destroyed before it's closed, in that
|
||||
// case we need to ensure the OnWindowClosed message is still notified.
|
||||
NotifyWindowClosed();
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(base::DictionaryValue* options) {
|
||||
NativeWindow* NativeWindow::Create(const mate::Dictionary& options) {
|
||||
content::WebContents::CreateParams create_params(AtomBrowserContext::Get());
|
||||
return Create(content::WebContents::Create(create_params), options);
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Debug(content::WebContents* web_contents) {
|
||||
base::DictionaryValue options;
|
||||
NativeWindow* window = NativeWindow::Create(&options);
|
||||
window->devtools_delegate_.reset(new DevToolsDelegate(window, web_contents));
|
||||
return window;
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::FromRenderView(int process_id, int routing_id) {
|
||||
// Stupid iterating.
|
||||
@@ -141,52 +131,55 @@ NativeWindow* NativeWindow::FromRenderView(int process_id, int routing_id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NativeWindow::InitFromOptions(base::DictionaryValue* options) {
|
||||
void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
// Setup window from options.
|
||||
int x = -1, y = -1;
|
||||
bool center;
|
||||
if (options->GetInteger(switches::kX, &x) &&
|
||||
options->GetInteger(switches::kY, &y)) {
|
||||
if (options.Get(switches::kX, &x) && options.Get(switches::kY, &y)) {
|
||||
int width = -1, height = -1;
|
||||
options->GetInteger(switches::kWidth, &width);
|
||||
options->GetInteger(switches::kHeight, &height);
|
||||
options.Get(switches::kWidth, &width);
|
||||
options.Get(switches::kHeight, &height);
|
||||
Move(gfx::Rect(x, y, width, height));
|
||||
} else if (options->GetBoolean(switches::kCenter, ¢er) && center) {
|
||||
} else if (options.Get(switches::kCenter, ¢er) && center) {
|
||||
Center();
|
||||
}
|
||||
int min_height = -1, min_width = -1;
|
||||
if (options->GetInteger(switches::kMinHeight, &min_height) &&
|
||||
options->GetInteger(switches::kMinWidth, &min_width)) {
|
||||
if (options.Get(switches::kMinHeight, &min_height) &&
|
||||
options.Get(switches::kMinWidth, &min_width)) {
|
||||
SetMinimumSize(gfx::Size(min_width, min_height));
|
||||
}
|
||||
int max_height = -1, max_width = -1;
|
||||
if (options->GetInteger(switches::kMaxHeight, &max_height) &&
|
||||
options->GetInteger(switches::kMaxWidth, &max_width)) {
|
||||
if (options.Get(switches::kMaxHeight, &max_height) &&
|
||||
options.Get(switches::kMaxWidth, &max_width)) {
|
||||
SetMaximumSize(gfx::Size(max_width, max_height));
|
||||
}
|
||||
bool resizable;
|
||||
if (options->GetBoolean(switches::kResizable, &resizable)) {
|
||||
if (options.Get(switches::kResizable, &resizable)) {
|
||||
SetResizable(resizable);
|
||||
}
|
||||
bool top;
|
||||
if (options->GetBoolean(switches::kAlwaysOnTop, &top) && top) {
|
||||
if (options.Get(switches::kAlwaysOnTop, &top) && top) {
|
||||
SetAlwaysOnTop(true);
|
||||
}
|
||||
bool fullscreen;
|
||||
if (options->GetBoolean(switches::kFullscreen, &fullscreen) && fullscreen) {
|
||||
if (options.Get(switches::kFullscreen, &fullscreen) && fullscreen) {
|
||||
SetFullscreen(true);
|
||||
}
|
||||
bool skip;
|
||||
if (options.Get(switches::kSkipTaskbar, &skip) && skip) {
|
||||
SetSkipTaskbar(skip);
|
||||
}
|
||||
bool kiosk;
|
||||
if (options->GetBoolean(switches::kKiosk, &kiosk) && kiosk) {
|
||||
if (options.Get(switches::kKiosk, &kiosk) && kiosk) {
|
||||
SetKiosk(kiosk);
|
||||
}
|
||||
std::string title("Atom Shell");
|
||||
options->GetString(switches::kTitle, &title);
|
||||
options.Get(switches::kTitle, &title);
|
||||
SetTitle(title);
|
||||
|
||||
// Then show it.
|
||||
bool show = true;
|
||||
options->GetBoolean(switches::kShow, &show);
|
||||
options.Get(switches::kShow, &show);
|
||||
if (show)
|
||||
Show();
|
||||
}
|
||||
@@ -194,36 +187,34 @@ void NativeWindow::InitFromOptions(base::DictionaryValue* options) {
|
||||
void NativeWindow::SetRepresentedFilename(const std::string& filename) {
|
||||
}
|
||||
|
||||
std::string NativeWindow::GetRepresentedFilename() {
|
||||
return "";
|
||||
}
|
||||
|
||||
void NativeWindow::SetDocumentEdited(bool edited) {
|
||||
}
|
||||
|
||||
void NativeWindow::SetMenu(ui::MenuModel* menu) {
|
||||
}
|
||||
|
||||
bool NativeWindow::IsDocumentEdited() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeWindow::HasModalDialog() {
|
||||
return has_dialog_attached_;
|
||||
}
|
||||
|
||||
void NativeWindow::OpenDevTools() {
|
||||
if (devtools_window_) {
|
||||
devtools_window_->Focus(true);
|
||||
} else {
|
||||
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
|
||||
}
|
||||
inspectable_web_contents()->ShowDevTools();
|
||||
}
|
||||
|
||||
void NativeWindow::CloseDevTools() {
|
||||
if (devtools_window_)
|
||||
devtools_window_->Close();
|
||||
else
|
||||
inspectable_web_contents()->CloseDevTools();
|
||||
inspectable_web_contents()->CloseDevTools();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsDevToolsOpened() {
|
||||
return (devtools_window_ && devtools_window_->IsFocused()) ||
|
||||
inspectable_web_contents()->IsDevToolsViewShowing();
|
||||
return inspectable_web_contents()->IsDevToolsViewShowing();
|
||||
}
|
||||
|
||||
void NativeWindow::InspectElement(int x, int y) {
|
||||
@@ -248,30 +239,6 @@ bool NativeWindow::IsWebViewFocused() {
|
||||
return host_view && host_view->HasFocus();
|
||||
}
|
||||
|
||||
bool NativeWindow::SetIcon(const std::string& str_path) {
|
||||
base::FilePath path = base::FilePath::FromUTF8Unsafe(str_path);
|
||||
|
||||
// Read the file from disk.
|
||||
std::string file_contents;
|
||||
if (path.empty() || !base::ReadFileToString(path, &file_contents))
|
||||
return false;
|
||||
|
||||
// Decode the bitmap using WebKit's image decoder.
|
||||
const unsigned char* data =
|
||||
reinterpret_cast<const unsigned char*>(file_contents.data());
|
||||
scoped_ptr<SkBitmap> decoded(new SkBitmap());
|
||||
gfx::PNGCodec::Decode(data, file_contents.length(), decoded.get());
|
||||
if (decoded->empty())
|
||||
return false; // Unable to decode.
|
||||
|
||||
icon_ = gfx::Image::CreateFrom1xBitmap(*decoded.release());
|
||||
return true;
|
||||
}
|
||||
|
||||
base::ProcessHandle NativeWindow::GetRenderProcessHandle() {
|
||||
return GetWebContents()->GetRenderProcessHost()->GetHandle();
|
||||
}
|
||||
|
||||
void NativeWindow::CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback) {
|
||||
content::RenderViewHost* render_view_host =
|
||||
@@ -298,7 +265,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() {
|
||||
@@ -332,7 +300,7 @@ void NativeWindow::CloseWebContents() {
|
||||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
if (web_contents->NeedToFireBeforeUnload())
|
||||
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
|
||||
web_contents->DispatchBeforeUnload(false);
|
||||
else
|
||||
web_contents->Close();
|
||||
}
|
||||
@@ -349,48 +317,45 @@ 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_);
|
||||
|
||||
// Append --zoom-factor.
|
||||
if (zoom_factor_ != 1.0)
|
||||
command_line->AppendSwitchASCII(switches::kZoomFactor,
|
||||
base::DoubleToString(zoom_factor_));
|
||||
}
|
||||
|
||||
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;
|
||||
base::ListValue* list;
|
||||
if (!web_preferences_)
|
||||
return;
|
||||
if (web_preferences_->GetBoolean("javascript", &b))
|
||||
std::vector<base::FilePath> list;
|
||||
mate::Dictionary web_preferences(web_preferences_.isolate(),
|
||||
web_preferences_.NewHandle());
|
||||
if (web_preferences.Get("javascript", &b))
|
||||
prefs->javascript_enabled = b;
|
||||
if (web_preferences_->GetBoolean("web-security", &b))
|
||||
if (web_preferences.Get("web-security", &b))
|
||||
prefs->web_security_enabled = b;
|
||||
if (web_preferences_->GetBoolean("images", &b))
|
||||
if (web_preferences.Get("images", &b))
|
||||
prefs->images_enabled = b;
|
||||
if (web_preferences_->GetBoolean("java", &b))
|
||||
if (web_preferences.Get("java", &b))
|
||||
prefs->java_enabled = b;
|
||||
if (web_preferences_->GetBoolean("text-areas-are-resizable", &b))
|
||||
if (web_preferences.Get("text-areas-are-resizable", &b))
|
||||
prefs->text_areas_are_resizable = b;
|
||||
if (web_preferences_->GetBoolean("webgl", &b))
|
||||
if (web_preferences.Get("webgl", &b))
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (web_preferences_->GetBoolean("webaudio", &b))
|
||||
if (web_preferences.Get("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (web_preferences_->GetBoolean("accelerated-compositing", &b))
|
||||
prefs->accelerated_compositing_enabled = b;
|
||||
if (web_preferences_->GetBoolean("plugins", &b))
|
||||
if (web_preferences.Get("plugins", &b))
|
||||
prefs->plugins_enabled = b;
|
||||
if (web_preferences_->GetList("extra-plugin-dirs", &list))
|
||||
for (size_t i = 0; i < list->GetSize(); ++i) {
|
||||
base::FilePath::StringType path_string;
|
||||
if (list->GetString(i, &path_string)) {
|
||||
base::FilePath path(path_string);
|
||||
content::PluginService::GetInstance()->AddExtraPluginDir(path);
|
||||
}
|
||||
}
|
||||
if (web_preferences.Get("extra-plugin-dirs", &list))
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
content::PluginService::GetInstance()->AddExtraPluginDir(list[i]);
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowClosed() {
|
||||
@@ -484,9 +449,6 @@ void NativeWindow::MoveContents(content::WebContents* source,
|
||||
}
|
||||
|
||||
void NativeWindow::CloseContents(content::WebContents* source) {
|
||||
// Destroy the WebContents before we close the window.
|
||||
DestroyWebContents();
|
||||
|
||||
// When the web contents is gone, close the window immediately, but the
|
||||
// memory will not be freed until you call delete.
|
||||
// In this way, it would be safe to manage windows via smart pointers. If you
|
||||
@@ -544,7 +506,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));
|
||||
@@ -555,22 +517,6 @@ void NativeWindow::Observe(int type,
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeWindow::DevToolsSetDockSide(const std::string& dock_side,
|
||||
bool* succeed) {
|
||||
if (dock_side == "undocked") {
|
||||
*succeed = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeWindow::DevToolsShow(std::string* dock_side) {
|
||||
if (*dock_side == "undocked")
|
||||
*dock_side = "bottom";
|
||||
return false;
|
||||
}
|
||||
|
||||
void NativeWindow::DevToolsSaveToFile(const std::string& url,
|
||||
const std::string& content,
|
||||
bool save_as) {
|
||||
@@ -580,19 +526,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,
|
||||
@@ -600,7 +546,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);
|
||||
@@ -656,8 +602,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,19 +16,18 @@
|
||||
#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 "ui/gfx/image/image.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 DictionaryValue;
|
||||
class ListValue;
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
@@ -37,15 +36,23 @@ class WebContents;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class Image;
|
||||
class Point;
|
||||
class Rect;
|
||||
class Size;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
class DevToolsDelegate;
|
||||
struct DraggableRegion;
|
||||
|
||||
class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
@@ -80,20 +87,16 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// Create window with existing WebContents, the caller is responsible for
|
||||
// managing the window's live.
|
||||
static NativeWindow* Create(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
const mate::Dictionary& options);
|
||||
|
||||
// Create window with new WebContents, the caller is responsible for
|
||||
// managing the window's live.
|
||||
static NativeWindow* Create(base::DictionaryValue* options);
|
||||
|
||||
// Creates a devtools window to debug the WebContents, the returned window
|
||||
// will manage its own life.
|
||||
static NativeWindow* Debug(content::WebContents* web_contents);
|
||||
static NativeWindow* Create(const mate::Dictionary& options);
|
||||
|
||||
// Find a window from its process id and routing id.
|
||||
static NativeWindow* FromRenderView(int process_id, int routing_id);
|
||||
|
||||
void InitFromOptions(base::DictionaryValue* options);
|
||||
void InitFromOptions(const mate::Dictionary& options);
|
||||
|
||||
virtual void Close() = 0;
|
||||
virtual void CloseImmediately() = 0;
|
||||
@@ -105,8 +108,10 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual bool IsVisible() = 0;
|
||||
virtual void Maximize() = 0;
|
||||
virtual void Unmaximize() = 0;
|
||||
virtual bool IsMaximized() = 0;
|
||||
virtual void Minimize() = 0;
|
||||
virtual void Restore() = 0;
|
||||
virtual bool IsMinimized() = 0;
|
||||
virtual void SetFullscreen(bool fullscreen) = 0;
|
||||
virtual bool IsFullscreen() = 0;
|
||||
virtual void SetSize(const gfx::Size& size) = 0;
|
||||
@@ -127,10 +132,14 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual void SetTitle(const std::string& title) = 0;
|
||||
virtual std::string GetTitle() = 0;
|
||||
virtual void FlashFrame(bool flash) = 0;
|
||||
virtual void SetSkipTaskbar(bool skip) = 0;
|
||||
virtual void SetKiosk(bool kiosk) = 0;
|
||||
virtual bool IsKiosk() = 0;
|
||||
virtual void SetRepresentedFilename(const std::string& filename);
|
||||
virtual std::string GetRepresentedFilename();
|
||||
virtual void SetDocumentEdited(bool edited);
|
||||
virtual void SetMenu(ui::MenuModel* menu);
|
||||
virtual bool IsDocumentEdited();
|
||||
virtual bool HasModalDialog();
|
||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||
|
||||
@@ -144,12 +153,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual void BlurWebView();
|
||||
virtual bool IsWebViewFocused();
|
||||
|
||||
virtual bool SetIcon(const std::string& path);
|
||||
|
||||
// Returns the process handle of render process, useful for killing the
|
||||
// render process manually
|
||||
virtual base::ProcessHandle GetRenderProcessHandle();
|
||||
|
||||
// Captures the page with |rect|, |callback| would be called when capturing is
|
||||
// done.
|
||||
virtual void CapturePage(const gfx::Rect& rect,
|
||||
@@ -171,7 +174,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);
|
||||
|
||||
@@ -197,7 +200,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
|
||||
protected:
|
||||
explicit NativeWindow(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
const mate::Dictionary& options);
|
||||
|
||||
brightray::InspectableWebContentsImpl* inspectable_web_contents() const {
|
||||
return static_cast<brightray::InspectableWebContentsImpl*>(
|
||||
@@ -241,9 +244,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
const content::NotificationDetails& details) OVERRIDE;
|
||||
|
||||
// Implementations of brightray::InspectableWebContentsDelegate.
|
||||
virtual bool DevToolsSetDockSide(const std::string& dock_side,
|
||||
bool* succeed) OVERRIDE;
|
||||
virtual bool DevToolsShow(std::string* dock_side) OVERRIDE;
|
||||
virtual void DevToolsSaveToFile(const std::string& url,
|
||||
const std::string& content,
|
||||
bool save_as) OVERRIDE;
|
||||
@@ -254,7 +254,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
bool has_frame_;
|
||||
|
||||
// Window icon.
|
||||
gfx::Image icon_;
|
||||
scoped_ptr<gfx::Image> icon_;
|
||||
|
||||
private:
|
||||
// Schedule a notification unresponsive event.
|
||||
@@ -293,14 +293,14 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// it should be cancelled when we can prove that the window is responsive.
|
||||
base::CancelableClosure window_unresposive_closure_;
|
||||
|
||||
// web preferences.
|
||||
scoped_ptr<base::DictionaryValue> web_preferences_;
|
||||
// Web preferences.
|
||||
mate::ScopedPersistent<v8::Object> web_preferences_;
|
||||
|
||||
// Page's default zoom factor.
|
||||
double zoom_factor_;
|
||||
|
||||
base::WeakPtrFactory<NativeWindow> weak_factory_;
|
||||
|
||||
base::WeakPtr<NativeWindow> devtools_window_;
|
||||
scoped_ptr<DevToolsDelegate> devtools_delegate_;
|
||||
|
||||
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
|
||||
|
||||
// Notice that inspectable_web_contents_ must be placed after dialog_manager_,
|
||||
|
||||
@@ -1,610 +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 "base/values.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 "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/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,
|
||||
base::DictionaryValue* 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->GetInteger(switches::kWidth, &width);
|
||||
options->GetInteger(switches::kHeight, &height);
|
||||
|
||||
bool use_content_size = false;
|
||||
options->GetBoolean(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_.IsEmpty())
|
||||
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::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,
|
||||
base::DictionaryValue* options) {
|
||||
return new NativeWindowGtk(web_contents, options);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,156 +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,
|
||||
base::DictionaryValue* options);
|
||||
virtual ~NativeWindowGtk();
|
||||
|
||||
// NativeWindow implementation.
|
||||
virtual void Close() OVERRIDE;
|
||||
virtual void CloseImmediately() OVERRIDE;
|
||||
virtual void Move(const gfx::Rect& pos) OVERRIDE;
|
||||
virtual void Focus(bool focus) OVERRIDE;
|
||||
virtual bool IsFocused() OVERRIDE;
|
||||
virtual void Show() OVERRIDE;
|
||||
virtual void Hide() OVERRIDE;
|
||||
virtual bool IsVisible() OVERRIDE;
|
||||
virtual void Maximize() OVERRIDE;
|
||||
virtual void Unmaximize() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
virtual void Restore() OVERRIDE;
|
||||
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
|
||||
virtual bool IsFullscreen() OVERRIDE;
|
||||
virtual void SetSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetSize() OVERRIDE;
|
||||
virtual void SetContentSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetContentSize() OVERRIDE;
|
||||
virtual void SetMinimumSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE;
|
||||
virtual void SetMaximumSize(const gfx::Size& size) OVERRIDE;
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE;
|
||||
virtual void SetResizable(bool resizable) OVERRIDE;
|
||||
virtual bool IsResizable() OVERRIDE;
|
||||
virtual void SetAlwaysOnTop(bool top) OVERRIDE;
|
||||
virtual bool IsAlwaysOnTop() OVERRIDE;
|
||||
virtual void Center() OVERRIDE;
|
||||
virtual void SetPosition(const gfx::Point& position) OVERRIDE;
|
||||
virtual gfx::Point GetPosition() OVERRIDE;
|
||||
virtual void SetTitle(const std::string& title) OVERRIDE;
|
||||
virtual std::string GetTitle() OVERRIDE;
|
||||
virtual void FlashFrame(bool flash) OVERRIDE;
|
||||
virtual void SetKiosk(bool kiosk) OVERRIDE;
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
// Set the native window menu.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
|
||||
protected:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Overridden from content::WebContentsDelegate:
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) OVERRIDE;
|
||||
|
||||
// Overridden from ActiveWindowWatcherXObserver.
|
||||
virtual void ActiveWindowChanged(GdkWindow* active_window) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Register accelerators supported by the menu model.
|
||||
void RegisterAccelerators();
|
||||
|
||||
// Set WebKit's style from current theme.
|
||||
void SetWebKitColorStyle();
|
||||
|
||||
// Set how font is renderered.
|
||||
void SetFontRenderering();
|
||||
|
||||
// Whether window is maximized.
|
||||
bool IsMaximized() const;
|
||||
|
||||
// If the point (|x|, |y|) is within the resize border area of the window,
|
||||
// returns true and sets |edge| to the appropriate GdkWindowEdge value.
|
||||
// Otherwise, returns false.
|
||||
bool GetWindowEdge(int x, int y, GdkWindowEdge* edge);
|
||||
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowDeleteEvent,
|
||||
GdkEvent*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusIn, GdkEventFocus*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusOut, GdkEventFocus*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowState,
|
||||
GdkEventWindowState*);
|
||||
|
||||
// Mouse move and mouse button press callbacks.
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnMouseMoveEvent,
|
||||
GdkEventMotion*);
|
||||
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnButtonPress,
|
||||
GdkEventButton*);
|
||||
|
||||
GtkWindow* window_;
|
||||
GtkWidget* vbox_;
|
||||
|
||||
GdkWindowState state_;
|
||||
bool is_always_on_top_;
|
||||
gfx::Size minimum_size_;
|
||||
gfx::Size maximum_size_;
|
||||
|
||||
// The region is treated as title bar, can be dragged to move and double
|
||||
// clicked to maximize.
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
// True if the window manager thinks the window is active. It could happpen
|
||||
// that the WM thinks a window is active but it's actually not, like when
|
||||
// showing a context menu.
|
||||
bool is_active_;
|
||||
|
||||
// If true, don't call gdk_window_raise() when we get a click in the title
|
||||
// bar or window border. This is to work around a compiz bug.
|
||||
bool suppress_window_raise_;
|
||||
|
||||
// True if the window has been visible for once, on Linux the window frame
|
||||
// would // only be considered as part of the window untill the window has
|
||||
// been shown, so we need it to correctly set the window size.
|
||||
bool has_ever_been_shown_;
|
||||
|
||||
// The current window cursor. We set it to a resize cursor when over the
|
||||
// custom frame border. We set it to NULL if we want the default cursor.
|
||||
GdkCursor* frame_cursor_;
|
||||
|
||||
// The window menu.
|
||||
scoped_ptr<MenuGtk> menu_;
|
||||
|
||||
// Map from accelerator to menu item's command id.
|
||||
accelerator_util::AcceleratorTable accelerator_table_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowGtk);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
|
||||
@@ -18,7 +18,7 @@ namespace atom {
|
||||
class NativeWindowMac : public NativeWindow {
|
||||
public:
|
||||
explicit NativeWindowMac(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
const mate::Dictionary& options);
|
||||
virtual ~NativeWindowMac();
|
||||
|
||||
// NativeWindow implementation.
|
||||
@@ -32,8 +32,10 @@ class NativeWindowMac : public NativeWindow {
|
||||
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 bool IsMinimized() OVERRIDE;
|
||||
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
|
||||
virtual bool IsFullscreen() OVERRIDE;
|
||||
virtual void SetSize(const gfx::Size& size) OVERRIDE;
|
||||
@@ -54,10 +56,13 @@ class NativeWindowMac : public NativeWindow {
|
||||
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 void SetRepresentedFilename(const std::string& filename) OVERRIDE;
|
||||
virtual std::string GetRepresentedFilename() OVERRIDE;
|
||||
virtual void SetDocumentEdited(bool edited) OVERRIDE;
|
||||
virtual bool IsDocumentEdited() OVERRIDE;
|
||||
virtual bool HasModalDialog() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
@@ -95,6 +100,9 @@ class NativeWindowMac : public NativeWindow {
|
||||
|
||||
NSInteger attention_request_id_; // identifier from requestUserAttention
|
||||
|
||||
// The presentation options before entering kiosk mode.
|
||||
NSApplicationPresentationOptions kiosk_options_;
|
||||
|
||||
// For system drag, the whole window is draggable and the non-draggable areas
|
||||
// have to been explicitly excluded.
|
||||
std::vector<gfx::Rect> system_drag_exclude_areas_;
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/values.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/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_view.h"
|
||||
|
||||
@@ -50,10 +50,30 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
|
||||
- (void)windowDidBecomeMain:(NSNotification*)notification {
|
||||
shell_->NotifyWindowFocus();
|
||||
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
web_contents->RestoreFocus();
|
||||
|
||||
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
|
||||
if (rwhv)
|
||||
rwhv->SetActive(true);
|
||||
}
|
||||
|
||||
- (void)windowDidResignMain:(NSNotification*)notification {
|
||||
shell_->NotifyWindowBlur();
|
||||
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
web_contents->StoreFocus();
|
||||
|
||||
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
|
||||
if (rwhv)
|
||||
rwhv->SetActive(false);
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)otification {
|
||||
@@ -148,13 +168,13 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
namespace atom {
|
||||
|
||||
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options)
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
is_kiosk_(false),
|
||||
attention_request_id_(0) {
|
||||
int width = 800, height = 600;
|
||||
options->GetInteger(switches::kWidth, &width);
|
||||
options->GetInteger(switches::kHeight, &height);
|
||||
options.Get(switches::kWidth, &width);
|
||||
options.Get(switches::kHeight, &height);
|
||||
|
||||
NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
|
||||
NSRect cocoa_bounds = NSMakeRect(
|
||||
@@ -185,18 +205,18 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
|
||||
// On OS X the initial window size doesn't include window frame.
|
||||
bool use_content_size = false;
|
||||
options->GetBoolean(switches::kUseContentSize, &use_content_size);
|
||||
options.Get(switches::kUseContentSize, &use_content_size);
|
||||
if (has_frame_ && !use_content_size)
|
||||
SetSize(gfx::Size(width, height));
|
||||
|
||||
// Enable the NSView to accept first mouse event.
|
||||
bool acceptsFirstMouse = false;
|
||||
options->GetBoolean(switches::kAcceptFirstMouse, &acceptsFirstMouse);
|
||||
options.Get(switches::kAcceptFirstMouse, &acceptsFirstMouse);
|
||||
[delegate setAcceptsFirstMouse:acceptsFirstMouse];
|
||||
|
||||
// Disable fullscreen button when 'fullscreen' is specified to false.
|
||||
bool fullscreen;
|
||||
if (!(options->GetBoolean(switches::kFullscreen, &fullscreen) &&
|
||||
if (!(options.Get(switches::kFullscreen, &fullscreen) &&
|
||||
!fullscreen)) {
|
||||
NSUInteger collectionBehavior = [window_ collectionBehavior];
|
||||
collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
@@ -221,6 +241,7 @@ void NativeWindowMac::Close() {
|
||||
|
||||
void NativeWindowMac::CloseImmediately() {
|
||||
[window_ close];
|
||||
window_.reset();
|
||||
}
|
||||
|
||||
void NativeWindowMac::Move(const gfx::Rect& pos) {
|
||||
@@ -271,6 +292,10 @@ void NativeWindowMac::Unmaximize() {
|
||||
[window_ zoom:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsMaximized() {
|
||||
return [window_ isZoomed];
|
||||
}
|
||||
|
||||
void NativeWindowMac::Minimize() {
|
||||
[window_ miniaturize:nil];
|
||||
}
|
||||
@@ -279,6 +304,10 @@ void NativeWindowMac::Restore() {
|
||||
[window_ deminiaturize:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsMinimized() {
|
||||
return [window_ isMiniaturized];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetFullscreen(bool fullscreen) {
|
||||
if (fullscreen == IsFullscreen())
|
||||
return;
|
||||
@@ -408,8 +437,12 @@ void NativeWindowMac::FlashFrame(bool flash) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetSkipTaskbar(bool skip) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetKiosk(bool kiosk) {
|
||||
if (kiosk) {
|
||||
if (kiosk && !is_kiosk_) {
|
||||
kiosk_options_ = [NSApp currentSystemPresentationOptions];
|
||||
NSApplicationPresentationOptions options =
|
||||
NSApplicationPresentationHideDock +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
@@ -421,10 +454,10 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
|
||||
[NSApp setPresentationOptions:options];
|
||||
is_kiosk_ = true;
|
||||
SetFullscreen(true);
|
||||
} else {
|
||||
[NSApp setPresentationOptions:[NSApp currentSystemPresentationOptions]];
|
||||
is_kiosk_ = false;
|
||||
} else if (!kiosk && is_kiosk_) {
|
||||
is_kiosk_ = false;
|
||||
SetFullscreen(false);
|
||||
[NSApp setPresentationOptions:kiosk_options_];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,10 +469,18 @@ void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
|
||||
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
|
||||
std::string NativeWindowMac::GetRepresentedFilename() {
|
||||
return base::SysNSStringToUTF8([window_ representedFilename]);
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetDocumentEdited(bool edited) {
|
||||
[window_ setDocumentEdited:edited];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsDocumentEdited() {
|
||||
return [window_ isDocumentEdited];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::HasModalDialog() {
|
||||
return [window_ attachedSheet] != nil;
|
||||
}
|
||||
@@ -451,7 +492,7 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
return false;
|
||||
NSView* webView = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* webView = GetWebContents()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
@@ -492,15 +533,32 @@ void NativeWindowMac::HandleKeyboardEvent(
|
||||
event.type == content::NativeWebKeyboardEvent::Char)
|
||||
return;
|
||||
|
||||
EventProcessingWindow* event_window =
|
||||
static_cast<EventProcessingWindow*>(window_);
|
||||
DCHECK([event_window isKindOfClass:[EventProcessingWindow class]]);
|
||||
[event_window redispatchKeyEvent:event.os_event];
|
||||
if (event.os_event.window == window_) {
|
||||
EventProcessingWindow* event_window =
|
||||
static_cast<EventProcessingWindow*>(window_);
|
||||
DCHECK([event_window isKindOfClass:[EventProcessingWindow class]]);
|
||||
[event_window redispatchKeyEvent:event.os_event];
|
||||
} else {
|
||||
// The event comes from detached devtools view, and it has already been
|
||||
// handled by the devtools itself, we now send it to application menu to
|
||||
// make menu acclerators work.
|
||||
BOOL handled = [[NSApp mainMenu] performKeyEquivalent:event.os_event];
|
||||
// Handle the cmd+~ shortcut.
|
||||
if (!handled && (event.os_event.modifierFlags & NSCommandKeyMask) &&
|
||||
(event.os_event.keyCode == 50 /* ~ key */))
|
||||
Focus(true);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -523,7 +581,7 @@ void NativeWindowMac::UninstallView() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::ClipWebView() {
|
||||
NSView* view = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* view = GetWebContents()->GetNativeView();
|
||||
|
||||
view.wantsLayer = YES;
|
||||
view.layer.masksToBounds = YES;
|
||||
@@ -536,7 +594,7 @@ void NativeWindowMac::InstallDraggableRegionViews() {
|
||||
// All ControlRegionViews should be added as children of the WebContentsView,
|
||||
// because WebContentsView will be removed and re-added when entering and
|
||||
// leaving fullscreen mode.
|
||||
NSView* webView = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* webView = GetWebContents()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
|
||||
// Remove all ControlRegionViews that are added last time.
|
||||
@@ -568,7 +626,7 @@ void NativeWindowMac::UpdateDraggableRegionsForCustomDrag(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// We still need one ControlRegionView to cover the whole window such that
|
||||
// mouse events could be captured.
|
||||
NSView* web_view = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* web_view = GetWebContents()->GetNativeView();
|
||||
gfx::Rect window_bounds(
|
||||
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
|
||||
system_drag_exclude_areas_.clear();
|
||||
@@ -593,7 +651,7 @@ void NativeWindowMac::UpdateDraggableRegionsForCustomDrag(
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options) {
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowMac(web_contents, options);
|
||||
}
|
||||
|
||||
|
||||
541
atom/browser/native_window_views.cc
Normal file
541
atom/browser/native_window_views.cc
Normal file
@@ -0,0 +1,541 @@
|
||||
// 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
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/Xlib.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 "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/frameless_view.h"
|
||||
#include "ui/gfx/x/x11_types.h"
|
||||
#include "ui/views/window/native_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.
|
||||
#if defined(OS_WIN)
|
||||
const int kMenuBarHeight = 20;
|
||||
#else
|
||||
const int kMenuBarHeight = 25;
|
||||
#endif
|
||||
|
||||
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;
|
||||
params.remove_standard_frame = !has_frame_;
|
||||
|
||||
#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_->UpdateWindowIcon();
|
||||
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();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsMinimized() {
|
||||
return window_->IsMinimized();
|
||||
}
|
||||
|
||||
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() {
|
||||
#if defined(OS_WIN)
|
||||
if (IsMinimized())
|
||||
return window_->GetRestoredBounds().size();
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
#if defined(USE_X11)
|
||||
XSizeHints size_hints;
|
||||
size_hints.flags = PMinSize;
|
||||
size_hints.min_width = size.width();
|
||||
size_hints.min_height = size.height();
|
||||
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
return minimum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
|
||||
maximum_size_ = size;
|
||||
|
||||
#if defined(USE_X11)
|
||||
XSizeHints size_hints;
|
||||
size_hints.flags = PMaxSize;
|
||||
size_hints.max_width = size.width();
|
||||
size_hints.max_height = size.height();
|
||||
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
return maximum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetResizable(bool resizable) {
|
||||
resizable_ = resizable;
|
||||
// FIXME Implement me for X11.
|
||||
}
|
||||
|
||||
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() {
|
||||
#if defined(OS_WIN)
|
||||
if (IsMinimized())
|
||||
return window_->GetRestoredBounds().origin();
|
||||
#endif
|
||||
|
||||
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(OS_WIN)
|
||||
WinFrameView* frame_view = new WinFrameView;
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
#elif defined(OS_LINUX)
|
||||
if (has_frame_) {
|
||||
return new views::NativeFrameView(widget);
|
||||
} else {
|
||||
FramelessView* frame_view = new FramelessView;
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
#include "ui/views/widget/widget_observer.h"
|
||||
|
||||
namespace views {
|
||||
class WebView;
|
||||
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,
|
||||
base::DictionaryValue* 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;
|
||||
@@ -49,8 +43,10 @@ class NativeWindowWin : public NativeWindow,
|
||||
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 bool IsMinimized() OVERRIDE;
|
||||
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
|
||||
virtual bool IsFullscreen() OVERRIDE;
|
||||
virtual void SetSize(const gfx::Size& size) OVERRIDE;
|
||||
@@ -71,85 +67,85 @@ class NativeWindowWin : public NativeWindow,
|
||||
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 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(); }
|
||||
|
||||
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::WebView* 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,618 +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 <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/values.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 "ui/gfx/path.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/views/controls/webview/webview.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,
|
||||
base::DictionaryValue* options)
|
||||
: NativeWindow(web_contents, options),
|
||||
window_(new views::Widget),
|
||||
web_view_(new views::WebView(NULL)),
|
||||
use_content_size_(false),
|
||||
resizable_(true) {
|
||||
options->GetBoolean(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->GetInteger(switches::kWidth, &width);
|
||||
options->GetInteger(switches::kHeight, &height);
|
||||
|
||||
gfx::Size size(width, height);
|
||||
options->GetBoolean(switches::kUseContentSize, &use_content_size_);
|
||||
if (has_frame_ && use_content_size_)
|
||||
ClientAreaSizeToWindowSize(&size);
|
||||
|
||||
window_->CenterWindow(size);
|
||||
window_->UpdateWindowIcon();
|
||||
|
||||
web_view_->SetWebContents(web_contents);
|
||||
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::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::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 web_view_;
|
||||
}
|
||||
|
||||
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_.IsEmpty())
|
||||
return gfx::ImageSkia();
|
||||
else
|
||||
return *icon_.ToImageSkia();
|
||||
}
|
||||
|
||||
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,
|
||||
base::DictionaryValue* 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_);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.13.0</string>
|
||||
<string>0.15.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,13,0,0
|
||||
PRODUCTVERSION 0,13,0,0
|
||||
FILEVERSION 0,15,0,0
|
||||
PRODUCTVERSION 0,15,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Atom-Shell"
|
||||
VALUE "FileVersion", "0.13.0"
|
||||
VALUE "FileVersion", "0.15.0"
|
||||
VALUE "InternalName", "atom.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "atom.exe"
|
||||
VALUE "ProductName", "Atom-Shell"
|
||||
VALUE "ProductVersion", "0.13.0"
|
||||
VALUE "ProductVersion", "0.15.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -87,7 +87,7 @@ ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
|
||||
|
||||
bool StringToAccelerator(const std::string& description,
|
||||
ui::Accelerator* accelerator) {
|
||||
if (!IsStringASCII(description)) {
|
||||
if (!base::IsStringASCII(description)) {
|
||||
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
|
||||
return false;
|
||||
}
|
||||
@@ -129,6 +129,8 @@ bool StringToAccelerator(const std::string& description,
|
||||
key = ui::VKEY_BACK;
|
||||
} else if (tokens[i] == "delete") {
|
||||
key = ui::VKEY_DELETE;
|
||||
} else if (tokens[i] == "insert") {
|
||||
key = ui::VKEY_INSERT;
|
||||
} else if (tokens[i] == "enter" || tokens[i] == "return") {
|
||||
key = ui::VKEY_RETURN;
|
||||
} else if (tokens[i] == "up") {
|
||||
@@ -147,7 +149,7 @@ bool StringToAccelerator(const std::string& description,
|
||||
key = ui::VKEY_PRIOR;
|
||||
} else if (tokens[i] == "pageup") {
|
||||
key = ui::VKEY_NEXT;
|
||||
} else if (tokens[i] == "esc") {
|
||||
} else if (tokens[i] == "esc" || tokens[i] == "escape") {
|
||||
key = ui::VKEY_ESCAPE;
|
||||
} else if (tokens[i] == "volumemute") {
|
||||
key = ui::VKEY_VOLUME_MUTE;
|
||||
|
||||
@@ -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,36 +4,71 @@
|
||||
|
||||
#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,
|
||||
atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path) {
|
||||
const base::FilePath& default_path)
|
||||
: dialog_scope_(new atom::NativeWindow::DialogScope(parent_window)) {
|
||||
const char* confirm_text = GTK_STOCK_OK;
|
||||
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
confirm_text = GTK_STOCK_SAVE;
|
||||
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_),
|
||||
@@ -41,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()) {
|
||||
@@ -109,6 +140,8 @@ class FileChooserDialog {
|
||||
SaveDialogCallback save_callback_;
|
||||
OpenDialogCallback open_callback_;
|
||||
|
||||
scoped_ptr<atom::NativeWindow::DialogScope> dialog_scope_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FileChooserDialog);
|
||||
};
|
||||
|
||||
|
||||
@@ -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,258 +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);
|
||||
// if (gtk_menu_)
|
||||
// DestroyMenu();
|
||||
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) {
|
||||
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,132 +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) {
|
||||
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_;
|
||||
|
||||
// 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,22 @@
|
||||
#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"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -26,8 +34,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 +48,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 +59,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 +79,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 +123,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 +157,43 @@ 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;
|
||||
}
|
||||
|
||||
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 +212,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 +236,32 @@ 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_) {
|
||||
#if defined(USE_X11)
|
||||
return new views::NativeFrameView(widget);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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 +326,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();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "atom/browser/ui/cocoa/atom_menu_controller.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
@interface StatusItemController : NSObject {
|
||||
atom::TrayIconCocoa* trayIcon_; // weak
|
||||
@@ -50,17 +50,17 @@ TrayIconCocoa::~TrayIconCocoa() {
|
||||
|
||||
void TrayIconCocoa::SetImage(const gfx::ImageSkia& image) {
|
||||
if (!image.isNull()) {
|
||||
NSImage* ns_image = gfx::SkBitmapToNSImage(*image.bitmap());
|
||||
if (ns_image)
|
||||
[item_ setImage:ns_image];
|
||||
gfx::Image neutral(image);
|
||||
if (!neutral.IsEmpty())
|
||||
[item_ setImage:neutral.ToNSImage()];
|
||||
}
|
||||
}
|
||||
|
||||
void TrayIconCocoa::SetPressedImage(const gfx::ImageSkia& image) {
|
||||
if (!image.isNull()) {
|
||||
NSImage* ns_image = gfx::SkBitmapToNSImage(*image.bitmap());
|
||||
if (ns_image)
|
||||
[item_ setAlternateImage:ns_image];
|
||||
gfx::Image neutral(image);
|
||||
if (!neutral.IsEmpty())
|
||||
[item_ setAlternateImage:neutral.ToNSImage()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
114
atom/browser/ui/views/menu_bar.cc
Normal file
114
atom/browser/ui/views/menu_bar.cc
Normal file
@@ -0,0 +1,114 @@
|
||||
// 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 "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.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"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/color_utils.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kViewClassName[] = "AtomMenuBar";
|
||||
|
||||
// Default color of the menu bar.
|
||||
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);
|
||||
|
||||
// Filter out the "&" in menu label.
|
||||
base::string16 FilterMenuButtonLabel(const base::string16& label) {
|
||||
base::string16 out;
|
||||
base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MenuBar::MenuBar()
|
||||
: menu_model_(NULL) {
|
||||
#if defined(OS_WIN)
|
||||
SkColor background_color = color_utils::GetSysSkColor(COLOR_MENUBAR);
|
||||
#else
|
||||
SkColor background_color = kDefaultColor;
|
||||
#endif
|
||||
set_background(views::Background::CreateSolidBackground(background_color));
|
||||
|
||||
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, FilterMenuButtonLabel(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_
|
||||
125
atom/browser/ui/views/menu_delegate.cc
Normal file
125
atom/browser/ui/views/menu_delegate.cc
Normal file
@@ -0,0 +1,125 @@
|
||||
// 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_item_view.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::MENU_ANCHOR_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::MenuAnchorPosition* anchor,
|
||||
bool* has_mnemonics,
|
||||
views::MenuButton** button) {
|
||||
ui::MenuModel* model;
|
||||
if (!menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, button))
|
||||
return NULL;
|
||||
|
||||
*anchor = views::MENU_ANCHOR_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::MenuAnchorPosition* 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,14 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
|
||||
if (!SetForegroundWindow(window_))
|
||||
return;
|
||||
|
||||
menu_.reset(new Menu2(menu_model_));
|
||||
menu_->RunContextMenuAt(cursor_pos);
|
||||
views::MenuRunner menu_runner(menu_model_);
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
NULL,
|
||||
NULL,
|
||||
gfx::Rect(cursor_pos, gfx::Size()),
|
||||
views::MENU_ANCHOR_TOPLEFT,
|
||||
ui::MENU_SOURCE_MOUSE,
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
|
||||
}
|
||||
|
||||
void NotifyIcon::ResetIcon() {
|
||||
@@ -107,7 +113,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";
|
||||
|
||||
@@ -22,7 +22,6 @@ class Point;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
class NotifyIconHost;
|
||||
|
||||
class NotifyIcon : public TrayIcon {
|
||||
@@ -69,7 +68,6 @@ class NotifyIcon : public TrayIcon {
|
||||
|
||||
// The context menu.
|
||||
ui::SimpleMenuModel* menu_model_;
|
||||
scoped_ptr<atom::Menu2> menu_;
|
||||
|
||||
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)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user