Compare commits

..

168 Commits

Author SHA1 Message Date
Cheng Zhao
55c8206bda Bump v0.20.1 2014-12-17 15:27:42 -08:00
Cheng Zhao
c01e3cf9aa Merge pull request #931 from atom/will-navigate
Add "will-navigate" event
2014-12-17 15:27:15 -08:00
Cheng Zhao
040049f9e7 docs: "will-navigate" event 2014-12-17 15:15:37 -08:00
Cheng Zhao
2fc1e2a4e6 Merge pull request #924 from atom/webview-ipc-message
Add ipc-message event for <webview>
2014-12-17 15:06:25 -08:00
Cheng Zhao
eaacf0a6ef spec: "will-navigate" event 2014-12-17 15:03:34 -08:00
Cheng Zhao
c2975d2bcc Redirect BrowserWindow's "will-navigate" event to WebContents 2014-12-17 14:56:51 -08:00
Cheng Zhao
60df32aab5 Add "will-navigate" event for WebContents 2014-12-17 14:55:22 -08:00
Cheng Zhao
fd596d4a65 Add "will-navigate" event for BrowserWindow 2014-12-17 14:40:19 -08:00
Cheng Zhao
5142b7858b Upgrade brightray to fix crash in #393 2014-12-17 13:16:06 -08:00
Cheng Zhao
a8f5a4e2d4 Add sendToHost method 2014-12-17 11:09:11 -08:00
Cheng Zhao
d46300587a Remove uses of deprecated APIs in remote module 2014-12-17 11:00:41 -08:00
Cheng Zhao
64a41b65bb Merge pull request #923 from ffdd/patch-1
Add that Menu.setApplication only works after 'ready' event.
2014-12-17 10:29:46 -08:00
Cheng Zhao
275ac2c4b6 doc: ipc-message event 2014-12-16 21:19:04 -08:00
Cheng Zhao
c0285747a2 spec: ipc-message event 2014-12-16 21:11:30 -08:00
Cheng Zhao
95793e410d Redirect guest page's ipc message to embedder 2014-12-16 21:10:53 -08:00
ffdd
31d606220e Add that Menu.setApplication only works after 'ready' event.
I got caught on this while trying to add a menu in my application in OSX.
2014-12-16 21:50:40 -05:00
Cheng Zhao
4fc14959a8 Allow same object to appear in one list when parsing V8 array
Fixes #874.
2014-12-16 16:57:42 -08:00
Cheng Zhao
95dd73bd1d Add maximum depth when converting V8 object to base::Value 2014-12-16 16:46:23 -08:00
Cheng Zhao
5bed184014 Merge pull request #922 from atom/dialog-thread
Run asynchronous file dialog in new thread on Windows
2014-12-16 14:01:05 -08:00
Cheng Zhao
4fa7e8e914 Merge pull request #919 from paulcbetts/nullref-in-webview-manager
Fix nullref crash in WebViewManager::RemoveGuest
2014-12-16 13:40:11 -08:00
Cheng Zhao
63e83a7ef8 win: Don't hang when failed to create thread 2014-12-16 12:33:17 -08:00
Cheng Zhao
c20e1e9d82 win: Run async save dialog in new thread 2014-12-16 12:27:26 -08:00
Cheng Zhao
253bacdf1d win: Run async open dialog in new thread 2014-12-16 11:27:38 -08:00
Cheng Zhao
98127ba13c linux: Fix building 2014-12-15 17:28:51 -08:00
Cheng Zhao
cb911b19dd win: Fixes stopping FlashFrame, closes #906 2014-12-15 17:27:58 -08:00
Cheng Zhao
d50eeb04d5 Upgrade cpplint 2014-12-15 17:15:56 -08:00
Cheng Zhao
1641caf353 Fix cpplint warnings 2014-12-15 16:57:04 -08:00
Cheng Zhao
23951e6ef3 views: Implement CanMinimize, fixes #918 2014-12-15 16:46:37 -08:00
Cheng Zhao
c9a5c6515c views: Make it possible to show a window in maximized state
Fixes #834.
2014-12-15 16:38:20 -08:00
Cheng Zhao
0ab32bfe17 win: Reserve border space for maximized frameless window
Fixes #732.
2014-12-15 16:01:11 -08:00
Cheng Zhao
3d30e6ddc4 win: Don't allow maximzing a unresiazble frameless window
Fixes #857.
2014-12-15 12:55:16 -08:00
Paul Betts
ffdf2f7fcf Check key via ContainsKey instead of null check 2014-12-15 11:22:14 -08:00
Paul Betts
974415f8a1 You're not my real Dad, cpplint 2014-12-15 06:23:00 -08:00
Paul Betts
3105092130 Fix nullref crash in RemoveGuest 2014-12-15 06:10:39 -08:00
Cheng Zhao
85b0885af7 Bump v0.20.0 2014-12-12 18:21:14 -08:00
Cheng Zhao
11cd301127 Only listen to its own events in <webview>, fixes #885 2014-12-12 17:16:12 -08:00
Cheng Zhao
654d21100f Upgrade libchromiumcontent to remove dom storage quota
Closes #897.
2014-12-12 16:42:07 -08:00
Cheng Zhao
5bd924a52d mac: Use com.github.atom-shell as default CFBundleIdentifier 2014-12-12 15:37:13 -08:00
Cheng Zhao
186d34c33a Merge pull request #904 from atom/chrome39
Upgrade to Chrome 39
2014-12-12 15:23:55 -08:00
Cheng Zhao
b0a414ea83 Upgrade brightray 2014-12-12 14:50:39 -08:00
Cheng Zhao
099eb53d3c Upgrade libchromiumcontent to fix generating node.lib 2014-12-12 10:40:42 -08:00
Cheng Zhao
e3ccb18696 win: Fix calculating window bounds on high DPI display 2014-12-12 09:04:43 -08:00
Cheng Zhao
e38614ce31 win: No longer support building with VS Express
The Community edition can provide everything we need for Professional
edition.
2014-12-11 19:47:15 -08:00
Cheng Zhao
290dd4ccd8 win: Use d3dcompiler_46.dll 2014-12-11 19:46:42 -08:00
Cheng Zhao
1bebf1cc2c win: Fix generating location.pak. 2014-12-11 19:29:36 -08:00
Cheng Zhao
d8d9dea792 Upgrade node to fix failed call to LoadLibrary 2014-12-11 18:33:39 -08:00
Cheng Zhao
7457f81283 mac: Fix installing view on frameless window
Closes #601.
2014-12-11 14:25:51 -08:00
Cheng Zhao
158d8efb8e Merge pull request #910 from sonnyp/patch-1
Update tray.md
2014-12-11 13:08:23 -08:00
Cheng Zhao
0b668b8e17 Minor fixes on <webview> 2014-12-11 09:30:55 -08:00
Sonny Piers
5437470b4e Update tray.md
checked seems to be the correct property
2014-12-11 12:28:01 +01:00
Cheng Zhao
409f2b4d0f win: Fix compilation errors 2014-12-10 14:17:07 -08:00
Cheng Zhao
64edede20d Move handling of "preload" to web-view-attributes 2014-12-10 11:05:51 -08:00
Cheng Zhao
6624fd9a1b Fix relative links in "src" of <webview> 2014-12-10 10:51:34 -08:00
Cheng Zhao
1cdbb6f186 Upgrade brightray to fix running on Mac 2014-12-09 22:40:26 -08:00
Cheng Zhao
f57533fa0e Add os_bsd variable for breakpad 2014-12-09 17:25:45 -08:00
Cheng Zhao
2db7c84cbc spec: Remove "restore" event test
It is too slow and unstable.
2014-12-09 17:16:21 -08:00
Cheng Zhao
cefc846e9e linux: Upgrade breakpad to fix building 2014-12-09 17:05:18 -08:00
Cheng Zhao
1853bef39a views: SizeConstraintsChanged has become required 2014-12-09 16:55:01 -08:00
Cheng Zhao
22c4911b58 linux: GTK+ status icon has come back 2014-12-09 16:55:01 -08:00
Cheng Zhao
e58b3ddc86 Bump Chrome version 2014-12-09 16:37:40 -08:00
Cheng Zhao
e3ba17f2d3 linux: Disable warnings for g_settings_list_schemas 2014-12-09 16:37:05 -08:00
Cheng Zhao
7d1830d014 Upgrade node to bump node module version 2014-12-09 15:49:17 -08:00
Cheng Zhao
da3a988c8c Merge branch 'master' into chrome39
Conflicts:
	vendor/brightray
2014-12-09 15:49:06 -08:00
Cheng Zhao
9d23cce2b6 Move "nodeintegration" and "plugins" to web-view-attributes 2014-12-09 14:51:35 -08:00
Cheng Zhao
68381e1b76 Use element instant id for GetGuestByInstanceID 2014-12-09 14:38:43 -08:00
Cheng Zhao
3493d2c701 Merge pull request #901 from IgorKlopov/patch-1
Full verbosity, helps troubleshooting
2014-12-08 21:45:55 -08:00
Cheng Zhao
9e1d3f9e27 Merge pull request #902 from IgorKlopov/patch-2
Why not verbose?
2014-12-08 21:44:00 -08:00
Cheng Zhao
7fdd94520e Merge pull request #898 from paulcbetts/dont-hardcode-atom-helper
Dont hardcode paths to Atom [Helper / Framework]
2014-12-08 21:39:14 -08:00
Cheng Zhao
9fcb6b2cd1 Moved parseSrcAttribute() into the SrcAttribute object as parse()
Imported from:
3bc15760f9%5E%21/
2014-12-08 21:35:10 -08:00
Cheng Zhao
cbafac774e Various webview cleanup
Imported from:
848f1ed048%5E%21/
2014-12-08 21:15:18 -08:00
Cheng Zhao
7f5fb4e6f9 Renamed "WebView" -> "WebViewImpl" in web_view.js and other files that import it
Imported from:
a615ea0839%5E%21/
2014-12-08 21:10:59 -08:00
Cheng Zhao
ac51207860 Optimized the handling of webview attribute mutation
Imported from:
86dff6fc51%5E%21/
2014-12-08 21:06:23 -08:00
Paul Betts
aa3be09ab0 Bump submodule to merged version 2014-12-08 20:26:09 -08:00
Cheng Zhao
4348143fd9 Simplify web-view.coffee
Imported from:
3ef1fc1b72%5E%21/
2014-12-08 17:15:50 -08:00
Cheng Zhao
b6b8b936f2 Automated the definitions of webview attributes as properties on the webview node
Imported from:
aef58f49f6%5E%21/
2014-12-08 17:05:57 -08:00
Cheng Zhao
2c27b953b5 Got rid of the internal copies of webview attributes
Imported from:
abb035a09b%5E%21/
2014-12-08 16:56:14 -08:00
Cheng Zhao
d7eae69587 Webview attributes overhaul
Imported from:
884a5b43cb
2014-12-08 16:14:12 -08:00
Cheng Zhao
e0f1433c12 Moved constants out of web-view.coffee and into a new file
Imported from:
ccbfe27c8d
2014-12-08 13:37:18 -08:00
IgorKlopov
27710cd4f7 bootstrap.py -v in mac 2014-12-08 20:07:29 +03:00
IgorKlopov
4d5bbbc2d7 bootstrap.py -v 2014-12-08 20:07:00 +03:00
IgorKlopov
da900b3094 bootstrap.py also imports it 2014-12-08 20:03:48 +03:00
IgorKlopov
0f29d9f30f verbose_mode from config.py
Also, no return value supposed for execute_stdout
2014-12-08 20:02:08 +03:00
IgorKlopov
b88824a70c verbose_mode getter/setter 2014-12-08 20:00:35 +03:00
Cheng Zhao
882a08f61a Fix browser plugin API changes 2014-12-08 09:00:00 -08:00
Cheng Zhao
a9072049ea Move webview code to atom/renderer/lib/web-view 2014-12-08 06:08:21 -08:00
Paul Betts
e87876671f Add some documentation about renaming Atom Shell 2014-12-07 21:38:29 -08:00
Paul Betts
d0f6c89e77 Bump brightray to pick up brightray/brightray#85 2014-12-07 21:26:19 -08:00
Paul Betts
8eab230fe1 Delete OverrideChildProcessPath and OverrideFrameworkBundlePath altogether 2014-12-07 21:06:47 -08:00
IgorKlopov
7ff95ec255 Travis CI says: execute unused
Removed `execute` import
2014-12-08 03:04:41 +03:00
IgorKlopov
20afd51a9d Travis CI says long line detected
Foldede the line
2014-12-08 02:58:04 +03:00
IgorKlopov
19bba5c18c One more verbose_mode
`bootstrap.py` new variable `verbose_mode` to run `npm install` with --verbose option
2014-12-08 02:52:13 +03:00
IgorKlopov
bf4c219766 Make use of execute_stdout
execute_stdout makes stdout real-time
2014-12-08 02:47:05 +03:00
IgorKlopov
a5e1d8c97f introduce execute_stdout
`execute_stdout` does not return the output of the process. Instead it outputs directly to current stdout (in real-time - to see what is `npm` doing now)
2014-12-08 02:42:55 +03:00
Cheng Zhao
7bc364a374 Upgrade node for new V8 API 2014-12-07 13:09:50 -08:00
Cheng Zhao
5dd73e74cb Disable crash reporter spec on Yosemite 2014-12-07 08:57:55 -08:00
Cheng Zhao
ba347f6460 mac: Fix crash reporting on Yosemite 2014-12-07 08:56:59 -08:00
Cheng Zhao
85cf8f9174 apm@0.112.0 2014-12-07 08:13:42 -08:00
IgorKlopov
2153e018a3 Bootstrap indeed 2014-12-07 18:47:23 +03:00
IgorKlopov
3f4fec0864 Why not verbose?
The silence are scary
2014-12-07 18:46:12 +03:00
Cheng Zhao
10823eeeaa Fix compilation errors caused by Chrome 39 2014-12-07 07:43:26 -08:00
Cheng Zhao
25ea169c72 Upgrade libchromiumcontent to 39.0.2171.65 2014-12-07 07:43:07 -08:00
IgorKlopov
743e8331b5 Helps troubleshooting 2014-12-07 18:42:59 +03:00
Cheng Zhao
d309fd5a27 Update printing code 2014-12-07 06:55:40 -08:00
Paul Betts
091357ad8e Find the MainMenu nib correctly 2014-12-05 23:19:19 -08:00
Paul Betts
3d4491a468 Determine the Helper name from the App name 2014-12-05 23:19:19 -08:00
Cheng Zhao
6d32db32ef Upgrade node, fixes #843 2014-12-04 12:17:36 -08:00
Cheng Zhao
357f5f9781 Upgrade brightray 2014-12-04 11:45:02 -08:00
Cheng Zhao
a0f5544a07 Fix compilation warning on Yosemite 2014-12-03 15:21:50 -08:00
Cheng Zhao
6c9dbe190d Bump v0.19.5 2014-11-28 20:01:42 +08:00
Cheng Zhao
29b8cd8df7 Merge pull request #872 from atom/tray-balloon
Add Tray.displayBalloon API on Windows
2014-11-28 20:01:08 +08:00
Cheng Zhao
f78f94d4f1 Fix building on Mac 2014-11-28 19:50:10 +08:00
Cheng Zhao
ef8b20af65 docs: "balloon-show" and "balloon-closed" events 2014-11-28 19:47:21 +08:00
Cheng Zhao
9f99209733 win: Add "balloon-show" and "balloon-closed" events 2014-11-28 19:42:57 +08:00
Cheng Zhao
ee3fa67c48 docs: Tray balloon 2014-11-28 19:23:13 +08:00
Cheng Zhao
a3327ac53e win: Remove XP code in Tray 2014-11-28 18:59:51 +08:00
Cheng Zhao
210c97f957 win: Add "balloon-clicked" event for Tray 2014-11-28 18:50:31 +08:00
Cheng Zhao
8097cb2b9e Add Tray.displayBallon API 2014-11-28 18:39:30 +08:00
Cheng Zhao
2650e34867 win: Add NotifyIcon::DisplayBalloon 2014-11-28 18:30:43 +08:00
Cheng Zhao
9f0b5a14a4 Remove tray_icon_win.h 2014-11-28 18:21:31 +08:00
Cheng Zhao
a8b4e5faec OVERRIDE => override in notify_icon.h 2014-11-28 18:20:38 +08:00
Cheng Zhao
f6c66a7374 Add Tray.destroy() API, fixes #871 2014-11-28 18:06:51 +08:00
Cheng Zhao
86cf5e0028 OVERRIDE => override in atom_api_tray.h 2014-11-28 17:54:38 +08:00
Cheng Zhao
89de5b6e9a win: Remove NotifyIconHostStateChanger
We don't need the ability it provided, and it is causing crashes on some
machines.

Fixes #850.
2014-11-28 17:47:47 +08:00
Cheng Zhao
ff26c3c16f Some coding style fixes 2014-11-28 15:59:03 +08:00
Cheng Zhao
8a736abac7 Merge pull request #870 from joaomoreno/popup
Allow positioning the context menu
2014-11-28 12:42:49 +08:00
Cheng Zhao
0397b282c0 Merge pull request #867 from IgorKlopov/patch-2
`subprocess.Popen` fails when Python is in "App Paths"
2014-11-28 11:47:57 +08:00
Cheng Zhao
d50a2b810d Merge pull request #866 from bwin/fix-typo
fix typo in variable name
2014-11-28 11:36:02 +08:00
Cheng Zhao
c5de8ea7bf Merge pull request #864 from IgorKlopov/patch-1
Lookup node in PATHs
2014-11-28 11:34:02 +08:00
Joao Moreno
c06e844ef4 fix build 2014-11-26 15:28:03 +01:00
Joao Moreno
c6a16161d9 Update documentation for Menu.popup() 2014-11-26 15:15:55 +01:00
Joao Moreno
46e6b5ec3e Allow positioning the context menu 2014-11-26 13:54:05 +01:00
IgorKlopov
0fd1f61a24 Paul suggests paths to be reversed 2014-11-26 01:43:30 +03:00
IgorKlopov
d8de9754d6 subprocess.Popen fails when Python is in "App Paths"
Win32. Python is not added to PATHs by default. Instead it is added to `App Paths` registry key ( http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx ). In both cases Python binary is found when i enter `python` command. But `subprocess.Popen` seems to fail when BOTH (1) runs a string `python tools/atom_source_root.py` AND (2) python is not in PATHs, only in App Paths. I suggest using list in <!( and hope this does not break linux/macos builds.
2014-11-25 14:16:17 -08:00
IgorKlopov
b00bbdeb81 Preserve that empty line 2014-11-25 13:54:02 -08:00
IgorKlopov
0ab4475f24 Compose full list in one place 2014-11-25 13:53:08 -08:00
IgorKlopov
5137e16485 WINDOWS_NODE_PATHs are to stay
WINDOWS_NODE_PATHs are checked first, and then os.environ['PATH']
2014-11-25 13:46:09 -08:00
Benjamin Winkler
bf85e61dc2 fix typo in variable name
This is just for the looks. No errors where throws, because the variable
name was misspelled in all occurences.
2014-11-25 20:57:55 +01:00
IgorKlopov
91a3e12ab0 Paul says lookup PATH
Works both with trailing slash `c:\nodejs\` and without it `c:\nodejs`
2014-11-25 11:41:11 -08:00
IgorKlopov
6aa6bdebe6 Travis says line too long
80 chars limit hit
2014-11-25 10:58:13 -08:00
IgorKlopov
1af0e0a762 Verbose required paths
I installed to `c:\nodejs` to avoid spaces in path (old habits die hard). So i had an obstacle you see.
2014-11-25 10:27:31 -08:00
Cheng Zhao
03f19bea6b Upgrade brightray for #849 2014-11-25 21:24:40 +08:00
Cheng Zhao
85a3e06718 Merge pull request #860 from rprichard/master
Move Linux pkg-config dependencies from atom-shell to brightray.
2014-11-25 21:23:49 +08:00
Cheng Zhao
8278d8b51a Merge pull request #862 from atom/window-state-events
Add window states events for BrowserWindow
2014-11-25 15:41:10 +08:00
Cheng Zhao
c19abed4fa spec: Don't test window state events in CI on Linux 2014-11-25 15:17:48 +08:00
Cheng Zhao
cef5f06ceb spec: Make timeout longer for window state tests 2014-11-25 15:06:57 +08:00
Cheng Zhao
a666014990 spec: Window state events 2014-11-25 14:52:49 +08:00
Cheng Zhao
5a8678b191 docs: Window state events 2014-11-25 14:43:11 +08:00
Cheng Zhao
271eb63083 SetFullscreen => SetFullScreen 2014-11-25 14:34:14 +08:00
Cheng Zhao
28ca883805 win: Implement window state events 2014-11-25 14:28:34 +08:00
Cheng Zhao
3c7e5e47b8 mac: Implement window state events 2014-11-25 13:16:51 +08:00
Cheng Zhao
588cc3c7ab Make WindowStateWatcher X11 only
On Windows we need to take another way of detecting window state events.
2014-11-25 13:05:04 +08:00
Cheng Zhao
b77e6c369a x11: Implement window state events 2014-11-25 12:43:25 +08:00
Cheng Zhao
06cc27c6b3 views: Add WindowStateWatcher 2014-11-25 11:46:30 +08:00
Ryan Prichard
73ee24bd98 Move Linux pkg-config dependencies from atom-shell to brightray. 2014-11-24 03:27:24 -08:00
Cheng Zhao
84fcfd1fac Merge pull request #858 from atom/wm-class
Use app's name for WM_CLASS
2014-11-24 16:12:07 +08:00
Cheng Zhao
cd5007cfa1 linux: Set WM_CLASS for devtools window 2014-11-24 16:04:41 +08:00
Cheng Zhao
172c55d194 linux: Use app's name for WM_CLASS 2014-11-24 15:51:26 +08:00
Cheng Zhao
60bd20872c linux: Set WM_WINDOW_ROLE correctly
WM_WINDOW_ROLE is used to specify the "role" of the window, and all
browser windows in atom-shell should have the same role.
2014-11-24 15:23:02 +08:00
Cheng Zhao
b2aaffa921 Upgrade node, fixes #843 2014-11-24 14:46:36 +08:00
Cheng Zhao
438d7ada49 Merge pull request #855 from paulcbetts/fix-webview-typo
Fix typo in method
2014-11-24 14:05:03 +08:00
Cheng Zhao
a9b1b567fb Fix capturePage API, closes #847 2014-11-24 13:44:45 +08:00
Paul Betts
2f530f7049 Downcast variable to appease clang 2014-11-23 13:52:59 -08:00
Paul Betts
dfcad75a27 Fix typo in method 2014-11-22 21:26:09 -08:00
Cheng Zhao
a0034521da Bump v0.19.4 2014-11-21 16:51:11 +08:00
Cheng Zhao
e4d9dbcfa2 Do not use no_overwrite mode.
Sometimes it would prevent uploading even when the file doesn't exist in
S3.
2014-11-21 16:41:16 +08:00
Cheng Zhao
ac914e1f19 OVERRODE => override in atom_main_delegate.h 2014-11-21 16:40:47 +08:00
Cheng Zhao
bed09839d5 Remove debugging print, closes #841 2014-11-21 16:39:16 +08:00
Cheng Zhao
8951572366 win: Fix crash when calling app.setName 2014-11-21 16:38:54 +08:00
134 changed files with 3005 additions and 2631 deletions

View File

@@ -44,11 +44,13 @@
'atom/common/lib/init.coffee',
'atom/common/lib/asar.coffee',
'atom/renderer/lib/chrome-api.coffee',
'atom/renderer/lib/guest-view-internal.coffee',
'atom/renderer/lib/init.coffee',
'atom/renderer/lib/inspector.coffee',
'atom/renderer/lib/override.coffee',
'atom/renderer/lib/web-view.coffee',
'atom/renderer/lib/web-view/guest-view-internal.coffee',
'atom/renderer/lib/web-view/web-view.coffee',
'atom/renderer/lib/web-view/web-view-attributes.coffee',
'atom/renderer/lib/web-view/web-view-constants.coffee',
'atom/renderer/api/lib/ipc.coffee',
'atom/renderer/api/lib/remote.coffee',
'atom/renderer/api/lib/web-frame.coffee',
@@ -58,7 +60,6 @@
'atom/app/atom_content_client.h',
'atom/app/atom_main_delegate.cc',
'atom/app/atom_main_delegate.h',
'atom/app/atom_main_delegate_mac.mm',
'atom/browser/api/atom_api_app.cc',
'atom/browser/api/atom_api_app.h',
'atom/browser/api/atom_api_auto_updater.cc',
@@ -179,6 +180,8 @@
'atom/browser/ui/win/notify_icon_host.h',
'atom/browser/ui/win/notify_icon.cc',
'atom/browser/ui/win/notify_icon.h',
'atom/browser/ui/x/window_state_watcher.cc',
'atom/browser/ui/x/window_state_watcher.h',
'atom/browser/ui/x/x_window_utils.cc',
'atom/browser/ui/x/x_window_utils.h',
'atom/browser/web_view/web_view_manager.cc',
@@ -281,6 +284,7 @@
'chromium_src/chrome/browser/printing/print_job_manager.h',
'chromium_src/chrome/browser/printing/print_job_worker.cc',
'chromium_src/chrome/browser/printing/print_job_worker.h',
'chromium_src/chrome/browser/printing/print_job_worker_owner.cc',
'chromium_src/chrome/browser/printing/print_job_worker_owner.h',
'chromium_src/chrome/browser/printing/print_view_manager_base.cc',
'chromium_src/chrome/browser/printing/print_view_manager_base.h',
@@ -291,8 +295,6 @@
'chromium_src/chrome/browser/printing/printer_query.h',
'chromium_src/chrome/browser/printing/printing_message_filter.cc',
'chromium_src/chrome/browser/printing/printing_message_filter.h',
'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc',
'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h',
'chromium_src/chrome/browser/speech/tts_controller.h',
'chromium_src/chrome/browser/speech/tts_controller_impl.cc',
'chromium_src/chrome/browser/speech/tts_controller_impl.h',
@@ -307,14 +309,8 @@
'chromium_src/chrome/browser/ui/cocoa/color_chooser_mac.mm',
'chromium_src/chrome/browser/ui/views/color_chooser_aura.cc',
'chromium_src/chrome/browser/ui/views/color_chooser_aura.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',
'chromium_src/chrome/common/print_messages.cc',
'chromium_src/chrome/common/print_messages.h',
'chromium_src/chrome/common/tts_messages.h',
@@ -323,7 +319,7 @@
'chromium_src/chrome/renderer/printing/print_web_view_helper.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm',
'chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper.h',
'chromium_src/chrome/renderer/tts_dispatcher.cc',
'chromium_src/chrome/renderer/tts_dispatcher.h',
@@ -350,7 +346,7 @@
'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk',
'vi', 'zh-CN', 'zh-TW',
],
'atom_source_root': '<!(python tools/atom_source_root.py)',
'atom_source_root': '<!(["python", "tools/atom_source_root.py"])',
'conditions': [
['OS=="win"', {
'app_sources': [
@@ -480,10 +476,10 @@
'<(libchromiumcontent_library_dir)/libEGL.dll',
'<(libchromiumcontent_library_dir)/libGLESv2.dll',
'<(libchromiumcontent_resources_dir)/icudtl.dat',
'<(libchromiumcontent_resources_dir)/content_resources_200_percent.pak',
'<(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/d3dcompiler_46.dll',
'external_binaries/msvcp120.dll',
'external_binaries/msvcr120.dll',
'external_binaries/vccorlib120.dll',
@@ -529,6 +525,8 @@
'defines': [
# This is defined in skia/skia_common.gypi.
'SK_SUPPORT_LEGACY_GETTOPDEVICE',
# Disable warnings for g_settings_list_schemas.
'GLIB_DISABLE_DEPRECATION_WARNINGS',
],
'sources': [
'<@(lib_sources)',
@@ -587,10 +585,6 @@
'-rpath \$$ORIGIN',
# Make native module dynamic loading work.
'-rdynamic',
'<!@(pkg-config --libs-only-L --libs-only-other dbus-1 x11 xrandr xext gconf-2.0)',
],
'libraries': [
'<!@(pkg-config --libs-only-l dbus-1 x11 xrandr xext gconf-2.0)',
],
},
# Required settings of using breakpad.
@@ -889,13 +883,14 @@
{
'action_name': 'Make Empty Paks',
'inputs': [
'tools/posix/make_locale_paks.sh',
'tools/make_locale_paks.py',
],
'outputs': [
'<(PRODUCT_DIR)/locales'
],
'action': [
'tools/posix/make_locale_paks.sh',
'python',
'tools/make_locale_paks.py',
'<(PRODUCT_DIR)',
'<@(locales)',
],
@@ -937,31 +932,5 @@
}, # target generate_node_lib
],
}], # OS==win
# Using Visual Studio Express.
['msvs_express==1', {
'target_defaults': {
'defines!': [
'_SECURE_ATL',
],
'msvs_settings': {
'VCLibrarianTool': {
'AdditionalLibraryDirectories': [
'<(atom_source_root)/external_binaries/atl/lib',
],
},
'VCLinkerTool': {
'AdditionalLibraryDirectories': [
'<(atom_source_root)/external_binaries/atl/lib',
],
'AdditionalDependencies': [
'atls.lib',
],
},
},
'msvs_system_include_dirs': [
'<(atom_source_root)/external_binaries/atl/include',
],
},
}], # msvs_express==1
],
}

View File

@@ -89,10 +89,6 @@ void AtomMainDelegate::PreSandboxStartup() {
command_line->AppendSwitch("atom-shell-switches-end");
}
void AtomMainDelegate::ProcessExiting(const std::string& process_type) {
LOG(ERROR) << "ProcessExiting: " << process_type;
}
content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
browser_client_.reset(new AtomBrowserClient);
return browser_client_.get();
@@ -115,7 +111,7 @@ void AtomMainDelegate::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")),
pak_dir.Append(FILE_PATH_LITERAL("content_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
#endif
}

View File

@@ -17,21 +17,15 @@ class AtomMainDelegate : public brightray::MainDelegate {
protected:
// content::ContentMainDelegate:
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
virtual void PreSandboxStartup() OVERRIDE;
virtual void ProcessExiting(const std::string& process_type) OVERRIDE;
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
virtual content::ContentRendererClient*
CreateContentRendererClient() OVERRIDE;
bool BasicStartupComplete(int* exit_code) override;
void PreSandboxStartup() override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;
// brightray::MainDelegate:
virtual scoped_ptr<brightray::ContentClient> CreateContentClient() OVERRIDE;
virtual void AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) OVERRIDE;
#if defined(OS_MACOSX)
virtual void OverrideChildProcessPath() OVERRIDE;
virtual void OverrideFrameworkBundlePath() OVERRIDE;
#endif
scoped_ptr<brightray::ContentClient> CreateContentClient() override;
void AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) override;
private:
brightray::ContentClient content_client_;

View File

@@ -1,37 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_main_delegate.h"
#include "base/mac/bundle_locations.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "brightray/common/mac/main_application_bundle.h"
#include "content/public/common/content_paths.h"
namespace atom {
namespace {
base::FilePath GetFrameworksPath() {
return brightray::MainApplicationBundlePath().Append("Contents")
.Append("Frameworks");
}
} // namespace
void AtomMainDelegate::OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(
GetFrameworksPath().Append("Atom Framework.framework"));
}
void AtomMainDelegate::OverrideChildProcessPath() {
base::FilePath helper_path = GetFrameworksPath().Append("Atom Helper.app")
.Append("Contents")
.Append("MacOS")
.Append("Atom Helper");
PathService::Override(content::CHILD_PROCESS_EXE, helper_path);
}
} // namespace atom

View File

@@ -69,14 +69,17 @@ void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
dict.SetMethod("startRecording", base::Bind(
&TracingController::EnableRecording, base::Unretained(controller)));
dict.SetMethod("stopRecording", base::Bind(
&TracingController::DisableRecording, base::Unretained(controller)));
&TracingController::DisableRecording,
base::Unretained(controller),
nullptr));
dict.SetMethod("startMonitoring", base::Bind(
&TracingController::EnableMonitoring, base::Unretained(controller)));
dict.SetMethod("stopMonitoring", base::Bind(
&TracingController::DisableMonitoring, base::Unretained(controller)));
dict.SetMethod("captureMonitoringSnapshot", base::Bind(
&TracingController::CaptureMonitoringSnapshot,
base::Unretained(controller)));
base::Unretained(controller),
nullptr));
dict.SetMethod("getTraceBufferPercentFull", base::Bind(
&TracingController::GetTraceBufferPercentFull,
base::Unretained(controller)));

View File

@@ -246,7 +246,8 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
.SetMethod("attachToWindow", &Menu::AttachToWindow)
.SetMethod("_popup", &Menu::Popup);
.SetMethod("_popup", &Menu::Popup)
.SetMethod("_popupAt", &Menu::PopupAt);
}
} // namespace api

View File

@@ -55,6 +55,7 @@ class Menu : public mate::Wrappable,
virtual void AttachToWindow(Window* window);
virtual void Popup(Window* window) = 0;
virtual void PopupAt(Window* window, int x, int y) = 0;
scoped_ptr<ui::SimpleMenuModel> model_;
Menu* parent_;

View File

@@ -20,6 +20,7 @@ class MenuMac : public Menu {
MenuMac();
virtual void Popup(Window* window) OVERRIDE;
virtual void PopupAt(Window* window, int x, int y) OVERRIDE;
base::scoped_nsobject<AtomMenuController> menu_controller_;

View File

@@ -19,13 +19,17 @@ MenuMac::MenuMac() {
}
void MenuMac::Popup(Window* window) {
NativeWindow* native_window = window->window();
if (!native_window)
return;
content::WebContents* web_contents = native_window->GetWebContents();
if (!web_contents)
return;
NSWindow* nswindow = native_window->GetNativeWindow();
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:model_.get()]);
NativeWindow* native_window = window->window();
NSWindow* nswindow = native_window->GetNativeWindow();
content::WebContents* web_contents = native_window->GetWebContents();
// Fake out a context menu event.
NSEvent* currentEvent = [NSApp currentEvent];
NSPoint position = [nswindow mouseLocationOutsideOfEventStream];
@@ -46,6 +50,25 @@ void MenuMac::Popup(Window* window) {
forView:web_contents->GetContentNativeView()];
}
void MenuMac::PopupAt(Window* window, int x, int y) {
NativeWindow* native_window = window->window();
if (!native_window)
return;
content::WebContents* web_contents = native_window->GetWebContents();
if (!web_contents)
return;
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:model_.get()]);
NSMenu* menu = [menu_controller menu];
NSView* view = web_contents->GetContentNativeView();
// Show the menu.
[menu popUpMenuPositioningItem:[menu itemAtIndex:0]
atLocation:NSMakePoint(x, [view frame].size.height - y)
inView:view];
}
// static
void Menu::SetApplicationMenu(Menu* base_menu) {
MenuMac* menu = static_cast<MenuMac*>(base_menu);

View File

@@ -5,6 +5,7 @@
#include "atom/browser/api/atom_api_menu_views.h"
#include "atom/browser/native_window_views.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_runner.h"
@@ -16,14 +17,32 @@ MenuViews::MenuViews() {
}
void MenuViews::Popup(Window* window) {
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
PopupAtPoint(window, gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
}
void MenuViews::PopupAt(Window* window, int x, int y) {
NativeWindow* native_window = static_cast<NativeWindow*>(window->window());
if (!native_window)
return;
content::WebContents* web_contents = native_window->GetWebContents();
if (!web_contents)
return;
content::RenderWidgetHostView* view = web_contents->GetRenderWidgetHostView();
if (!view)
return;
gfx::Point origin = view->GetViewBounds().origin();
PopupAtPoint(window, gfx::Point(origin.x() + x, origin.y() + y));
}
void MenuViews::PopupAtPoint(Window* window, const gfx::Point& point) {
views::MenuRunner menu_runner(
model(),
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt(
static_cast<NativeWindowViews*>(window->window())->widget(),
NULL,
gfx::Rect(cursor, gfx::Size()),
gfx::Rect(point, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
}

View File

@@ -6,6 +6,7 @@
#define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
#include "atom/browser/api/atom_api_menu.h"
#include "ui/gfx/screen.h"
namespace atom {
@@ -17,8 +18,11 @@ class MenuViews : public Menu {
protected:
virtual void Popup(Window* window) OVERRIDE;
virtual void PopupAt(Window* window, int x, int y) OVERRIDE;
private:
void PopupAtPoint(Window* window, const gfx::Point& point);
DISALLOW_COPY_AND_ASSIGN(MenuViews);
};

View File

@@ -9,6 +9,7 @@
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/ui/tray_icon.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
@@ -40,39 +41,95 @@ void Tray::OnDoubleClicked() {
Emit("double-clicked");
}
void Tray::SetImage(const gfx::ImageSkia& image) {
void Tray::OnBalloonShow() {
Emit("balloon-show");
}
void Tray::OnBalloonClicked() {
Emit("balloon-clicked");
}
void Tray::OnBalloonClosed() {
Emit("balloon-closed");
}
void Tray::Destroy() {
tray_icon_.reset();
}
void Tray::SetImage(mate::Arguments* args, const gfx::ImageSkia& image) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetImage(image);
}
void Tray::SetPressedImage(const gfx::ImageSkia& image) {
void Tray::SetPressedImage(mate::Arguments* args, const gfx::ImageSkia& image) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetPressedImage(image);
}
void Tray::SetToolTip(const std::string& tool_tip) {
void Tray::SetToolTip(mate::Arguments* args, const std::string& tool_tip) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetToolTip(tool_tip);
}
void Tray::SetTitle(const std::string& title) {
void Tray::SetTitle(mate::Arguments* args, const std::string& title) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetTitle(title);
}
void Tray::SetHighlightMode(bool highlight) {
void Tray::SetHighlightMode(mate::Arguments* args, bool highlight) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetHighlightMode(highlight);
}
void Tray::SetContextMenu(Menu* menu) {
void Tray::DisplayBalloon(mate::Arguments* args,
const mate::Dictionary& options) {
if (!CheckTrayLife(args))
return;
gfx::ImageSkia icon;
options.Get("icon", &icon);
base::string16 title, content;
if (!options.Get("title", &title) ||
!options.Get("content", &content)) {
args->ThrowError("'title' and 'content' must be defined");
return;
}
tray_icon_->DisplayBalloon(icon, title, content);
}
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetContextMenu(menu->model());
}
bool Tray::CheckTrayLife(mate::Arguments* args) {
if (!tray_icon_) {
args->ThrowError("Tray is already destroyed");
return false;
} else {
return true;
}
}
// static
void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Handle<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy)
.SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip)
.SetMethod("setTitle", &Tray::SetTitle)
.SetMethod("setHighlightMode", &Tray::SetHighlightMode)
.SetMethod("displayBalloon", &Tray::DisplayBalloon)
.SetMethod("_setContextMenu", &Tray::SetContextMenu);
}

View File

@@ -15,6 +15,11 @@ namespace gfx {
class ImageSkia;
}
namespace mate {
class Arguments;
class Dictionary;
}
namespace atom {
class TrayIcon;
@@ -35,18 +40,25 @@ class Tray : public mate::EventEmitter,
explicit Tray(const gfx::ImageSkia& image);
virtual ~Tray();
// TrayIcon implementations:
virtual void OnClicked() OVERRIDE;
virtual void OnDoubleClicked() OVERRIDE;
// TrayIconObserver:
void OnClicked() override;
void OnDoubleClicked() override;
void OnBalloonShow() override;
void OnBalloonClicked() override;
void OnBalloonClosed() override;
void SetImage(const gfx::ImageSkia& image);
void SetPressedImage(const gfx::ImageSkia& image);
void SetToolTip(const std::string& tool_tip);
void SetTitle(const std::string& title);
void SetHighlightMode(bool highlight);
void SetContextMenu(Menu* menu);
void Destroy();
void SetImage(mate::Arguments* args, const gfx::ImageSkia& image);
void SetPressedImage(mate::Arguments* args, const gfx::ImageSkia& image);
void SetToolTip(mate::Arguments* args, const std::string& tool_tip);
void SetTitle(mate::Arguments* args, const std::string& title);
void SetHighlightMode(mate::Arguments* args, bool highlight);
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
void SetContextMenu(mate::Arguments* args, Menu* menu);
private:
bool CheckTrayLife(mate::Arguments* args);
scoped_ptr<TrayIcon> tray_icon_;
DISALLOW_COPY_AND_ASSIGN(Tray);

View File

@@ -12,6 +12,7 @@
#include "atom/common/native_mate_converters/value_converter.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "content/public/browser/navigation_details.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"
@@ -37,12 +38,14 @@ v8::Persistent<v8::ObjectTemplate> template_;
WebContents::WebContents(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
guest_instance_id_(-1),
element_instance_id_(-1),
guest_opaque_(true),
auto_size_enabled_(false) {
}
WebContents::WebContents(const mate::Dictionary& options)
: guest_instance_id_(-1),
element_instance_id_(-1),
guest_opaque_(true),
auto_size_enabled_(false) {
options.Get("guestInstanceId", &guest_instance_id_);
@@ -108,9 +111,15 @@ content::WebContents* WebContents::OpenURLFromTab(
args.AppendString("");
args.AppendInteger(params.disposition);
Emit("-new-window", args);
return NULL;
return nullptr;
}
// Give user a chance to cancel navigation.
base::ListValue args;
args.AppendString(params.url.spec());
if (Emit("will-navigate", args))
return nullptr;
content::NavigationController::LoadURLParams load_url_params(params.url);
load_url_params.referrer = params.referrer;
load_url_params.transition_type = params.transition;
@@ -188,6 +197,13 @@ void WebContents::DidGetRedirectForResourceRequest(
Emit("did-get-redirect-request", args);
}
void WebContents::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
if (details.is_navigation_to_different_page())
Emit("did-navigate-to-different-page");
}
bool WebContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContents, message)
@@ -225,26 +241,8 @@ void WebContents::WebContentsDestroyed() {
Emit("destroyed");
}
void WebContents::WillAttach(content::WebContents* embedder_web_contents,
const base::DictionaryValue& extra_params) {
embedder_web_contents_ = embedder_web_contents;
extra_params_.reset(extra_params.DeepCopy());
}
content::WebContents* WebContents::CreateNewGuestWindow(
const content::WebContents::CreateParams& create_params) {
NOTREACHED() << "Should not create new window from guest";
return nullptr;
}
void WebContents::DidAttach() {
base::ListValue args;
args.Append(extra_params_.release());
Emit("did-attach", args);
}
int WebContents::GetGuestInstanceID() const {
return guest_instance_id_;
void WebContents::DidAttach(int guest_proxy_routing_id) {
Emit("did-attach");
}
void WebContents::ElementSizeChanged(const gfx::Size& old_size,
@@ -260,18 +258,17 @@ void WebContents::GuestSizeChanged(const gfx::Size& old_size,
GuestSizeChangedDueToAutoSize(old_size, new_size);
}
void WebContents::RequestPointerLockPermission(
bool user_gesture,
bool last_unlocked_by_target,
const base::Callback<void(bool enabled)>& callback) {
callback.Run(true);
}
void WebContents::RegisterDestructionCallback(
const DestructionCallback& callback) {
destruction_callback_ = callback;
}
void WebContents::WillAttach(content::WebContents* embedder_web_contents,
int browser_plugin_instance_id) {
embedder_web_contents_ = embedder_web_contents;
element_instance_id_ = browser_plugin_instance_id;
}
void WebContents::Destroy() {
if (storage_) {
if (!destruction_callback_.is_null())
@@ -294,7 +291,7 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
blink::WebReferrerPolicyDefault);
params.transition_type = content::PAGE_TRANSITION_TYPED;
params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
web_contents()->GetController().LoadURLWithParams(params);
}

View File

@@ -92,7 +92,7 @@ class WebContents : public mate::EventEmitter,
~WebContents();
// mate::Wrappable:
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
// content::WebContentsDelegate:
@@ -118,42 +118,35 @@ class WebContents : public mate::EventEmitter,
const content::NativeWebKeyboardEvent& event) override;
// content::WebContentsObserver:
virtual void RenderViewDeleted(content::RenderViewHost*) override;
virtual void RenderProcessGone(base::TerminationStatus status) override;
virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
virtual void DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) override;
virtual void DidStartLoading(
content::RenderViewHost* render_view_host) override;
virtual void DidStopLoading(
content::RenderViewHost* render_view_host) override;
virtual void DidGetRedirectForResourceRequest(
void RenderViewDeleted(content::RenderViewHost*) override;
void RenderProcessGone(base::TerminationStatus status) override;
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
void DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) override;
void DidStartLoading(content::RenderViewHost* render_view_host) override;
void DidStopLoading(content::RenderViewHost* render_view_host) override;
void DidGetRedirectForResourceRequest(
content::RenderViewHost* render_view_host,
const content::ResourceRedirectDetails& details) override;
virtual bool OnMessageReceived(const IPC::Message& message) override;
virtual void RenderViewReady() override;
virtual void WebContentsDestroyed() override;
void DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) override;
bool OnMessageReceived(const IPC::Message& message) override;
void RenderViewReady() override;
void WebContentsDestroyed() override;
// content::BrowserPluginGuestDelegate:
virtual void WillAttach(content::WebContents* embedder_web_contents,
const base::DictionaryValue& extra_params) override;
virtual content::WebContents* CreateNewGuestWindow(
const content::WebContents::CreateParams& create_params) override;
virtual void DidAttach() override;
virtual int GetGuestInstanceID() const override;
virtual void ElementSizeChanged(const gfx::Size& old_size,
const gfx::Size& new_size) override;
virtual void GuestSizeChanged(const gfx::Size& old_size,
const gfx::Size& new_size) override;
virtual void RequestPointerLockPermission(
bool user_gesture,
bool last_unlocked_by_target,
const base::Callback<void(bool enabled)>& callback) override;
virtual void RegisterDestructionCallback(
const DestructionCallback& callback) override;
void DidAttach(int guest_proxy_routing_id) final;
void ElementSizeChanged(const gfx::Size& old_size,
const gfx::Size& new_size) final;
void GuestSizeChanged(const gfx::Size& old_size,
const gfx::Size& new_size) final;
void RegisterDestructionCallback(const DestructionCallback& callback) final;
void WillAttach(content::WebContents* embedder_web_contents,
int browser_plugin_instance_id) final;
private:
// Called when received a message from renderer.
@@ -171,17 +164,15 @@ class WebContents : public mate::EventEmitter,
// Unique ID for a guest WebContents.
int guest_instance_id_;
// |element_instance_id_| is an identifer that's unique to a particular
// element.
int element_instance_id_;
DestructionCallback destruction_callback_;
// Stores whether the contents of the guest can be transparent.
bool guest_opaque_;
// The extra parameters associated with this guest view passed
// in from JavaScript. This will typically be the view instance ID,
// the API to use, and view-specific parameters. These parameters
// are passed along to new guests that are created from this guest.
scoped_ptr<base::DictionaryValue> extra_params_;
// Stores the WebContents that managed by this class.
scoped_ptr<brightray::InspectableWebContents> storage_;

View File

@@ -19,7 +19,7 @@ namespace {
struct PrintSettings {
bool silent;
bool print_backgournd;
bool print_background;
};
} // namespace
@@ -34,7 +34,7 @@ struct Converter<PrintSettings> {
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("silent", &(out->silent));
dict.Get("printBackground", &(out->print_backgournd));
dict.Get("printBackground", &(out->print_background));
return true;
}
};
@@ -72,8 +72,6 @@ Window::Window(const mate::Dictionary& options)
Window::~Window() {
if (window_)
Destroy();
Emit("destroyed");
}
void Window::OnPageTitleUpdated(bool* prevent_default,
@@ -94,6 +92,12 @@ void Window::WillCreatePopupWindow(const base::string16& frame_name,
Emit("-new-window", args);
}
void Window::WillNavigate(bool* prevent_default, const GURL& url) {
base::ListValue args;
args.AppendString(url.spec());
*prevent_default = Emit("-will-navigate", args);
}
void Window::WillCloseWindow(bool* prevent_default) {
*prevent_default = Emit("close");
}
@@ -112,6 +116,30 @@ void Window::OnWindowFocus() {
Emit("focus");
}
void Window::OnWindowMaximize() {
Emit("maximize");
}
void Window::OnWindowUnmaximize() {
Emit("unmaximize");
}
void Window::OnWindowMinimize() {
Emit("minimize");
}
void Window::OnWindowRestore() {
Emit("restore");
}
void Window::OnWindowEnterFullScreen() {
Emit("enter-full-screen");
}
void Window::OnWindowLeaveFullScreen() {
Emit("leave-full-screen");
}
void Window::OnRendererUnresponsive() {
Emit("unresponsive");
}
@@ -193,8 +221,8 @@ bool Window::IsMinimized() {
return window_->IsMinimized();
}
void Window::SetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
void Window::SetFullScreen(bool fullscreen) {
window_->SetFullScreen(fullscreen);
}
bool Window::IsFullscreen() {
@@ -371,7 +399,7 @@ void Window::Print(mate::Arguments* args) {
return;
}
window_->Print(settings.silent, settings.print_backgournd);
window_->Print(settings.silent, settings.print_background);
}
void Window::SetProgressBar(double progress) {
@@ -422,7 +450,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("minimize", &Window::Minimize)
.SetMethod("restore", &Window::Restore)
.SetMethod("isMinimized", &Window::IsMinimized)
.SetMethod("setFullScreen", &Window::SetFullscreen)
.SetMethod("setFullScreen", &Window::SetFullScreen)
.SetMethod("isFullScreen", &Window::IsFullscreen)
.SetMethod("getSize", &Window::GetSize)
.SetMethod("setSize", &Window::SetSize)

View File

@@ -43,17 +43,24 @@ class Window : public mate::EventEmitter,
explicit Window(const mate::Dictionary& options);
virtual ~Window();
// Implementations of NativeWindowObserver:
// NativeWindowObserver:
void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) override;
void WillCreatePopupWindow(const base::string16& frame_name,
const GURL& target_url,
const std::string& partition_id,
WindowOpenDisposition disposition) override;
void WillNavigate(bool* prevent_default, const GURL& url) override;
void WillCloseWindow(bool* prevent_default) override;
void OnWindowClosed() override;
void OnWindowBlur() override;
void OnWindowFocus() override;
void OnWindowMaximize() override;
void OnWindowUnmaximize() override;
void OnWindowMinimize() override;
void OnWindowRestore() override;
void OnWindowEnterFullScreen() override;
void OnWindowLeaveFullScreen() override;
void OnRendererUnresponsive() override;
void OnRendererResponsive() override;
@@ -74,7 +81,7 @@ class Window : public mate::EventEmitter,
void Minimize();
void Restore();
bool IsMinimized();
void SetFullscreen(bool fullscreen);
void SetFullScreen(bool fullscreen);
bool IsFullscreen();
void SetSize(int width, int height);
std::vector<int> GetSize();

View File

@@ -30,6 +30,10 @@ BrowserWindow::_init = ->
options = show: true, width: 800, height: 600
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
# Redirect "will-navigate" to webContents.
@on '-will-navigate', (event, url) =>
@webContents.emit 'will-navigate', event, url
# Remove the window from weak map immediately when it's destroyed, since we
# could be iterating windows before GC happened.
@once 'closed', =>

View File

@@ -45,9 +45,12 @@ Menu::_init = ->
break
v8Util.setHiddenValue group[0], 'checked', true unless checked
Menu::popup = (window) ->
Menu::popup = (window, x, y) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
@_popup window
if x? and y?
@_popupAt(window, x, y)
else
@_popup window
Menu::append = (item) ->
@insert @getItemCount(), item

View File

@@ -56,7 +56,7 @@ AtomBrowserClient::~AtomBrowserClient() {
void AtomBrowserClient::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
int id = host->GetID();
host->AddFilter(new PrintingMessageFilter(host->GetID()));
host->AddFilter(new printing::PrintingMessageFilter(host->GetID()));
host->AddFilter(new TtsMessageFilter(id, host->GetBrowserContext()));
}

View File

@@ -23,12 +23,12 @@ class AtomBrowserContext : public brightray::BrowserContext {
static AtomBrowserContext* Get();
// brightray::URLRequestContextGetter::Delegate:
virtual net::URLRequestJobFactory* CreateURLRequestJobFactory(
net::URLRequestJobFactory* CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers,
content::URLRequestInterceptorScopedVector* interceptors) override;
// content::BrowserContext:
virtual content::BrowserPluginGuestManager* GetGuestManager() override;
content::BrowserPluginGuestManager* GetGuestManager() override;
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }

View File

@@ -13,6 +13,11 @@
namespace atom {
std::string GetApplicationName() {
std::string name = brightray::MainApplicationBundlePath().BaseName().AsUTF8Unsafe();
return name.substr(0, name.length() - 4/*.app*/);
}
void AtomBrowserMainParts::PreMainMessageLoopStart() {
// Initialize locale setting.
l10n_util::OverrideLocaleWithCocoaLocale();
@@ -26,7 +31,7 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
base::FilePath frameworkPath = brightray::MainApplicationBundlePath()
.Append("Contents")
.Append("Frameworks")
.Append("Atom Framework.framework");
.Append(GetApplicationName() + " Framework.framework");
NSBundle* frameworkBundle = [NSBundle
bundleWithPath:base::mac::FilePathToNSString(frameworkPath)];
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:@"MainMenu"

View File

@@ -20,28 +20,28 @@ class AtomSpeechRecognitionManagerDelegate
virtual ~AtomSpeechRecognitionManagerDelegate();
// content::SpeechRecognitionEventListener:
virtual void OnRecognitionStart(int session_id) override;
virtual void OnAudioStart(int session_id) override;
virtual void OnEnvironmentEstimationComplete(int session_id) override;
virtual void OnSoundStart(int session_id) override;
virtual void OnSoundEnd(int session_id) override;
virtual void OnAudioEnd(int session_id) override;
virtual void OnRecognitionEnd(int session_id) override;
virtual void OnRecognitionResults(
void OnRecognitionStart(int session_id) override;
void OnAudioStart(int session_id) override;
void OnEnvironmentEstimationComplete(int session_id) override;
void OnSoundStart(int session_id) override;
void OnSoundEnd(int session_id) override;
void OnAudioEnd(int session_id) override;
void OnRecognitionEnd(int session_id) override;
void OnRecognitionResults(
int session_id, const content::SpeechRecognitionResults& result) override;
virtual void OnRecognitionError(
void OnRecognitionError(
int session_id, const content::SpeechRecognitionError& error) override;
virtual void OnAudioLevelsChange(int session_id, float volume,
float noise_volume) override;
void OnAudioLevelsChange(int session_id, float volume,
float noise_volume) override;
// content::SpeechRecognitionManagerDelegate:
virtual void GetDiagnosticInformation(bool* can_report_metrics,
std::string* hardware_info) override;
virtual void CheckRecognitionIsAllowed(
void GetDiagnosticInformation(bool* can_report_metrics,
std::string* hardware_info) override;
void CheckRecognitionIsAllowed(
int session_id,
base::Callback<void(bool ask_user, bool is_allowed)> callback) override;
virtual content::SpeechRecognitionEventListener* GetEventListener() override;
virtual bool FilterProfanities(int render_process_id) override;
content::SpeechRecognitionEventListener* GetEventListener() override;
bool FilterProfanities(int render_process_id) override;
private:
DISALLOW_COPY_AND_ASSIGN(AtomSpeechRecognitionManagerDelegate);

View File

@@ -71,7 +71,7 @@ void Browser::DockShow() {
}
void Browser::DockSetMenu(ui::MenuModel* model) {
AtomApplicationDelegate* delegate = [NSApp delegate];
AtomApplicationDelegate* delegate = (AtomApplicationDelegate*)[NSApp delegate];
[delegate setApplicationDockMenu:model];
}

View File

@@ -118,8 +118,8 @@ void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
}
void Browser::SetAppUserModelID(const std::string& name) {
app_user_model_id_ = base::UTF8ToUTF16(
base::StringPrintf("atom-shell.app.%s", name));
app_user_model_id_ = base::string16(L"atom-shell.app.");
app_user_model_id_ += base::UTF8ToUTF16(name);
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str());
}

View File

@@ -7,8 +7,7 @@
namespace atom {
JavascriptEnvironment::JavascriptEnvironment()
: isolate_holder_(gin::IsolateHolder::kNonStrictMode),
isolate_(isolate_holder_.isolate()),
: isolate_(isolate_holder_.isolate()),
isolate_scope_(isolate_),
locker_(isolate_),
handle_scope_(isolate_),

View File

@@ -18,6 +18,8 @@ supportedWebViewEvents = [
nextInstanceId = 0
guestInstances = {}
embedderElementsMap = {}
reverseEmbedderElementsMap = {}
# Generate guestInstanceId.
getNextInstanceId = (webContents) ->
@@ -33,15 +35,19 @@ createGuest = (embedder, params) ->
guestInstanceId: id
storagePartitionId: params.storagePartitionId
guestInstances[id] = {guest, embedder}
preload = params.preload ? ''
webViewManager.addGuest id, embedder, guest, params.nodeIntegration, params.plugins, preload
# Destroy guest when the embedder is gone.
embedder.once 'render-view-deleted', ->
# Destroy guest when the embedder is gone or navigated.
destroyEvents = ['destroyed', 'crashed', 'did-navigate-to-different-page']
destroy = ->
destroyGuest id if guestInstances[id]?
embedder.removeListener event, destroy for event in destroyEvents
embedder.once event, destroy for event in destroyEvents
# Init guest web view after attached.
guest.once 'did-attach', (event, params) ->
guest.once 'did-attach', ->
params = @attachParams
delete @attachParams
@viewInstanceId = params.instanceId
min = width: params.minwidth, height: params.minheight
max = width: params.maxwidth, height: params.maxheight
@@ -60,21 +66,57 @@ createGuest = (embedder, params) ->
guest.on event, (_, args...) ->
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args...
# Dispatch guest's IPC messages to embedder.
guest.on 'ipc-message-host', (_, channel, args...) ->
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args...
# Autosize.
guest.on 'size-changed', (_, args...) ->
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED", args...
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args...
id
# Attach the guest to an element of embedder.
attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
guest = guestInstances[guestInstanceId].guest
# Destroy the old guest when attaching.
key = "#{embedder.getId()}-#{elementInstanceId}"
oldGuestInstanceId = embedderElementsMap[key]
if oldGuestInstanceId?
# Reattachment to the same guest is not currently supported.
return unless oldGuestInstanceId != guestInstanceId
return unless guestInstances[oldGuestInstanceId]?
destroyGuest oldGuestInstanceId
webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest,
nodeIntegration: params.nodeintegration
plugins: params.plugins
preloadUrl: params.preload ? ''
guest.attachParams = params
embedderElementsMap[key] = guestInstanceId
reverseEmbedderElementsMap[guestInstanceId] = key
# Destroy an existing guest instance.
destroyGuest = (id) ->
webViewManager.removeGuest id
guestInstances[id].guest.destroy()
delete guestInstances[id]
key = reverseEmbedderElementsMap[id]
if key?
delete reverseEmbedderElementsMap[id]
delete embedderElementsMap[key]
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, type, params, requestId) ->
event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params)
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params, requestId) ->
attachGuest event.sender, elementInstanceId, guestInstanceId, params
event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}"
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) ->
destroyGuest id

View File

@@ -50,11 +50,15 @@
#include "ipc/ipc_message_macros.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size.h"
using content::NavigationEntry;
using content::RenderWidgetHostView;
using content::RenderWidgetHost;
namespace atom {
@@ -165,7 +169,7 @@ NativeWindow* NativeWindow::FromRenderView(int process_id, int routing_id) {
return window;
}
return NULL;
return nullptr;
}
void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
@@ -200,7 +204,7 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
}
bool fullscreen;
if (options.Get(switches::kFullscreen, &fullscreen) && fullscreen) {
SetFullscreen(true);
SetFullScreen(true);
}
bool skip;
if (options.Get(switches::kSkipTaskbar, &skip) && skip) {
@@ -289,31 +293,43 @@ void NativeWindow::BlurWebView() {
}
bool NativeWindow::IsWebViewFocused() {
content::RenderWidgetHostView* host_view =
RenderWidgetHostView* host_view =
GetWebContents()->GetRenderViewHost()->GetView();
return host_view && host_view->HasFocus();
}
void NativeWindow::CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback) {
content::RenderViewHost* render_view_host =
GetWebContents()->GetRenderViewHost();
content::RenderWidgetHostView* render_widget_host_view =
render_view_host->GetView();
if (!render_widget_host_view) {
content::WebContents* contents = GetWebContents();
RenderWidgetHostView* const view = contents->GetRenderWidgetHostView();
RenderWidgetHost* const host = view ? view->GetRenderWidgetHost() : nullptr;
if (!view || !host) {
callback.Run(std::vector<unsigned char>());
return;
}
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
rect,
rect.IsEmpty() ? render_widget_host_view->GetViewBounds().size() :
rect.size(),
// Capture full page if user doesn't specify a |rect|.
const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() :
rect.size();
// By default, the requested bitmap size is the view size in screen
// coordinates. However, if there's more pixel detail available on the
// current system, increase the requested bitmap size to capture it all.
gfx::Size bitmap_size = view_size;
const gfx::NativeView native_view = view->GetNativeView();
gfx::Screen* const screen = gfx::Screen::GetScreenFor(native_view);
const float scale =
screen->GetDisplayNearestWindow(native_view).device_scale_factor();
if (scale > 1.0f)
bitmap_size = gfx::ToCeiledSize(gfx::ScaleSize(view_size, scale));
host->CopyFromBackingStore(
rect.IsEmpty() ? gfx::Rect(view_size) : rect,
bitmap_size,
base::Bind(&NativeWindow::OnCapturePageDone,
weak_factory_.GetWeakPtr(),
callback),
kAlpha_8_SkColorType);
kBGRA_8888_SkColorType);
}
void NativeWindow::DestroyWebContents() {
@@ -354,13 +370,13 @@ void NativeWindow::CloseWebContents() {
content::WebContents* NativeWindow::GetWebContents() const {
if (!inspectable_web_contents_)
return NULL;
return nullptr;
return inspectable_web_contents()->GetWebContents();
}
content::WebContents* NativeWindow::GetDevToolsWebContents() const {
if (!inspectable_web_contents_)
return NULL;
return nullptr;
return inspectable_web_contents()->devtools_web_contents();
}
@@ -423,9 +439,10 @@ void NativeWindow::OverrideWebkitPrefs(const GURL& url,
prefs->experimental_webgl_enabled = b;
if (web_preferences_.Get("webaudio", &b))
prefs->webaudio_enabled = b;
if (web_preferences_.Get("extra-plugin-dirs", &list))
if (web_preferences_.Get("extra-plugin-dirs", &list)) {
for (size_t i = 0; i < list.size(); ++i)
content::PluginService::GetInstance()->AddExtraPluginDir(list[i]);
}
}
void NativeWindow::NotifyWindowClosed() {
@@ -450,6 +467,32 @@ void NativeWindow::NotifyWindowFocus() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowFocus());
}
void NativeWindow::NotifyWindowMaximize() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMaximize());
}
void NativeWindow::NotifyWindowUnmaximize() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowUnmaximize());
}
void NativeWindow::NotifyWindowMinimize() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMinimize());
}
void NativeWindow::NotifyWindowRestore() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowRestore());
}
void NativeWindow::NotifyWindowEnterFullScreen() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnWindowEnterFullScreen());
}
void NativeWindow::NotifyWindowLeaveFullScreen() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnWindowLeaveFullScreen());
}
bool NativeWindow::ShouldCreateWebContents(
content::WebContents* web_contents,
int route_id,
@@ -481,9 +524,17 @@ content::WebContents* NativeWindow::OpenURLFromTab(
params.url,
"",
params.disposition));
return NULL;
return nullptr;
}
// Give user a chance to prevent navigation.
bool prevent_default = false;
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
WillNavigate(&prevent_default, params.url));
if (prevent_default)
return nullptr;
content::NavigationController::LoadURLParams load_url_params(params.url);
load_url_params.referrer = params.referrer;
load_url_params.transition_type = params.transition;
@@ -698,6 +749,7 @@ void NativeWindow::NotifyWindowUnresponsive() {
void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap) {
SkAutoLockPixels screen_capture_lock(bitmap);
std::vector<unsigned char> data;
if (succeed)
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data);

View File

@@ -111,7 +111,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void Minimize() = 0;
virtual void Restore() = 0;
virtual bool IsMinimized() = 0;
virtual void SetFullscreen(bool fullscreen) = 0;
virtual void SetFullScreen(bool fullscreen) = 0;
virtual bool IsFullscreen() = 0;
virtual void SetSize(const gfx::Size& size) = 0;
virtual gfx::Size GetSize() = 0;
@@ -192,6 +192,12 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
void NotifyWindowClosed();
void NotifyWindowBlur();
void NotifyWindowFocus();
void NotifyWindowMaximize();
void NotifyWindowUnmaximize();
void NotifyWindowMinimize();
void NotifyWindowRestore();
void NotifyWindowEnterFullScreen();
void NotifyWindowLeaveFullScreen();
void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs);

View File

@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "atom/browser/native_window.h"
@class FullSizeContentView;
class SkRegion;
namespace atom {
@@ -37,7 +38,7 @@ class NativeWindowMac : public NativeWindow {
virtual void Minimize() OVERRIDE;
virtual void Restore() OVERRIDE;
virtual bool IsMinimized() OVERRIDE;
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
virtual void SetFullScreen(bool fullscreen) OVERRIDE;
virtual bool IsFullscreen() OVERRIDE;
virtual void SetSize(const gfx::Size& size) OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
@@ -98,6 +99,9 @@ class NativeWindowMac : public NativeWindow {
base::scoped_nsobject<NSWindow> window_;
// The view that will fill the whole frameless window.
base::scoped_nsobject<FullSizeContentView> content_view_;
bool is_kiosk_;
NSInteger attention_request_id_; // identifier from requestUserAttention

View File

@@ -25,6 +25,31 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
- (CGFloat)roundedCornerRadius;
@end
// This view always takes the size of its superview. It is intended to be used
// as a NSWindow's contentView. It is needed because NSWindow's implementation
// explicitly resizes the contentView at inopportune times.
@interface FullSizeContentView : NSView
@end
@implementation FullSizeContentView
// This method is directly called by NSWindow during a window resize on OSX
// 10.10.0, beta 2. We must override it to prevent the content view from
// shrinking.
- (void)setFrameSize:(NSSize)size {
if ([self superview])
size = [[self superview] bounds].size;
[super setFrameSize:size];
}
// The contentView gets moved around during certain full-screen operations.
// This is less than ideal, and should eventually be removed.
- (void)viewDidMoveToSuperview {
[self setFrame:[[self superview] bounds]];
}
@end
@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
@private
atom::NativeWindowMac* shell_;
@@ -81,11 +106,36 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
shell_->ClipWebView();
}
- (void)windowDidMiniaturize:(NSNotification*)notification {
shell_->NotifyWindowMinimize();
}
- (void)windowDidDeminiaturize:(NSNotification*)notification {
shell_->NotifyWindowRestore();
}
- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame {
// Cocoa doen't have concept of maximize/unmaximize, so wee need to emulate
// them by calculating size change when zooming.
if (newFrame.size.width < [window frame].size.width ||
newFrame.size.height < [window frame].size.height)
shell_->NotifyWindowUnmaximize();
else
shell_->NotifyWindowMaximize();
return YES;
}
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
shell_->NotifyWindowEnterFullScreen();
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
if (!shell_->has_frame()) {
NSWindow* window = shell_->GetNativeWindow();
[[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
}
shell_->NotifyWindowLeaveFullScreen();
}
- (void)windowWillClose:(NSNotification*)notification {
@@ -375,7 +425,7 @@ bool NativeWindowMac::IsMinimized() {
return [window_ isMiniaturized];
}
void NativeWindowMac::SetFullscreen(bool fullscreen) {
void NativeWindowMac::SetFullScreen(bool fullscreen) {
if (fullscreen == IsFullscreen())
return;
@@ -520,10 +570,10 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
NSApplicationPresentationDisableHideApplication;
[NSApp setPresentationOptions:options];
is_kiosk_ = true;
SetFullscreen(true);
SetFullScreen(true);
} else if (!kiosk && is_kiosk_) {
is_kiosk_ = false;
SetFullscreen(false);
SetFullScreen(false);
[NSApp setPresentationOptions:kiosk_options_];
}
}
@@ -665,9 +715,24 @@ void NativeWindowMac::InstallView() {
[view setFrame:[[window_ contentView] bounds]];
[[window_ contentView] addSubview:view];
} else {
NSView* frameView = [[window_ contentView] superview];
[view setFrame:[frameView bounds]];
[frameView addSubview:view];
if (base::mac::IsOSYosemiteOrLater()) {
// In OSX 10.10, adding subviews to the root view for the NSView hierarchy
// produces warnings. To eliminate the warnings, we resize the contentView
// to fill the window, and add subviews to that.
// http://crbug.com/380412
content_view_.reset([[FullSizeContentView alloc] init]);
[content_view_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[content_view_ setFrame:[[[window_ contentView] superview] bounds]];
[window_ setContentView:content_view_];
[view setFrame:[content_view_ bounds]];
[content_view_ addSubview:view];
} else {
NSView* frameView = [[window_ contentView] superview];
[view setFrame:[frameView bounds]];
[frameView addSubview:view];
}
ClipWebView();

View File

@@ -27,6 +27,9 @@ class NativeWindowObserver {
const std::string& partition_id,
WindowOpenDisposition disposition) {}
// Called when user is starting an navigation in web page.
virtual void WillNavigate(bool* prevent_default, const GURL& url) {}
// Called when the window is gonna closed.
virtual void WillCloseWindow(bool* prevent_default) {}
@@ -39,6 +42,14 @@ class NativeWindowObserver {
// Called when window gains focus.
virtual void OnWindowFocus() {}
// Called when window state changed.
virtual void OnWindowMaximize() {}
virtual void OnWindowUnmaximize() {}
virtual void OnWindowMinimize() {}
virtual void OnWindowRestore() {}
virtual void OnWindowEnterFullScreen() {}
virtual void OnWindowLeaveFullScreen() {}
// Called when renderer is hung.
virtual void OnRendererUnresponsive() {}

View File

@@ -26,16 +26,18 @@
#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/native_widget_private.h"
#include "ui/views/widget/widget.h"
#if defined(USE_X11)
#include "atom/browser/browser.h"
#include "atom/browser/ui/views/global_menu_bar_x11.h"
#include "atom/browser/ui/views/frameless_view.h"
#include "atom/browser/ui/x/window_state_watcher.h"
#include "atom/browser/ui/x/x_window_utils.h"
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ui/libgtk2ui/unity_service.h"
#include "dbus/bus.h"
#include "dbus/object_proxy.h"
@@ -48,6 +50,7 @@
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/win/hwnd_util.h"
#endif
@@ -63,10 +66,6 @@ const int kMenuBarHeight = 25;
#endif
#if defined(USE_X11)
// Counts how many window has already been created, it will be used to set the
// window role for X11.
int kWindowsCreated = 0;
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
bool ShouldUseGlobalMenuBar() {
dbus::Bus::Options options;
@@ -148,6 +147,9 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
menu_bar_autohide_(false),
menu_bar_visible_(false),
menu_bar_alt_pressed_(false),
#if defined(OS_WIN)
is_minimized_(false),
#endif
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
use_content_size_(false),
resizable_(true) {
@@ -182,18 +184,20 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
params.remove_standard_frame = !has_frame_;
#if defined(USE_X11)
std::string name = Browser::Get()->GetName();
// Set WM_WINDOW_ROLE.
params.wm_role_name = base::StringPrintf(
"%s/%s/%d", "Atom Shell", Browser::Get()->GetName().c_str(),
++kWindowsCreated);
params.wm_role_name = "browser-window";
// Set WM_CLASS.
params.wm_class_name = "atom";
params.wm_class_class = "Atom";
params.wm_class_name = base::StringToLowerASCII(name);
params.wm_class_class = name;
#endif
window_->Init(params);
#if defined(USE_X11)
// Start monitoring window states.
window_state_watcher_.reset(new WindowStateWatcher(this));
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(switches::kDarkTheme, &use_dark_theme) && use_dark_theme) {
@@ -218,7 +222,7 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
#endif
// Add web view.
SetLayoutManager(new MenuLayout(kMenuBarHeight));
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_);
@@ -293,7 +297,11 @@ bool NativeWindowViews::IsVisible() {
}
void NativeWindowViews::Maximize() {
window_->Maximize();
if (IsVisible())
window_->Maximize();
else
window_->native_widget_private()->ShowWithWindowState(
ui::SHOW_STATE_MAXIMIZED);
}
void NativeWindowViews::Unmaximize() {
@@ -305,7 +313,11 @@ bool NativeWindowViews::IsMaximized() {
}
void NativeWindowViews::Minimize() {
window_->Minimize();
if (IsVisible())
window_->Minimize();
else
window_->native_widget_private()->ShowWithWindowState(
ui::SHOW_STATE_MINIMIZED);
}
void NativeWindowViews::Restore() {
@@ -316,8 +328,19 @@ bool NativeWindowViews::IsMinimized() {
return window_->IsMinimized();
}
void NativeWindowViews::SetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
void NativeWindowViews::SetFullScreen(bool fullscreen) {
if (IsVisible())
window_->SetFullscreen(fullscreen);
else
window_->native_widget_private()->ShowWithWindowState(
ui::SHOW_STATE_FULLSCREEN);
#if defined(OS_WIN)
// There is no native fullscreen state on Windows.
if (fullscreen)
NotifyWindowEnterFullScreen();
else
NotifyWindowLeaveFullScreen();
#endif
}
bool NativeWindowViews::IsFullscreen() {
@@ -401,17 +424,15 @@ gfx::Size NativeWindowViews::GetMaximumSize() {
void NativeWindowViews::SetResizable(bool resizable) {
#if defined(OS_WIN)
if (has_frame_) {
// WS_MAXIMIZEBOX => Maximize button
// WS_MINIMIZEBOX => Minimize button
// WS_THICKFRAME => Resize handle
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
if (resizable)
style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
else
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX;
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
}
// WS_MAXIMIZEBOX => Maximize button
// WS_MINIMIZEBOX => Minimize button
// WS_THICKFRAME => Resize handle
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
if (resizable)
style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
else
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX;
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
#elif defined(USE_X11)
if (resizable != resizable_) {
// On Linux there is no "resizable" property of a window, we have to set
@@ -468,6 +489,18 @@ std::string NativeWindowViews::GetTitle() {
}
void NativeWindowViews::FlashFrame(bool flash) {
#if defined(OS_WIN)
// The Chromium's implementation has a bug stopping flash.
if (!flash) {
FLASHWINFO fwi;
fwi.cbSize = sizeof(fwi);
fwi.hwnd = GetAcceleratedWidget();
fwi.dwFlags = FLASHW_STOP;
fwi.uCount = 0;
FlashWindowEx(&fwi);
return;
}
#endif
window_->FlashFrame(flash);
}
@@ -489,7 +522,7 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) {
}
void NativeWindowViews::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
SetFullScreen(kiosk);
}
bool NativeWindowViews::IsKiosk() {
@@ -654,6 +687,10 @@ bool NativeWindowViews::CanMaximize() const {
return resizable_;
}
bool NativeWindowViews::CanMinimize() const {
return true;
}
base::string16 NativeWindowViews::GetWindowTitle() const {
return base::UTF8ToUTF16(title_);
}
@@ -721,10 +758,39 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
#endif
}
#if defined(OS_WIN)
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
// Windows uses the 4 lower order bits of |command_id| for type-specific
// information so we must exclude this when comparing.
static const int sc_mask = 0xFFF0;
if ((command_id & sc_mask) == SC_MINIMIZE) {
NotifyWindowMinimize();
is_minimized_ = true;
} else if ((command_id & sc_mask) == SC_RESTORE) {
if (is_minimized_)
NotifyWindowRestore();
else
NotifyWindowUnmaximize();
is_minimized_ = false;
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
NotifyWindowMaximize();
}
return false;
}
#endif
gfx::ImageSkia NativeWindowViews::GetDevToolsWindowIcon() {
return GetWindowAppIcon();
}
#if defined(USE_X11)
void NativeWindowViews::GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) {
*class_name = Browser::Get()->GetName();
*name = base::StringToLowerASCII(*class_name);
}
#endif
void NativeWindowViews::HandleMouseDown() {
// Hide menu bar when web view is clicked.
if (menu_bar_autohide_ && menu_bar_visible_)
@@ -799,8 +865,15 @@ void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
const gfx::Rect& bounds) {
#if defined(OS_WIN)
gfx::Rect dpi_bounds = gfx::win::DIPToScreenRect(bounds);
gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
#else
gfx::Rect window_bounds =
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
#endif
if (menu_bar_ && menu_bar_visible_)
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
return window_bounds;

View File

@@ -22,6 +22,7 @@ namespace atom {
class GlobalMenuBarX11;
class MenuBar;
class WindowStateWatcher;
class NativeWindowViews : public NativeWindow,
public views::WidgetDelegateView,
@@ -47,7 +48,7 @@ class NativeWindowViews : public NativeWindow,
void Minimize() override;
void Restore() override;
bool IsMinimized() override;
void SetFullscreen(bool fullscreen) override;
void SetFullScreen(bool fullscreen) override;
bool IsFullscreen() override;
void SetSize(const gfx::Size& size) override;
gfx::Size GetSize() override;
@@ -97,6 +98,7 @@ class NativeWindowViews : public NativeWindow,
views::View* GetInitiallyFocusedView() override;
bool CanResize() const override;
bool CanMaximize() const override;
bool CanMinimize() const override;
base::string16 GetWindowTitle() const override;
bool ShouldHandleSystemCommands() const override;
gfx::ImageSkia GetWindowAppIcon() override;
@@ -110,9 +112,16 @@ class NativeWindowViews : public NativeWindow,
views::ClientView* CreateClientView(views::Widget* widget) override;
views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) override;
#if defined(OS_WIN)
bool ExecuteWindowsCommand(int command_id) override;
#endif
// brightray::InspectableWebContentsDelegate:
gfx::ImageSkia GetDevToolsWindowIcon() override;
#if defined(USE_X11)
void GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) override;
#endif
// content::WebContentsDelegate:
void HandleMouseDown() override;
@@ -140,6 +149,13 @@ class NativeWindowViews : public NativeWindow,
#if defined(USE_X11)
scoped_ptr<GlobalMenuBarX11> global_menu_bar_;
// Handles window state events.
scoped_ptr<WindowStateWatcher> window_state_watcher_;
#elif defined(OS_WIN)
// Records window was whether restored from minimized state or maximized
// state.
bool is_minimized_;
#endif
// Handles unhandled keyboard messages coming back from the renderer process.

View File

@@ -22,7 +22,7 @@ AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
}
void AdapterRequestJob::Start() {
DCHECK(!real_job_);
DCHECK(!real_job_.get());
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
@@ -31,35 +31,35 @@ void AdapterRequestJob::Start() {
}
void AdapterRequestJob::Kill() {
if (real_job_) // Kill could happen when real_job_ is created.
if (real_job_.get()) // Kill could happen when real_job_ is created.
real_job_->Kill();
}
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) {
DCHECK(real_job_);
DCHECK(!real_job_.get());
return real_job_->ReadRawData(buf, buf_size, bytes_read);
}
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
DCHECK(real_job_);
DCHECK(!real_job_.get());
return real_job_->IsRedirectResponse(location, http_status_code);
}
net::Filter* AdapterRequestJob::SetupFilter() const {
DCHECK(real_job_);
DCHECK(!real_job_.get());
return real_job_->SetupFilter();
}
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
DCHECK(real_job_);
DCHECK(!real_job_.get());
return real_job_->GetMimeType(mime_type);
}
bool AdapterRequestJob::GetCharset(std::string* charset) {
DCHECK(real_job_);
DCHECK(!real_job_.get());
return real_job_->GetCharset(charset);
}

View File

@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.github.atom</string>
<string>com.github.atom-shell</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -17,7 +17,7 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.19.3</string>
<string>0.20.1</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>NSMainNibFile</key>

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,19,3,0
PRODUCTVERSION 0,19,3,0
FILEVERSION 0,20,1,0
PRODUCTVERSION 0,20,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Atom-Shell"
VALUE "FileVersion", "0.19.3"
VALUE "FileVersion", "0.20.1"
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.19.3"
VALUE "ProductVersion", "0.20.1"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -15,6 +15,7 @@
#include "base/strings/string_util.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "base/win/registry.h"
#include "third_party/wtl/include/atlapp.h"
#include "third_party/wtl/include/atldlgs.h"
@@ -113,6 +114,50 @@ class FileDialog {
DISALLOW_COPY_AND_ASSIGN(FileDialog);
};
struct RunState {
base::Thread* dialog_thread;
base::MessageLoop* ui_message_loop;
};
bool CreateDialogThread(RunState* run_state) {
base::Thread* thread = new base::Thread("AtomShell_FileDialogThread");
thread->init_com_with_mta(false);
if (!thread->Start())
return false;
run_state->dialog_thread = thread;
run_state->ui_message_loop = base::MessageLoop::current();
return true;
}
void RunOpenDialogInNewThread(const RunState& run_state,
atom::NativeWindow* parent,
const std::string& title,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback) {
std::vector<base::FilePath> paths;
bool result = ShowOpenDialog(parent, title, default_path, filters, properties,
&paths);
run_state.ui_message_loop->PostTask(FROM_HERE,
base::Bind(callback, result, paths));
run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread);
}
void RunSaveDialogInNewThread(const RunState& run_state,
atom::NativeWindow* parent,
const std::string& title,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback) {
base::FilePath path;
bool result = ShowSaveDialog(parent, title, default_path, filters, &path);
run_state.ui_message_loop->PostTask(FROM_HERE,
base::Bind(callback, result, path));
run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread);
}
} // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window,
@@ -162,20 +207,22 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
return true;
}
void ShowOpenDialog(atom::NativeWindow* parent_window,
void ShowOpenDialog(atom::NativeWindow* parent,
const std::string& title,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback) {
std::vector<base::FilePath> paths;
bool result = ShowOpenDialog(parent_window,
title,
default_path,
filters,
properties,
&paths);
callback.Run(result, paths);
RunState run_state;
if (!CreateDialogThread(&run_state)) {
callback.Run(false, std::vector<base::FilePath>());
return;
}
run_state.dialog_thread->message_loop()->PostTask(
FROM_HERE,
base::Bind(&RunOpenDialogInNewThread, run_state, parent, title,
default_path, filters, properties, callback));
}
bool ShowSaveDialog(atom::NativeWindow* parent_window,
@@ -218,15 +265,21 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
return true;
}
void ShowSaveDialog(atom::NativeWindow* parent_window,
void ShowSaveDialog(atom::NativeWindow* parent,
const std::string& title,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback) {
base::FilePath path;
bool result = ShowSaveDialog(parent_window, title, default_path, filters,
&path);
callback.Run(result, path);
RunState run_state;
if (!CreateDialogThread(&run_state)) {
callback.Run(false, base::FilePath());
return;
}
run_state.dialog_thread->message_loop()->PostTask(
FROM_HERE,
base::Bind(&RunSaveDialogInNewThread, run_state, parent, title,
default_path, filters, callback));
}
} // namespace file_dialog

View File

@@ -12,12 +12,20 @@ TrayIcon::TrayIcon() {
TrayIcon::~TrayIcon() {
}
void TrayIcon::SetPressedImage(const gfx::ImageSkia& image) {
}
void TrayIcon::SetTitle(const std::string& title) {
}
void TrayIcon::SetHighlightMode(bool highlight) {
}
void TrayIcon::DisplayBalloon(const gfx::ImageSkia& icon,
const base::string16& title,
const base::string16& contents) {
}
void TrayIcon::NotifyClicked() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked());
}
@@ -26,4 +34,16 @@ void TrayIcon::NotifyDoubleClicked() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDoubleClicked());
}
void TrayIcon::NotifyBalloonShow() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonShow());
}
void TrayIcon::NotifyBalloonClicked() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClicked());
}
void TrayIcon::NotifyBalloonClosed() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClosed());
}
} // namespace atom

View File

@@ -23,7 +23,7 @@ class TrayIcon {
virtual void SetImage(const gfx::ImageSkia& image) = 0;
// Sets the image associated with this status icon when pressed.
virtual void SetPressedImage(const gfx::ImageSkia& image) = 0;
virtual void SetPressedImage(const gfx::ImageSkia& image);
// Sets the hover text for this status icon. This is also used as the label
// for the menu item which is created as a replacement for the status icon
@@ -39,6 +39,12 @@ class TrayIcon {
// works on OS X.
virtual void SetHighlightMode(bool highlight);
// Displays a notification balloon with the specified contents.
// Depending on the platform it might not appear by the icon tray.
virtual void DisplayBalloon(const gfx::ImageSkia& icon,
const base::string16& title,
const base::string16& contents);
// Set the context menu for this icon.
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;
@@ -46,6 +52,9 @@ class TrayIcon {
void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); }
void NotifyClicked();
void NotifyDoubleClicked();
void NotifyBalloonShow();
void NotifyBalloonClicked();
void NotifyBalloonClosed();
protected:
TrayIcon();

View File

@@ -32,10 +32,6 @@ void TrayIconGtk::SetImage(const gfx::ImageSkia& image) {
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));
}

View File

@@ -24,7 +24,6 @@ class TrayIconGtk : public TrayIcon,
// 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;

View File

@@ -11,6 +11,9 @@ class TrayIconObserver {
public:
virtual void OnClicked() {}
virtual void OnDoubleClicked() {}
virtual void OnBalloonShow() {}
virtual void OnBalloonClicked() {}
virtual void OnBalloonClosed() {}
protected:
virtual ~TrayIconObserver() {}

View File

@@ -1,30 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// 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_WIN_H_
#define ATOM_BROWSER_UI_TRAY_ICON_WIN_H_
#include <string>
#include "atom/browser/ui/tray_icon.h"
namespace atom {
class TrayIconWin : public TrayIcon {
public:
TrayIconWin();
virtual ~TrayIconWin();
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:
DISALLOW_COPY_AND_ASSIGN(TrayIconWin);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_TRAY_ICON_WIN_H_

View File

@@ -95,6 +95,9 @@ void FramelessView::UpdateWindowIcon() {
void FramelessView::UpdateWindowTitle() {
}
void FramelessView::SizeConstraintsChanged() {
}
gfx::Size FramelessView::GetPreferredSize() const {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();

View File

@@ -36,6 +36,7 @@ class FramelessView : public views::NonClientFrameView {
void ResetWindowControls() override;
void UpdateWindowIcon() override;
void UpdateWindowTitle() override;
void SizeConstraintsChanged() override;
// Overridden from View:
gfx::Size GetPreferredSize() const override;

View File

@@ -4,16 +4,47 @@
#include "atom/browser/ui/views/menu_layout.h"
#if defined(OS_WIN)
#include "atom/browser/native_window_views.h"
#endif
namespace atom {
MenuLayout::MenuLayout(int menu_height)
: menu_height_(menu_height) {
namespace {
#if defined(OS_WIN)
gfx::Rect SubstractBorderSize(gfx::Rect bounds) {
int border_width = GetSystemMetrics(SM_CXSIZEFRAME) - 1;
int border_height = GetSystemMetrics(SM_CYSIZEFRAME) - 1;
bounds.set_x(bounds.x() + border_width);
bounds.set_y(bounds.y() + border_height);
bounds.set_width(bounds.width() - 2 * border_width);
bounds.set_height(bounds.height() - 2 * border_height);
return bounds;
}
#endif
} // namespace
MenuLayout::MenuLayout(NativeWindowViews* window, int menu_height)
: window_(window),
menu_height_(menu_height) {
}
MenuLayout::~MenuLayout() {
}
void MenuLayout::Layout(views::View* host) {
#if defined(OS_WIN)
// Reserve border space for maximized frameless window so we won't have the
// content go outside of screen.
if (!window_->has_frame() && window_->IsMaximized()) {
gfx::Rect bounds = SubstractBorderSize(host->GetContentsBounds());
host->child_at(0)->SetBoundsRect(bounds);
return;
}
#endif
if (!HasMenu(host)) {
views::FillLayout::Layout(host);
return;

View File

@@ -9,9 +9,11 @@
namespace atom {
class NativeWindowViews;
class MenuLayout : public views::FillLayout {
public:
explicit MenuLayout(int menu_height);
MenuLayout(NativeWindowViews* window, int menu_height);
virtual ~MenuLayout();
// views::LayoutManager:
@@ -23,6 +25,7 @@ class MenuLayout : public views::FillLayout {
private:
bool HasMenu(const views::View* host) const;
NativeWindowViews* window_;
int menu_height_;
DISALLOW_COPY_AND_ASSIGN(MenuLayout);

View File

@@ -27,9 +27,9 @@ 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);
return views::GetWindowBoundsForClientBounds(
static_cast<views::View*>(const_cast<WinFrameView*>(this)),
client_bounds);
}
int WinFrameView::NonClientHitTest(const gfx::Point& point) {
@@ -53,12 +53,4 @@ const char* WinFrameView::GetClassName() const {
return kViewClassName;
}
void WinFrameView::ClientAreaSizeToWindowSize(gfx::Size* size) const {
// AdjustWindowRect seems to return a wrong window size.
gfx::Size window = frame_->GetWindowBoundsInScreen().size();
gfx::Size client = frame_->GetClientAreaBoundsInScreen().size();
size->set_width(size->width() + window.width() - client.width());
size->set_height(size->height() + window.height() - client.height());
}
} // namespace atom

View File

@@ -25,8 +25,6 @@ class WinFrameView : public FramelessView {
const char* GetClassName() const override;
private:
void ClientAreaSizeToWindowSize(gfx::Size* size) const;
DISALLOW_COPY_AND_ASSIGN(WinFrameView);
};

View File

@@ -100,8 +100,6 @@ void NotifyIcon::SetImage(const gfx::ImageSkia& image) {
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result)
LOG(WARNING) << "Error setting status tray icon image";
else
host_->UpdateIconVisibilityInBackground(this);
}
void NotifyIcon::SetPressedImage(const gfx::ImageSkia& image) {
@@ -120,19 +118,36 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
LOG(WARNING) << "Unable to set tooltip for status tray icon";
}
void NotifyIcon::DisplayBalloon(const gfx::ImageSkia& icon,
const base::string16& title,
const base::string16& contents) {
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags = NIF_INFO;
icon_data.dwInfoFlags = NIIF_INFO;
wcscpy_s(icon_data.szInfoTitle, title.c_str());
wcscpy_s(icon_data.szInfo, contents.c_str());
icon_data.uTimeout = 0;
base::win::Version win_version = base::win::GetVersion();
if (!icon.isNull() && win_version != base::win::VERSION_PRE_XP) {
balloon_icon_.Set(IconUtil::CreateHICONFromSkBitmap(*icon.bitmap()));
icon_data.hBalloonIcon = balloon_icon_.Get();
icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
}
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result)
LOG(WARNING) << "Unable to create status tray balloon.";
}
void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_model_ = menu_model;
}
void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
memset(icon_data, 0, sizeof(NOTIFYICONDATA));
icon_data->cbSize = sizeof(NOTIFYICONDATA);
} else {
memset(icon_data, 0, NOTIFYICONDATA_V3_SIZE);
icon_data->cbSize = NOTIFYICONDATA_V3_SIZE;
}
memset(icon_data, 0, sizeof(NOTIFYICONDATA));
icon_data->cbSize = sizeof(NOTIFYICONDATA);
icon_data->hWnd = window_;
icon_data->uID = icon_id_;
}

View File

@@ -43,10 +43,13 @@ class NotifyIcon : public TrayIcon {
UINT message_id() const { return message_id_; }
// Overridden from 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;
void SetImage(const gfx::ImageSkia& image) override;
void SetPressedImage(const gfx::ImageSkia& image) override;
void SetToolTip(const std::string& tool_tip) override;
void DisplayBalloon(const gfx::ImageSkia& icon,
const base::string16& title,
const base::string16& contents) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private:
void InitIconData(NOTIFYICONDATA* icon_data);
@@ -66,6 +69,9 @@ class NotifyIcon : public TrayIcon {
// The currently-displayed icon for the window.
base::win::ScopedHICON icon_;
// The currently-displayed icon for the notification balloon.
base::win::ScopedHICON balloon_icon_;
// The context menu.
ui::SimpleMenuModel* menu_model_;

View File

@@ -12,7 +12,6 @@
#include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h"
#include "base/win/wrapped_window_proc.h"
#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h"
@@ -29,68 +28,6 @@ const wchar_t kNotifyIconHostWindowClass[] = L"AtomShell_NotifyIconHostWindow";
} // namespace
// Default implementation for NotifyIconHostStateChangerProxy that communicates
// to Exporer.exe via COM. It spawns a background thread with a fresh COM
// apartment and requests that the visibility be increased unless the user
// has explicitly set the icon to be hidden.
class NotifyIconHostStateChangerProxyImpl
: public NotifyIconHostStateChangerProxy,
public base::NonThreadSafe {
public:
NotifyIconHostStateChangerProxyImpl()
: pending_requests_(0),
worker_thread_("NotifyIconCOMWorkerThread"),
weak_factory_(this) {
worker_thread_.init_com_with_mta(false);
}
virtual void EnqueueChange(UINT icon_id, HWND window) OVERRIDE {
DCHECK(CalledOnValidThread());
if (pending_requests_ == 0)
worker_thread_.Start();
++pending_requests_;
worker_thread_.message_loop_proxy()->PostTaskAndReply(
FROM_HERE,
base::Bind(
&NotifyIconHostStateChangerProxyImpl::EnqueueChangeOnWorkerThread,
icon_id,
window),
base::Bind(&NotifyIconHostStateChangerProxyImpl::ChangeDone,
weak_factory_.GetWeakPtr()));
}
private:
// Must be called only on |worker_thread_|, to ensure the correct COM
// apartment.
static void EnqueueChangeOnWorkerThread(UINT icon_id, HWND window) {
// It appears that IUnknowns are coincidentally compatible with
// scoped_refptr. Normally I wouldn't depend on that but it seems that
// base::win::IUnknownImpl itself depends on that coincidence so it's
// already being assumed elsewhere.
scoped_refptr<StatusTrayStateChangerWin> status_tray_state_changer(
new StatusTrayStateChangerWin(icon_id, window));
status_tray_state_changer->EnsureTrayIconVisible();
}
// Called on UI thread.
void ChangeDone() {
DCHECK(CalledOnValidThread());
DCHECK_GT(pending_requests_, 0);
if (--pending_requests_ == 0)
worker_thread_.Stop();
}
private:
int pending_requests_;
base::Thread worker_thread_;
base::WeakPtrFactory<NotifyIconHostStateChangerProxyImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NotifyIconHostStateChangerProxyImpl);
};
NotifyIconHost::NotifyIconHost()
: next_icon_id_(1),
atom_(0),
@@ -151,15 +88,6 @@ void NotifyIconHost::Remove(NotifyIcon* icon) {
notify_icons_.erase(i);
}
void NotifyIconHost::UpdateIconVisibilityInBackground(
NotifyIcon* notify_icon) {
if (!state_changer_proxy_.get())
state_changer_proxy_.reset(new NotifyIconHostStateChangerProxyImpl);
state_changer_proxy_->EnqueueChange(notify_icon->icon_id(),
notify_icon->window());
}
LRESULT CALLBACK NotifyIconHost::WndProcStatic(HWND hwnd,
UINT message,
WPARAM wparam,
@@ -204,6 +132,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
return TRUE;
switch (lparam) {
case TB_CHECKBUTTON:
win_icon->NotifyBalloonShow();
return TRUE;
case TB_INDETERMINATE:
win_icon->NotifyBalloonClicked();
return TRUE;
case TB_HIDEBUTTON:
win_icon->NotifyBalloonClosed();
return TRUE;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:

View File

@@ -16,16 +16,6 @@ namespace atom {
class NotifyIcon;
// A class that's responsible for increasing, if possible, the visibility
// of a status tray icon on the taskbar. The default implementation sends
// a task to a worker thread each time EnqueueChange is called.
class NotifyIconHostStateChangerProxy {
public:
// Called by NotifyIconHost to request upgraded visibility on the icon
// represented by the |icon_id|, |window| pair.
virtual void EnqueueChange(UINT icon_id, HWND window) = 0;
};
class NotifyIconHost {
public:
NotifyIconHost();
@@ -34,8 +24,6 @@ class NotifyIconHost {
NotifyIcon* CreateNotifyIcon();
void Remove(NotifyIcon* notify_icon);
void UpdateIconVisibilityInBackground(NotifyIcon* notify_icon);
private:
typedef std::vector<NotifyIcon*> NotifyIcons;
@@ -67,10 +55,6 @@ class NotifyIconHost {
// reset our status icons.
UINT taskbar_created_message_;
// Manages changes performed on a background thread to manipulate visibility
// of notification icons.
scoped_ptr<NotifyIconHostStateChangerProxy> state_changer_proxy_;
DISALLOW_COPY_AND_ASSIGN(NotifyIconHost);
};

View File

@@ -0,0 +1,78 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/x/window_state_watcher.h"
#include <X11/Xlib.h>
#include "ui/events/platform/platform_event_source.h"
namespace atom {
namespace {
const char* kAtomsToCache[] = {
"_NET_WM_STATE",
NULL,
};
} // namespace
WindowStateWatcher::WindowStateWatcher(NativeWindowViews* window)
: window_(window),
widget_(window->GetAcceleratedWidget()),
atom_cache_(gfx::GetXDisplay(), kAtomsToCache),
was_minimized_(false),
was_maximized_(false) {
ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
}
WindowStateWatcher::~WindowStateWatcher() {
ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
}
void WindowStateWatcher::WillProcessEvent(const ui::PlatformEvent& event) {
if (IsWindowStateEvent(event)) {
was_minimized_ = window_->IsMinimized();
was_maximized_ = window_->IsMaximized();
}
}
void WindowStateWatcher::DidProcessEvent(const ui::PlatformEvent& event) {
if (IsWindowStateEvent(event)) {
bool is_minimized = window_->IsMinimized();
bool is_maximized = window_->IsMaximized();
bool is_fullscreen = window_->IsFullscreen();
if (is_minimized != was_minimized_) {
if (is_minimized)
window_->NotifyWindowMinimize();
else
window_->NotifyWindowRestore();
} else if (is_maximized != was_maximized_) {
if (is_maximized)
window_->NotifyWindowMaximize();
else
window_->NotifyWindowUnmaximize();
} else {
// If this is neither a "maximize" or "minimize" event, then we think it
// is a "fullscreen" event.
// The "IsFullscreen()" becomes true immediately before "WillProcessEvent"
// is called, so we can not handle this like "maximize" and "minimize" by
// watching whether they have changed.
if (is_fullscreen)
window_->NotifyWindowEnterFullScreen();
else
window_->NotifyWindowLeaveFullScreen();
}
}
}
bool WindowStateWatcher::IsWindowStateEvent(const ui::PlatformEvent& event) {
::Atom changed_atom = event->xproperty.atom;
return (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE") &&
event->type == PropertyNotify &&
event->xproperty.window == widget_);
}
} // namespace atom

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_
#define ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_
#include "ui/events/platform/platform_event_observer.h"
#include "atom/browser/native_window_views.h"
#include "ui/gfx/x/x11_atom_cache.h"
namespace atom {
class WindowStateWatcher : public ui::PlatformEventObserver {
public:
explicit WindowStateWatcher(NativeWindowViews* window);
virtual ~WindowStateWatcher();
protected:
// ui::PlatformEventObserver:
void WillProcessEvent(const ui::PlatformEvent& event) override;
void DidProcessEvent(const ui::PlatformEvent& event) override;
private:
bool IsWindowStateEvent(const ui::PlatformEvent& event);
NativeWindowViews* window_;
gfx::AcceleratedWidget widget_;
ui::X11AtomCache atom_cache_;
bool was_minimized_;
bool was_maximized_;
DISALLOW_COPY_AND_ASSIGN(WindowStateWatcher);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_

View File

@@ -32,6 +32,19 @@ struct Converter<content::WebContents*> {
}
};
template<>
struct Converter<atom::WebViewManager::WebViewOptions> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
atom::WebViewManager::WebViewOptions* out) {
Dictionary options;
if (!ConvertFromV8(isolate, val, &options))
return false;
return options.Get("nodeIntegration", &(out->node_integration)) &&
options.Get("plugins", &(out->plugins)) &&
options.Get("preloadUrl", &(out->preload_url));
}
};
} // namespace mate
namespace atom {
@@ -43,17 +56,16 @@ WebViewManager::~WebViewManager() {
}
void WebViewManager::AddGuest(int guest_instance_id,
int element_instance_id,
content::WebContents* embedder,
content::WebContents* web_contents,
bool node_integration,
bool plugins,
const GURL& preload_url) {
const WebViewOptions& options) {
web_contents_map_[guest_instance_id] = { web_contents, embedder };
WebViewRendererState::WebViewInfo web_view_info = {
guest_instance_id, node_integration, plugins
guest_instance_id, options.node_integration, options.plugins
};
net::FileURLToFilePath(preload_url, &web_view_info.preload_script);
net::FileURLToFilePath(options.preload_url, &web_view_info.preload_script);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
@@ -61,10 +73,19 @@ void WebViewManager::AddGuest(int guest_instance_id,
base::Unretained(WebViewRendererState::GetInstance()),
web_contents->GetRenderProcessHost()->GetID(),
web_view_info));
// Map the element in embedder to guest.
ElementInstanceKey key(embedder, element_instance_id);
element_instance_id_to_guest_map_[key] = guest_instance_id;
}
void WebViewManager::RemoveGuest(int guest_instance_id) {
if (!ContainsKey(web_contents_map_, guest_instance_id)) {
return;
}
auto web_contents = web_contents_map_[guest_instance_id].web_contents;
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(
@@ -73,16 +94,27 @@ void WebViewManager::RemoveGuest(int guest_instance_id) {
web_contents->GetRenderProcessHost()->GetID()));
web_contents_map_.erase(guest_instance_id);
// Remove the record of element in embedder too.
for (const auto& element : element_instance_id_to_guest_map_)
if (element.second == guest_instance_id) {
element_instance_id_to_guest_map_.erase(element.first);
break;
}
}
void WebViewManager::MaybeGetGuestByInstanceIDOrKill(
int guest_instance_id,
int embedder_render_process_id,
const GuestByInstanceIDCallback& callback) {
content::WebContents* WebViewManager::GetGuestByInstanceID(
content::WebContents* embedder,
int element_instance_id) {
ElementInstanceKey key(embedder, element_instance_id);
if (!ContainsKey(element_instance_id_to_guest_map_, key))
return nullptr;
int guest_instance_id = element_instance_id_to_guest_map_[key];
if (ContainsKey(web_contents_map_, guest_instance_id))
callback.Run(web_contents_map_[guest_instance_id].web_contents);
return web_contents_map_[guest_instance_id].web_contents;
else
callback.Run(nullptr);
return nullptr;
}
bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents,

View File

@@ -8,6 +8,7 @@
#include <map>
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
@@ -20,22 +21,26 @@ class WebViewManager : public content::BrowserPluginGuestManager {
explicit WebViewManager(content::BrowserContext* context);
virtual ~WebViewManager();
struct WebViewOptions {
bool node_integration;
bool plugins;
GURL preload_url;
};
void AddGuest(int guest_instance_id,
int element_instance_id,
content::WebContents* embedder,
content::WebContents* web_contents,
bool node_integration,
bool plugins,
const GURL& preload_url);
const WebViewOptions& options);
void RemoveGuest(int guest_instance_id);
protected:
// content::BrowserPluginGuestManager:
virtual void MaybeGetGuestByInstanceIDOrKill(
int guest_instance_id,
int embedder_render_process_id,
const GuestByInstanceIDCallback& callback) override;
virtual bool ForEachGuest(content::WebContents* embedder_web_contents,
const GuestCallback& callback) override;
content::WebContents* GetGuestByInstanceID(
content::WebContents* embedder_web_contents,
int element_instance_id) override;
bool ForEachGuest(content::WebContents* embedder,
const GuestCallback& callback) override;
private:
struct WebContentsWithEmbedder {
@@ -44,6 +49,32 @@ class WebViewManager : public content::BrowserPluginGuestManager {
};
std::map<int, WebContentsWithEmbedder> web_contents_map_;
struct ElementInstanceKey {
content::WebContents* owner_web_contents;
int element_instance_id;
ElementInstanceKey()
: owner_web_contents(nullptr),
element_instance_id(0) {}
ElementInstanceKey(content::WebContents* owner_web_contents,
int element_instance_id)
: owner_web_contents(owner_web_contents),
element_instance_id(element_instance_id) {}
bool operator<(const ElementInstanceKey& other) const {
if (owner_web_contents != other.owner_web_contents)
return owner_web_contents < other.owner_web_contents;
return element_instance_id < other.element_instance_id;
}
bool operator==(const ElementInstanceKey& other) const {
return (owner_web_contents == other.owner_web_contents) &&
(element_instance_id == other.element_instance_id);
}
};
std::map<ElementInstanceKey, int> element_instance_id_to_guest_map_;
DISALLOW_COPY_AND_ASSIGN(WebViewManager);
};

View File

@@ -58,8 +58,7 @@ base::string16 ReadText(ui::ClipboardType type) {
}
void WriteText(const base::string16& text, ui::ClipboardType type) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::ScopedClipboardWriter writer(clipboard, type);
ui::ScopedClipboardWriter writer(type);
writer.WriteText(text);
}

View File

@@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 19
#define ATOM_PATCH_VERSION 3
#define ATOM_MINOR_VERSION 20
#define ATOM_PATCH_VERSION 1
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -8,7 +8,7 @@
#ifndef ATOM_COMMON_CHROME_VERSION_H_
#define ATOM_COMMON_CHROME_VERSION_H_
#define CHROME_VERSION_STRING "38.0.2125.101"
#define CHROME_VERSION_STRING "39.0.2171.65"
#define CHROME_VERSION "v" CHROME_VERSION_STRING
#endif // ATOM_COMMON_CHROME_VERSION_H_

View File

@@ -4,6 +4,7 @@
#include "atom/common/crash_reporter/crash_reporter_mac.h"
#include "base/mac/mac_util.h"
#include "base/memory/singleton.h"
#include "base/strings/sys_string_conversions.h"
#import "vendor/breakpad/src/client/apple/Framework/BreakpadDefines.h"
@@ -54,7 +55,19 @@ void CrashReporterMac::InitBreakpad(const std::string& product_name,
[parameters setValue:base::SysUTF8ToNSString(dump_dir)
forKey:@BREAKPAD_DUMP_DIRECTORY];
// Temporarily run Breakpad in-process on 10.10 and later because APIs that
// it depends on got broken (http://crbug.com/386208).
// This can catch crashes in the browser process only.
if (base::mac::IsOSYosemiteOrLater()) {
[parameters setObject:[NSNumber numberWithBool:YES]
forKey:@BREAKPAD_IN_PROCESS];
}
breakpad_ = BreakpadCreate(parameters);
if (!breakpad_) {
LOG(ERROR) << "Failed to initialize breakpad";
return;
}
for (StringMap::const_iterator iter = upload_parameters_.begin();
iter != upload_parameters_.end(); ++iter) {

View File

@@ -456,7 +456,7 @@ DWORD CrashService::AsyncSendDump(void* context) {
default:
report_id = L"<unknown>";
break;
};
}
}
VLOG(1) << "dump for pid =" << info->pid << " crash2 id =" << report_id;

View File

@@ -4,6 +4,7 @@
#include "atom/common/native_mate_converters/v8_value_converter.h"
#include <map>
#include <string>
#include <utility>
@@ -13,12 +14,70 @@
namespace atom {
namespace {
const int kMaxRecursionDepth = 100;
} // namespace
// The state of a call to FromV8Value.
class V8ValueConverter::FromV8ValueState {
public:
// Level scope which updates the current depth of some FromV8ValueState.
class Level {
public:
explicit Level(FromV8ValueState* state) : state_(state) {
state_->max_recursion_depth_--;
}
~Level() {
state_->max_recursion_depth_++;
}
private:
FromV8ValueState* state_;
};
FromV8ValueState() : max_recursion_depth_(kMaxRecursionDepth) {}
// If |handle| is not in |unique_map_|, then add it to |unique_map_| and
// return true.
//
// Otherwise do nothing and return false. Here "A is unique" means that no
// other handle B in the map points to the same object as A. Note that A can
// be unique even if there already is another handle with the same identity
// hash (key) in the map, because two objects can have the same hash.
bool UpdateAndCheckUniqueness(v8::Handle<v8::Object> handle) {
typedef HashToHandleMap::const_iterator Iterator;
int hash = handle->GetIdentityHash();
// We only compare using == with handles to objects with the same identity
// hash. Different hash obviously means different objects, but two objects
// in a couple of thousands could have the same identity hash.
std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash);
for (Iterator it = range.first; it != range.second; ++it) {
// Operator == for handles actually compares the underlying objects.
if (it->second == handle)
return false;
}
unique_map_.insert(std::make_pair(hash, handle));
return true;
}
bool HasReachedMaxRecursionDepth() {
return max_recursion_depth_ < 0;
}
private:
typedef std::multimap<int, v8::Handle<v8::Object> > HashToHandleMap;
HashToHandleMap unique_map_;
int max_recursion_depth_;
};
V8ValueConverter::V8ValueConverter()
: date_allowed_(false),
reg_exp_allowed_(false),
function_allowed_(false),
strip_null_from_objects_(false),
avoid_identity_hash_for_testing_(false) {}
strip_null_from_objects_(false) {}
void V8ValueConverter::SetDateAllowed(bool val) {
date_allowed_ = val;
@@ -48,8 +107,8 @@ base::Value* V8ValueConverter::FromV8Value(
v8::Local<v8::Context> context) const {
v8::Context::Scope context_scope(context);
v8::HandleScope handle_scope(context->GetIsolate());
HashToHandleMap unique_map;
return FromV8ValueImpl(val, &unique_map);
FromV8ValueState state;
return FromV8ValueImpl(&state, val, context->GetIsolate());
}
v8::Local<v8::Value> V8ValueConverter::ToV8ValueImpl(
@@ -141,10 +200,16 @@ v8::Local<v8::Value> V8ValueConverter::ToV8Object(
return result;
}
base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local<v8::Value> val,
HashToHandleMap* unique_map) const {
base::Value* V8ValueConverter::FromV8ValueImpl(
FromV8ValueState* state,
v8::Handle<v8::Value> val,
v8::Isolate* isolate) const {
CHECK(!val.IsEmpty());
FromV8ValueState::Level state_level(state);
if (state->HasReachedMaxRecursionDepth())
return NULL;
if (val->IsNull())
return base::Value::CreateNullValue();
@@ -170,7 +235,7 @@ base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local<v8::Value> val,
if (!date_allowed_)
// JSON.stringify would convert this to a string, but an object is more
// consistent within this class.
return FromV8Object(val->ToObject(), unique_map);
return FromV8Object(val->ToObject(), state, isolate);
v8::Date* date = v8::Date::Cast(*val);
return new base::FundamentalValue(date->NumberValue() / 1000.0);
}
@@ -178,35 +243,36 @@ base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local<v8::Value> val,
if (val->IsRegExp()) {
if (!reg_exp_allowed_)
// JSON.stringify converts to an object.
return FromV8Object(val->ToObject(), unique_map);
return FromV8Object(val->ToObject(), state, isolate);
return new base::StringValue(*v8::String::Utf8Value(val->ToString()));
}
// v8::Value doesn't have a ToArray() method for some reason.
if (val->IsArray())
return FromV8Array(val.As<v8::Array>(), unique_map);
return FromV8Array(val.As<v8::Array>(), state, isolate);
if (val->IsFunction()) {
if (!function_allowed_)
// JSON.stringify refuses to convert function(){}.
return NULL;
return FromV8Object(val->ToObject(), unique_map);
return FromV8Object(val->ToObject(), state, isolate);
}
if (val->IsObject()) {
return FromV8Object(val->ToObject(), unique_map);
return FromV8Object(val->ToObject(), state, isolate);
}
LOG(ERROR) << "Unexpected v8 value type encountered.";
return NULL;
}
base::Value* V8ValueConverter::FromV8Array(v8::Local<v8::Array> val,
HashToHandleMap* unique_map) const {
if (!UpdateAndCheckUniqueness(unique_map, val))
base::Value* V8ValueConverter::FromV8Array(
v8::Handle<v8::Array> val,
FromV8ValueState* state,
v8::Isolate* isolate) const {
if (!state->UpdateAndCheckUniqueness(val))
return base::Value::CreateNullValue();
v8::Isolate* isolate = v8::Isolate::GetCurrent();
scoped_ptr<v8::Context::Scope> scope;
// If val was created in a different context than our current one, change to
// that context, but change back after val is converted.
@@ -228,7 +294,10 @@ base::Value* V8ValueConverter::FromV8Array(v8::Local<v8::Array> val,
if (!val->HasRealIndexedProperty(i))
continue;
base::Value* child = FromV8ValueImpl(child_v8, unique_map);
// When parsing elements in an array, we use a new state so we can have the
// same object showed twice in array.
FromV8ValueState new_state;
base::Value* child = FromV8ValueImpl(&new_state, child_v8, isolate);
if (child)
result->Append(child);
else
@@ -241,10 +310,11 @@ base::Value* V8ValueConverter::FromV8Array(v8::Local<v8::Array> val,
base::Value* V8ValueConverter::FromV8Object(
v8::Local<v8::Object> val,
HashToHandleMap* unique_map) const {
if (!UpdateAndCheckUniqueness(unique_map, val))
FromV8ValueState* state,
v8::Isolate* isolate) const {
if (!state->UpdateAndCheckUniqueness(val))
return base::Value::CreateNullValue();
v8::Isolate* isolate = v8::Isolate::GetCurrent();
scoped_ptr<v8::Context::Scope> scope;
// If val was created in a different context than our current one, change to
// that context, but change back after val is converted.
@@ -281,7 +351,7 @@ base::Value* V8ValueConverter::FromV8Object(
child_v8 = v8::Null(isolate);
}
scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map));
scoped_ptr<base::Value> child(FromV8ValueImpl(state, child_v8, isolate));
if (!child.get())
// JSON.stringify skips properties whose values don't serialize, for
// example undefined and functions. Emulate that behavior.
@@ -317,24 +387,4 @@ base::Value* V8ValueConverter::FromV8Object(
return result.release();
}
bool V8ValueConverter::UpdateAndCheckUniqueness(
HashToHandleMap* map,
v8::Local<v8::Object> handle) const {
typedef HashToHandleMap::const_iterator Iterator;
int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash();
// We only compare using == with handles to objects with the same identity
// hash. Different hash obviously means different objects, but two objects in
// a couple of thousands could have the same identity hash.
std::pair<Iterator, Iterator> range = map->equal_range(hash);
for (Iterator it = range.first; it != range.second; ++it) {
// Operator == for handles actually compares the underlying objects.
if (it->second == handle)
return false;
}
map->insert(std::pair<int, v8::Local<v8::Object> >(hash, handle));
return true;
}
} // namespace atom

View File

@@ -5,8 +5,6 @@
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_
#include <map>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "v8/include/v8.h"
@@ -34,7 +32,7 @@ class V8ValueConverter {
v8::Local<v8::Context> context) const;
private:
typedef std::multimap<int, v8::Local<v8::Object> > HashToHandleMap;
class FromV8ValueState;
v8::Local<v8::Value> ToV8ValueImpl(v8::Isolate* isolate,
const base::Value* value) const;
@@ -44,21 +42,16 @@ class V8ValueConverter {
v8::Isolate* isolate,
const base::DictionaryValue* dictionary) const;
base::Value* FromV8ValueImpl(v8::Local<v8::Value> value,
HashToHandleMap* unique_map) const;
base::Value* FromV8Array(v8::Local<v8::Array> array,
HashToHandleMap* unique_map) const;
base::Value* FromV8ValueImpl(FromV8ValueState* state,
v8::Handle<v8::Value> value,
v8::Isolate* isolate) const;
base::Value* FromV8Array(v8::Handle<v8::Array> array,
FromV8ValueState* state,
v8::Isolate* isolate) const;
base::Value* FromV8Object(v8::Local<v8::Object> object,
HashToHandleMap* unique_map) const;
// If |handle| is not in |map|, then add it to |map| and return true.
// Otherwise do nothing and return false. Here "A is unique" means that no
// other handle B in the map points to the same object as A. Note that A can
// be unique even if there already is another handle with the same identity
// hash (key) in the map, because two objects can have the same hash.
bool UpdateAndCheckUniqueness(HashToHandleMap* map,
v8::Local<v8::Object> handle) const;
FromV8ValueState* state,
v8::Isolate* isolate) const;
// If true, we will convert Date JavaScript objects to doubles.
bool date_allowed_;
@@ -73,8 +66,6 @@ class V8ValueConverter {
// into Values.
bool strip_null_from_objects_;
bool avoid_identity_hash_for_testing_;
DISALLOW_COPY_AND_ASSIGN(V8ValueConverter);
};

View File

@@ -89,6 +89,19 @@ namespace {
void UvNoOp(uv_async_t* handle) {
}
// Moved from node.cc.
void HandleCloseCb(uv_handle_t* handle) {
node::Environment* env = reinterpret_cast<node::Environment*>(handle->data);
env->FinishHandleCleanup(handle);
}
void HandleCleanup(node::Environment* env,
uv_handle_t* handle,
void* arg) {
handle->data = env;
uv_close(handle, HandleCloseCb);
}
// Convert the given vector to an array of C-strings. The strings in the
// returned vector are only guaranteed valid so long as the vector of strings
// is not modified.
@@ -181,6 +194,7 @@ node::Environment* NodeBindings::CreateEnvironment(
// Construct the parameters that passed to node::CreateEnvironment:
v8::Isolate* isolate = context->GetIsolate();
uv_loop_t* loop = uv_default_loop();
int argc = args.size();
const char** argv = c_argv.get();
int exec_argc = 0;
@@ -191,13 +205,16 @@ node::Environment* NodeBindings::CreateEnvironment(
// Following code are stripped from node::CreateEnvironment in node.cc:
HandleScope handle_scope(isolate);
Context::Scope context_scope(context);
Environment* env = Environment::New(context);
Context::Scope context_scope(context);
Environment* env = Environment::New(context, loop);
isolate->SetAutorunMicrotasks(false);
uv_check_init(env->event_loop(), env->immediate_check_handle());
uv_unref(
reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()));
uv_idle_init(env->event_loop(), env->immediate_idle_handle());
uv_prepare_init(env->event_loop(), env->idle_prepare_handle());
@@ -205,6 +222,24 @@ node::Environment* NodeBindings::CreateEnvironment(
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()));
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()));
// Register handle cleanups
env->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()),
HandleCleanup,
nullptr);
env->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(env->immediate_idle_handle()),
HandleCleanup,
nullptr);
env->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()),
HandleCleanup,
nullptr);
env->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(env->idle_check_handle()),
HandleCleanup,
nullptr);
Local<FunctionTemplate> process_template = FunctionTemplate::New(isolate);
process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process"));
@@ -212,7 +247,7 @@ node::Environment* NodeBindings::CreateEnvironment(
env->set_process_object(process_object);
SetupProcessObject(env, argc, argv, exec_argc, exec_argv);
Load(env);
LoadEnvironment(env);
return env;
}

View File

@@ -5,6 +5,7 @@
#include "atom/renderer/api/atom_api_web_frame.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "content/public/renderer/render_frame.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "third_party/WebKit/public/web/WebDocument.h"
@@ -51,6 +52,10 @@ v8::Handle<v8::Value> WebFrame::RegisterEmbedderCustomElement(
return web_frame_->document().registerEmbedderCustomElement(name, options, c);
}
void WebFrame::AttachGuest(int id) {
content::RenderFrame::FromWebFrame(web_frame_)->AttachGuest(id);
}
mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
@@ -60,7 +65,8 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
.SetMethod("setZoomFactor", &WebFrame::SetZoomFactor)
.SetMethod("getZoomFactor", &WebFrame::GetZoomFactor)
.SetMethod("registerEmbedderCustomElement",
&WebFrame::RegisterEmbedderCustomElement);
&WebFrame::RegisterEmbedderCustomElement)
.SetMethod("attachGuest", &WebFrame::AttachGuest);
}
// static

View File

@@ -35,6 +35,7 @@ class WebFrame : public mate::Wrappable {
v8::Handle<v8::Value> RegisterEmbedderCustomElement(
const base::string16& name, v8::Handle<v8::Object> options);
void AttachGuest(int element_instance_id);
// mate::Wrappable:
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(

View File

@@ -16,6 +16,9 @@ class Ipc extends EventEmitter
sendSync: (args...) ->
JSON.parse ipc.sendSync('ipc-message-sync', [args...])
sendToHost: (args...) ->
ipc.send 'ipc-message-host', [args...]
# Discarded
sendChannel: -> @send.apply this, arguments
sendChannelSync: -> @sendSync.apply this, arguments

View File

@@ -40,7 +40,7 @@ metaToValue = (meta) ->
constructor: ->
if @constructor == RemoteFunction
# Constructor call.
obj = ipc.sendChannelSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)
obj = ipc.sendSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)
# Returning object in constructor will replace constructed object
# with the returned object.
@@ -48,7 +48,7 @@ metaToValue = (meta) ->
return metaToValue obj
else
# Function call.
ret = ipc.sendChannelSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)
ret = ipc.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)
return metaToValue ret
else
ret = v8Util.createObjectWithName meta.name
@@ -62,27 +62,27 @@ metaToValue = (meta) ->
constructor: ->
if @constructor is RemoteMemberFunction
# Constructor call.
obj = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', meta.id, member.name, wrapArgs(arguments)
obj = ipc.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', meta.id, member.name, wrapArgs(arguments)
return metaToValue obj
else
# Call member function.
ret = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
return metaToValue ret
else
ret.__defineSetter__ member.name, (value) ->
# Set member data.
ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
ipc.sendSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
value
ret.__defineGetter__ member.name, ->
# Get member data.
ret = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
metaToValue ret
# Track delegate object's life time, and tell the browser to clean up
# when the object is GCed.
v8Util.setDestructor ret, ->
ipc.sendChannel 'ATOM_BROWSER_DEREFERENCE', meta.storeId
ipc.send 'ATOM_BROWSER_DEREFERENCE', meta.storeId
# Remember object's id.
v8Util.setHiddenValue ret, 'atomId', meta.id
@@ -104,19 +104,19 @@ moduleCache = {}
exports.require = (module) ->
return moduleCache[module] if moduleCache[module]?
meta = ipc.sendChannelSync 'ATOM_BROWSER_REQUIRE', module
meta = ipc.sendSync 'ATOM_BROWSER_REQUIRE', module
moduleCache[module] = metaToValue meta
# Get current window object.
windowCache = null
exports.getCurrentWindow = ->
return windowCache if windowCache?
meta = ipc.sendChannelSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId
meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId
windowCache = metaToValue meta
# Get a global object in browser.
exports.getGlobal = (name) ->
meta = ipc.sendChannelSync 'ATOM_BROWSER_GLOBAL', name
meta = ipc.sendSync 'ATOM_BROWSER_GLOBAL', name
metaToValue meta
# Get the process object in browser.
@@ -133,5 +133,5 @@ exports.createFunctionWithReturnValue = (returnValue) ->
# Get the guest WebContents from guestInstanceId.
exports.getGuestWebContents = (guestInstanceId) ->
meta = ipc.sendChannelSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId
meta = ipc.sendSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId
metaToValue meta

View File

@@ -92,7 +92,7 @@ void AtomRendererClient::WebKitInitialized() {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
global_env = node::Environment::New(context);
global_env = node::Environment::New(context, uv_default_loop());
}
void AtomRendererClient::RenderThreadStarted() {
@@ -161,7 +161,7 @@ void AtomRendererClient::DidCreateScriptContext(blink::WebFrame* frame,
}
void AtomRendererClient::WillReleaseScriptContext(
blink::WebFrame* frame,
blink::WebLocalFrame* frame,
v8::Handle<v8::Context> context,
int world_id) {
node::Environment* env = node::Environment::GetCurrent(context);

View File

@@ -27,7 +27,7 @@ class AtomRendererClient : public content::ContentRendererClient,
virtual ~AtomRendererClient();
// Forwarded by RenderFrameObserver.
void WillReleaseScriptContext(blink::WebFrame* frame,
void WillReleaseScriptContext(blink::WebLocalFrame* frame,
v8::Handle<v8::Context> context,
int world_id);

View File

@@ -36,17 +36,19 @@ for arg in process.argv
if location.protocol is 'chrome-devtools:'
# Override some inspector APIs.
require path.join(__dirname, 'inspector')
require './inspector'
nodeIntegration = 'true'
else if location.protocol is 'chrome-extension:'
# Add implementations of chrome API.
require path.join(__dirname, 'chrome-api')
require './chrome-api'
nodeIntegration = 'true'
else
# Override default web functions.
require path.join(__dirname, 'override')
require './override'
# Load webview tag implementation.
require path.join(__dirname, 'web-view') unless process.guestInstanceId?
unless process.guestInstanceId?
require './web-view/web-view'
require './web-view/web-view-attributes'
if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe']
# Export node bindings to global.

View File

@@ -1,590 +0,0 @@
v8Util = process.atomBinding 'v8_util'
guestViewInternal = require './guest-view-internal'
webFrame = require 'web-frame'
remote = require 'remote'
# ID generator.
nextId = 0
getNextId = -> ++nextId
# FIXME
# Discarded after Chrome 39
PLUGIN_METHOD_ATTACH = '-internal-attach'
# Attributes.
WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY = 'allowtransparency'
WEB_VIEW_ATTRIBUTE_AUTOSIZE = 'autosize'
WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'
WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'
WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'
WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'
WEB_VIEW_ATTRIBUTE_PARTITION = 'partition'
WEB_VIEW_ATTRIBUTE_NODEINTEGRATION = 'nodeintegration'
WEB_VIEW_ATTRIBUTE_PLUGINS = 'plugins'
WEB_VIEW_ATTRIBUTE_PRELOAD = 'preload'
AUTO_SIZE_ATTRIBUTES = [
WEB_VIEW_ATTRIBUTE_AUTOSIZE,
WEB_VIEW_ATTRIBUTE_MAXHEIGHT,
WEB_VIEW_ATTRIBUTE_MAXWIDTH,
WEB_VIEW_ATTRIBUTE_MINHEIGHT,
WEB_VIEW_ATTRIBUTE_MINWIDTH,
]
# Error messages.
ERROR_MSG_ALREADY_NAVIGATED =
'The object has already navigated, so its partition cannot be changed.'
ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview>: ' +
'Script cannot be injected into content until the page has loaded.'
ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = '<webview>: ' +
'contentWindow is not available at this time. It will become available ' +
'when the page has finished loading.'
ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.'
ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE =
'Only "file:" or "asar:" protocol is supported in "preload" attribute.'
# Represents the state of the storage partition.
class Partition
constructor: ->
@validPartitionId = true
@persistStorage = false
@storagePartitionId = ''
toAttribute: ->
return '' unless @validPartitionId
(if @persistStorage then 'persist:' else '') + @storagePartitionId
fromAttribute: (value, hasNavigated) ->
result = {}
if hasNavigated
result.error = ERROR_MSG_ALREADY_NAVIGATED
return result
value ?= ''
LEN = 'persist:'.length
if value.substr(0, LEN) == 'persist:'
value = value.substr LEN
unless value
@validPartitionId = false
result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE
return result
@persistStorage = true
else
@persistStorage = false
@storagePartitionId = value
result
# Represents the internal state of the WebView node.
class WebView
constructor: (@webviewNode) ->
v8Util.setHiddenValue @webviewNode, 'internal', this
@attached = false
@pendingGuestCreation = false
@elementAttached = false
@beforeFirstNavigation = true
@contentWindow = null
@validPartitionId = true
# Used to save some state upon deferred attachment.
# If <object> bindings is not available, we defer attachment.
# This state contains whether or not the attachment request was for
# newwindow.
@deferredAttachState = null
# on* Event handlers.
@on = {}
@browserPluginNode = @createBrowserPluginNode()
shadowRoot = @webviewNode.createShadowRoot()
@partition = new Partition()
@setupWebViewSrcAttributeMutationObserver()
@setupFocusPropagation()
@setupWebviewNodeProperties()
@viewInstanceId = getNextId()
guestViewInternal.registerEvents this, @viewInstanceId
shadowRoot.appendChild @browserPluginNode
createBrowserPluginNode: ->
# We create BrowserPlugin as a custom element in order to observe changes
# to attributes synchronously.
browserPluginNode = new WebView.BrowserPlugin()
v8Util.setHiddenValue browserPluginNode, 'internal', this
browserPluginNode
getGuestInstanceId: ->
@guestInstanceId
# Resets some state upon reattaching <webview> element to the DOM.
reset: ->
# If guestInstanceId is defined then the <webview> has navigated and has
# already picked up a partition ID. Thus, we need to reset the initialization
# state. However, it may be the case that beforeFirstNavigation is false BUT
# guestInstanceId has yet to be initialized. This means that we have not
# heard back from createGuest yet. We will not reset the flag in this case so
# that we don't end up allocating a second guest.
if @guestInstanceId
guestViewInternal.destroyGuest @guestInstanceId
@guestInstanceId = undefined
@beforeFirstNavigation = true
@validPartitionId = true
@partition.validPartitionId = true
@contentWindow = null
@internalInstanceId = 0
# Sets the <webview>.request property.
setRequestPropertyOnWebViewNode: (request) ->
Object.defineProperty @webviewNode, 'request', value: request, enumerable: true
setupFocusPropagation: ->
unless @webviewNode.hasAttribute 'tabIndex'
# <webview> needs a tabIndex in order to be focusable.
# TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
# to allow <webview> to be focusable.
# See http://crbug.com/231664.
@webviewNode.setAttribute 'tabIndex', -1
@webviewNode.addEventListener 'focus', (e) =>
# Focus the BrowserPlugin when the <webview> takes focus.
@browserPluginNode.focus()
@webviewNode.addEventListener 'blur', (e) =>
# Blur the BrowserPlugin when the <webview> loses focus.
@browserPluginNode.blur()
# Validation helper function for executeScript() and insertCSS().
validateExecuteCodeCall: ->
throw new Error(ERROR_MSG_CANNOT_INJECT_SCRIPT) unless @guestInstanceId
setupAutoSizeProperties: ->
for attributeName in AUTO_SIZE_ATTRIBUTES
this[attributeName] = @webviewNode.getAttribute attributeName
Object.defineProperty @webviewNode, attributeName,
get: => this[attributeName]
set: (value) => @webviewNode.setAttribute attributeName, value
enumerable: true
setupWebviewNodeProperties: ->
@setupAutoSizeProperties()
Object.defineProperty @webviewNode, WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY,
get: => @allowtransparency
set: (value) =>
@webviewNode.setAttribute WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY, value
enumerable: true
# We cannot use {writable: true} property descriptor because we want a
# dynamic getter value.
Object.defineProperty @webviewNode, 'contentWindow',
get: =>
return @contentWindow if @contentWindow?
window.console.error ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE
# No setter.
enumerable: true
Object.defineProperty @webviewNode, 'partition',
get: => @partition.toAttribute()
set: (value) =>
result = @partition.fromAttribute value, @hasNavigated()
throw result.error if result.error?
@webviewNode.setAttribute 'partition', value
enumerable: true
@src = @webviewNode.getAttribute 'src'
Object.defineProperty @webviewNode, 'src',
get: => @src
set: (value) => @webviewNode.setAttribute 'src', value
# No setter.
enumerable: true
@httpreferrer = @webviewNode.getAttribute 'httpreferrer'
Object.defineProperty @webviewNode, 'httpreferrer',
get: => @httpreferrer
set: (value) => @webviewNode.setAttribute 'httpreferrer', value
enumerable: true
# The purpose of this mutation observer is to catch assignment to the src
# attribute without any changes to its value. This is useful in the case
# where the webview guest has crashed and navigating to the same address
# spawns off a new process.
setupWebViewSrcAttributeMutationObserver: ->
@srcAndPartitionObserver = new MutationObserver (mutations) =>
for mutation in mutations
oldValue = mutation.oldValue
newValue = @webviewNode.getAttribute mutation.attributeName
return if oldValue isnt newValue
@handleWebviewAttributeMutation mutation.attributeName, oldValue, newValue
params =
attributes: true,
attributeOldValue: true,
attributeFilter: ['src', 'partition', 'httpreferrer']
@srcAndPartitionObserver.observe @webviewNode, params
# This observer monitors mutations to attributes of the <webview> and
# updates the BrowserPlugin properties accordingly. In turn, updating
# a BrowserPlugin property will update the corresponding BrowserPlugin
# attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
# details.
handleWebviewAttributeMutation: (name, oldValue, newValue) ->
if name in AUTO_SIZE_ATTRIBUTES
this[name] = newValue
return unless @guestInstanceId
# Convert autosize attribute to boolean.
autosize = @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_AUTOSIZE
guestViewInternal.setAutoSize @guestInstanceId,
enableAutoSize: autosize,
min:
width: parseInt @minwidth || 0
height: parseInt @minheight || 0
max:
width: parseInt @maxwidth || 0
height: parseInt @maxheight || 0
else if name is WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY
# We treat null attribute (attribute removed) and the empty string as
# one case.
oldValue ?= ''
newValue ?= ''
return if oldValue is newValue
@allowtransparency = newValue != ''
return unless @guestInstanceId
guestViewInternal.setAllowTransparency @guestInstanceId, @allowtransparency
else if name is 'httpreferrer'
oldValue ?= ''
newValue ?= ''
if newValue == '' and oldValue != ''
@webviewNode.setAttribute 'httpreferrer', oldValue
@httpreferrer = newValue
result = {}
# If the httpreferrer changes treat it as though the src changes and reload
# the page with the new httpreferrer.
@parseSrcAttribute result
throw result.error if result.error?
else if name is 'src'
# We treat null attribute (attribute removed) and the empty string as
# one case.
oldValue ?= ''
newValue ?= ''
# Once we have navigated, we don't allow clearing the src attribute.
# Once <webview> enters a navigated state, it cannot be return back to a
# placeholder state.
if newValue == '' and oldValue != ''
# src attribute changes normally initiate a navigation. We suppress
# the next src attribute handler call to avoid reloading the page
# on every guest-initiated navigation.
@ignoreNextSrcAttributeChange = true
@webviewNode.setAttribute 'src', oldValue
@src = newValue
if @ignoreNextSrcAttributeChange
# Don't allow the src mutation observer to see this change.
@srcAndPartitionObserver.takeRecords()
@ignoreNextSrcAttributeChange = false
return
result = {}
@parseSrcAttribute result
throw result.error if result.error?
else if name is 'partition'
# Note that throwing error here won't synchronously propagate.
@partition.fromAttribute newValue, @hasNavigated()
handleBrowserPluginAttributeMutation: (name, oldValue, newValue) ->
# FIXME
# internalbindings => internalInstanceid after Chrome 39
if name is 'internalbindings' and !oldValue and !!newValue
@browserPluginNode.removeAttribute 'internalbindings'
# FIXME
# @internalInstanceId = parseInt newValue
if !!@guestInstanceId and @guestInstanceId != 0
isNewWindow = if @deferredAttachState then @deferredAttachState.isNewWindow else false
params = @buildAttachParams isNewWindow
# FIXME
# guestViewInternalNatives.AttachGuest
# @internalInstanceId,
# @guestInstanceId,
# params,
# (w) => @contentWindow = w
@browserPluginNode[PLUGIN_METHOD_ATTACH] @guestInstanceId, params
onSizeChanged: (webViewEvent) ->
newWidth = webViewEvent.newWidth
newHeight = webViewEvent.newHeight
node = @webviewNode
width = node.offsetWidth
height = node.offsetHeight
# Check the current bounds to make sure we do not resize <webview>
# outside of current constraints.
if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXWIDTH) and
node[WEB_VIEW_ATTRIBUTE_MAXWIDTH]
maxWidth = node[WEB_VIEW_ATTRIBUTE_MAXWIDTH]
else
maxWidth = width
if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINWIDTH) and
node[WEB_VIEW_ATTRIBUTE_MINWIDTH]
minWidth = node[WEB_VIEW_ATTRIBUTE_MINWIDTH]
else
minWidth = width
minWidth = maxWidth if minWidth > maxWidth
if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXHEIGHT) and
node[WEB_VIEW_ATTRIBUTE_MAXHEIGHT]
maxHeight = node[WEB_VIEW_ATTRIBUTE_MAXHEIGHT]
else
maxHeight = height
if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINHEIGHT) and
node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]
minHeight = node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]
else
minHeight = height
minHeight = maxHeight if minHeight > maxHeight
if not @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_AUTOSIZE or
(newWidth >= minWidth and
newWidth <= maxWidth and
newHeight >= minHeight and
newHeight <= maxHeight)
node.style.width = newWidth + 'px'
node.style.height = newHeight + 'px'
# Only fire the DOM event if the size of the <webview> has actually
# changed.
@dispatchEvent webViewEvent
# Returns if <object> is in the render tree.
isPluginInRenderTree: ->
# FIXME
# !!@internalInstanceId && @internalInstanceId != 0
'function' == typeof this.browserPluginNode[PLUGIN_METHOD_ATTACH]
hasNavigated: ->
not @beforeFirstNavigation
parseSrcAttribute: (result) ->
unless @partition.validPartitionId
result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE
return
@src = @webviewNode.getAttribute 'src'
return unless @src
unless @guestInstanceId?
if @beforeFirstNavigation
@beforeFirstNavigation = false
@createGuest()
return
# Navigate to |this.src|.
urlOptions = if @httpreferrer then {@httpreferrer} else {}
remote.getGuestWebContents(@guestInstanceId).loadUrl @src, urlOptions
parseAttributes: ->
return unless @elementAttached
hasNavigated = @hasNavigated()
attributeValue = @webviewNode.getAttribute 'partition'
result = @partition.fromAttribute attributeValue, hasNavigated
@parseSrcAttribute result
createGuest: ->
return if @pendingGuestCreation
storagePartitionId =
@webviewNode.getAttribute(WEB_VIEW_ATTRIBUTE_PARTITION) or
@webviewNode[WEB_VIEW_ATTRIBUTE_PARTITION]
params =
storagePartitionId: storagePartitionId
nodeIntegration: @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_NODEINTEGRATION
plugins: @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_PLUGINS
if @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_PRELOAD
preload = @webviewNode.getAttribute WEB_VIEW_ATTRIBUTE_PRELOAD
# Get the full path.
a = document.createElement 'a'
a.href = preload
params.preload = a.href
# Only support file: or asar: protocol.
protocol = params.preload.substr 0, 5
unless protocol in ['file:', 'asar:']
delete params.preload
console.error ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE
guestViewInternal.createGuest 'webview', params, (guestInstanceId) =>
@pendingGuestCreation = false
unless @elementAttached
guestViewInternal.destroyGuest guestInstanceId
return
@attachWindow guestInstanceId, false
@pendingGuestCreation = true
dispatchEvent: (webViewEvent) ->
@webviewNode.dispatchEvent webViewEvent
# Adds an 'on<event>' property on the webview, which can be used to set/unset
# an event handler.
setupEventProperty: (eventName) ->
propertyName = 'on' + eventName.toLowerCase()
Object.defineProperty @webviewNode, propertyName,
get: => @on[propertyName]
set: (value) =>
if @on[propertyName]
@webviewNode.removeEventListener eventName, @on[propertyName]
@on[propertyName] = value
if value
@webviewNode.addEventListener eventName, value
enumerable: true
# Updates state upon loadcommit.
onLoadCommit: (@baseUrlForDataUrl, @currentEntryIndex, @entryCount, @processId, url, isTopLevel) ->
oldValue = @webviewNode.getAttribute 'src'
newValue = url
if isTopLevel and (oldValue != newValue)
# Touching the src attribute triggers a navigation. To avoid
# triggering a page reload on every guest-initiated navigation,
# we use the flag ignoreNextSrcAttributeChange here.
this.ignoreNextSrcAttributeChange = true
this.webviewNode.setAttribute 'src', newValue
onAttach: (storagePartitionId) ->
@webviewNode.setAttribute 'partition', storagePartitionId
@partition.fromAttribute storagePartitionId, this.hasNavigated()
buildAttachParams: (isNewWindow) ->
allowtransparency: @allowtransparency || false
autosize: @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_AUTOSIZE
instanceId: @viewInstanceId
maxheight: parseInt @maxheight || 0
maxwidth: parseInt @maxwidth || 0
minheight: parseInt @minheight || 0
minwidth: parseInt @minwidth || 0
# We don't need to navigate new window from here.
src: if isNewWindow then undefined else @src
# If we have a partition from the opener, that will also be already
# set via this.onAttach().
storagePartitionId: @partition.toAttribute()
userAgentOverride: @userAgentOverride
httpreferrer: @httpreferrer
attachWindow: (guestInstanceId, isNewWindow) ->
@guestInstanceId = guestInstanceId
params = @buildAttachParams isNewWindow
unless @isPluginInRenderTree()
@deferredAttachState = isNewWindow: isNewWindow
return true
@deferredAttachState = null
# FIXME
# guestViewInternalNatives.AttachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w
@browserPluginNode[PLUGIN_METHOD_ATTACH] @guestInstanceId, params
# Registers browser plugin <object> custom element.
registerBrowserPluginElement = ->
proto = Object.create HTMLObjectElement.prototype
proto.createdCallback = ->
@setAttribute 'type', 'application/browser-plugin'
@setAttribute 'id', 'browser-plugin-' + getNextId()
# The <object> node fills in the <webview> container.
@style.width = '100%'
@style.height = '100%'
proto.attributeChangedCallback = (name, oldValue, newValue) ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
internal.handleBrowserPluginAttributeMutation name, oldValue, newValue
proto.attachedCallback = ->
# Load the plugin immediately.
unused = this.nonExistentAttribute
WebView.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin',
extends: 'object', prototype: proto
delete proto.createdCallback
delete proto.attachedCallback
delete proto.detachedCallback
delete proto.attributeChangedCallback
# Registers <webview> custom element.
registerWebViewElement = ->
proto = Object.create HTMLObjectElement.prototype
proto.createdCallback = ->
new WebView(this)
proto.attributeChangedCallback = (name, oldValue, newValue) ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
internal.handleWebviewAttributeMutation name, oldValue, newValue
proto.detachedCallback = ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
internal.elementAttached = false
internal.reset()
proto.attachedCallback = ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
unless internal.elementAttached
internal.elementAttached = true
internal.parseAttributes()
# Public-facing API methods.
methods = [
"getUrl"
"getTitle"
"isLoading"
"isWaitingForResponse"
"stop"
"reload"
"reloadIngoringCache"
"canGoBack"
"canGoForward"
"canGoToOffset"
"goBack"
"goForward"
"goToIndex"
"goToOffset"
"isCrashed"
"setUserAgent"
"executeJavaScript"
"insertCSS"
"openDevTools"
"closeDevTools"
"isDevToolsOpened"
"send"
"getId"
]
# Forward proto.foo* method calls to WebView.foo*.
createHandler = (m) ->
(args...) ->
internal = v8Util.getHiddenValue this, 'internal'
remote.getGuestWebContents(internal.guestInstanceId)[m] args...
proto[m] = createHandler m for m in methods
window.WebView = webFrame.registerEmbedderCustomElement 'webview',
prototype: proto
# Delete the callbacks so developers cannot call them and produce unexpected
# behavior.
delete proto.createdCallback
delete proto.attachedCallback
delete proto.detachedCallback
delete proto.attributeChangedCallback
useCapture = true
listener = (event) ->
return if document.readyState == 'loading'
registerBrowserPluginElement()
registerWebViewElement()
window.removeEventListener event.type, listener, useCapture
window.addEventListener 'readystatechange', listener, true

View File

@@ -1,4 +1,5 @@
ipc = require 'ipc'
webFrame = require 'web-frame'
requestId = 0
@@ -27,7 +28,13 @@ module.exports =
ipc.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{viewInstanceId}", (event, args...) ->
dispatchEvent webView, event, args...
ipc.on 'ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED', (args...) ->
ipc.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{viewInstanceId}", (channel, args...) ->
domEvent = new Event('ipc-message')
domEvent.channel = channel
domEvent.args = [args...]
webView.dispatchEvent domEvent
ipc.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{viewInstanceId}", (args...) ->
domEvent = new Event('size-changed')
for f, i in ['oldWidth', 'oldHeight', 'newWidth', 'newHeight']
domEvent[f] = args[i]
@@ -36,7 +43,13 @@ module.exports =
createGuest: (type, params, callback) ->
requestId++
ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', type, params, requestId
ipc.on "ATOM_SHELL_RESPONSE_#{requestId}", callback
ipc.once "ATOM_SHELL_RESPONSE_#{requestId}", callback
attachGuest: (elementInstanceId, guestInstanceId, params, callback) ->
requestId++
ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params, requestId
ipc.once "ATOM_SHELL_RESPONSE_#{requestId}", callback
webFrame.attachGuest elementInstanceId
destroyGuest: (guestInstanceId) ->
ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId

View File

@@ -0,0 +1,207 @@
WebViewImpl = require './web-view'
guestViewInternal = require './guest-view-internal'
webViewConstants = require './web-view-constants'
remote = require 'remote'
# Helper function to resolve url set in attribute.
a = document.createElement 'a'
resolveUrl = (url) ->
a.href = url
a.href
# Attribute objects.
# Default implementation of a WebView attribute.
class WebViewAttribute
constructor: (name, webViewImpl) ->
@name = name
@webViewImpl = webViewImpl
@ignoreMutation = false
@defineProperty()
# Retrieves and returns the attribute's value.
getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || ''
# Sets the attribute's value.
setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '')
# Changes the attribute's value without triggering its mutation handler.
setValueIgnoreMutation: (value) ->
@ignoreMutation = true
@webViewImpl.webviewNode.setAttribute(@name, value || '')
@ignoreMutation = false
# Defines this attribute as a property on the webview node.
defineProperty: ->
Object.defineProperty @webViewImpl.webviewNode, @name,
get: => @getValue()
set: (value) => @setValue value
enumerable: true
# Called when the attribute's value changes.
handleMutation: ->
# An attribute that is treated as a Boolean.
class BooleanAttribute extends WebViewAttribute
constructor: (name, webViewImpl) ->
super name, webViewImpl
getValue: -> @webViewImpl.webviewNode.hasAttribute @name
setValue: (value) ->
unless value
@webViewImpl.webviewNode.removeAttribute @name
else
@webViewImpl.webviewNode.setAttribute @name, ''
# Attribute that specifies whether transparency is allowed in the webview.
class AllowTransparencyAttribute extends BooleanAttribute
constructor: (webViewImpl) ->
super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl
handleMutation: (oldValue, newValue) ->
return unless @webViewImpl.guestInstanceId
guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue()
# Attribute used to define the demension limits of autosizing.
class AutosizeDimensionAttribute extends WebViewAttribute
constructor: (name, webViewImpl) ->
super name, webViewImpl
getValue: -> parseInt(@webViewImpl.webviewNode.getAttribute(@name)) || 0
handleMutation: (oldValue, newValue) ->
return unless @webViewImpl.guestInstanceId
guestViewInternal.setAutoSize @webViewImpl.guestInstanceId,
enableAutoSize: @webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue()
min:
width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0
height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0
max:
width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0
height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0
# Attribute that specifies whether the webview should be autosized.
class AutosizeAttribute extends BooleanAttribute
constructor: (webViewImpl) ->
super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl
handleMutation: AutosizeDimensionAttribute::handleMutation
# Attribute representing the state of the storage partition.
class PartitionAttribute extends WebViewAttribute
constructor: (webViewImpl) ->
super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl
@validPartitionId = true
handleMutation: (oldValue, newValue) ->
newValue = newValue || ''
# The partition cannot change if the webview has already navigated.
unless @webViewImpl.beforeFirstNavigation
window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED
@setValueIgnoreMutation oldValue
return
if newValue is 'persist:'
@validPartitionId = false
window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE
# Attribute that handles the location and navigation of the webview.
class SrcAttribute extends WebViewAttribute
constructor: (webViewImpl) ->
super webViewConstants.ATTRIBUTE_SRC, webViewImpl
@setupMutationObserver()
getValue: ->
if @webViewImpl.webviewNode.hasAttribute @name
resolveUrl @webViewImpl.webviewNode.getAttribute(@name)
else
''
handleMutation: (oldValue, newValue) ->
# Once we have navigated, we don't allow clearing the src attribute.
# Once <webview> enters a navigated state, it cannot return to a
# placeholder state.
if not newValue and oldValue
# src attribute changes normally initiate a navigation. We suppress
# the next src attribute handler call to avoid reloading the page
# on every guest-initiated navigation.
@setValueIgnoreMutation oldValue
return
@parse()
# The purpose of this mutation observer is to catch assignment to the src
# attribute without any changes to its value. This is useful in the case
# where the webview guest has crashed and navigating to the same address
# spawns off a new process.
setupMutationObserver: ->
@observer = new MutationObserver (mutations) =>
for mutation in mutations
oldValue = mutation.oldValue
newValue = @getValue()
return if oldValue isnt newValue
@handleMutation oldValue, newValue
params =
attributes: true,
attributeOldValue: true,
attributeFilter: [@name]
@observer.observe @webViewImpl.webviewNode, params
parse: ->
if not @webViewImpl.elementAttached or
not @webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId or
not @.getValue()
return
unless @webViewImpl.guestInstanceId?
if @webViewImpl.beforeFirstNavigation
@webViewImpl.beforeFirstNavigation = false
@webViewImpl.createGuest()
return
# Navigate to |this.src|.
httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue()
urlOptions = if httpreferrer then {httpreferrer} else {}
remote.getGuestWebContents(@webViewImpl.guestInstanceId).loadUrl @getValue(), urlOptions
# Attribute specifies HTTP referrer.
class HttpReferrerAttribute extends WebViewAttribute
constructor: (webViewImpl) ->
super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl
# Attribute that set preload script.
class PreloadAttribute extends WebViewAttribute
constructor: (webViewImpl) ->
super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl
getValue: ->
return '' unless @webViewImpl.webviewNode.hasAttribute @name
preload = resolveUrl @webViewImpl.webviewNode.getAttribute(@name)
protocol = preload.substr 0, 5
unless protocol in ['file:', 'asar:']
console.error webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE
preload = ''
preload
# Sets up all of the webview attributes.
WebViewImpl::setupWebViewAttributes = ->
@attributes = {}
@attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] = new AllowTransparencyAttribute(this)
@attributes[webViewConstants.ATTRIBUTE_AUTOSIZE] = new AutosizeAttribute(this)
@attributes[webViewConstants.ATTRIBUTE_PARTITION] = new PartitionAttribute(this)
@attributes[webViewConstants.ATTRIBUTE_SRC] = new SrcAttribute(this)
@attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this)
@attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this)
@attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this)
@attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this)
autosizeAttributes = [
webViewConstants.ATTRIBUTE_MAXHEIGHT
webViewConstants.ATTRIBUTE_MAXWIDTH
webViewConstants.ATTRIBUTE_MINHEIGHT
webViewConstants.ATTRIBUTE_MINWIDTH
]
for attribute in autosizeAttributes
@attributes[attribute] = new AutosizeDimensionAttribute(attribute, this)

View File

@@ -0,0 +1,28 @@
module.exports =
# Attributes.
ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency'
ATTRIBUTE_AUTOSIZE: 'autosize'
ATTRIBUTE_MAXHEIGHT: 'maxheight'
ATTRIBUTE_MAXWIDTH: 'maxwidth'
ATTRIBUTE_MINHEIGHT: 'minheight'
ATTRIBUTE_MINWIDTH: 'minwidth'
ATTRIBUTE_NAME: 'name'
ATTRIBUTE_PARTITION: 'partition'
ATTRIBUTE_SRC: 'src'
ATTRIBUTE_HTTPREFERRER: 'httpreferrer'
ATTRIBUTE_NODEINTEGRATION: 'nodeintegration'
ATTRIBUTE_PLUGINS: 'plugins'
ATTRIBUTE_PRELOAD: 'preload'
# Internal attribute.
ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid'
# Error messages.
ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.'
ERROR_MSG_CANNOT_INJECT_SCRIPT: '<webview>: ' +
'Script cannot be injected into content until the page has loaded.'
ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE: '<webview>: ' +
'contentWindow is not available at this time. It will become available ' +
'when the page has finished loading.'
ERROR_MSG_INVALID_PARTITION_ATTRIBUTE: 'Invalid partition attribute.'
ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE: 'Only "file:" or "asar:" protocol is supported in "preload" attribute.'

View File

@@ -0,0 +1,300 @@
v8Util = process.atomBinding 'v8_util'
guestViewInternal = require './guest-view-internal'
webViewConstants = require './web-view-constants'
webFrame = require 'web-frame'
remote = require 'remote'
# ID generator.
nextId = 0
getNextId = -> ++nextId
# Represents the internal state of the WebView node.
class WebViewImpl
constructor: (@webviewNode) ->
v8Util.setHiddenValue @webviewNode, 'internal', this
@attached = false
@pendingGuestCreation = false
@elementAttached = false
@beforeFirstNavigation = true
@contentWindow = null
# on* Event handlers.
@on = {}
@browserPluginNode = @createBrowserPluginNode()
shadowRoot = @webviewNode.createShadowRoot()
@setupWebViewAttributes()
@setupFocusPropagation()
@setupWebviewNodeProperties()
@viewInstanceId = getNextId()
guestViewInternal.registerEvents this, @viewInstanceId
shadowRoot.appendChild @browserPluginNode
createBrowserPluginNode: ->
# We create BrowserPlugin as a custom element in order to observe changes
# to attributes synchronously.
browserPluginNode = new WebViewImpl.BrowserPlugin()
v8Util.setHiddenValue browserPluginNode, 'internal', this
browserPluginNode
# Resets some state upon reattaching <webview> element to the DOM.
reset: ->
# If guestInstanceId is defined then the <webview> has navigated and has
# already picked up a partition ID. Thus, we need to reset the initialization
# state. However, it may be the case that beforeFirstNavigation is false BUT
# guestInstanceId has yet to be initialized. This means that we have not
# heard back from createGuest yet. We will not reset the flag in this case so
# that we don't end up allocating a second guest.
if @guestInstanceId
# FIXME
guestViewInternal.destroyGuest @guestInstanceId
@guestInstanceId = undefined
@beforeFirstNavigation = true
@attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true
@contentWindow = null
@internalInstanceId = 0
# Sets the <webview>.request property.
setRequestPropertyOnWebViewNode: (request) ->
Object.defineProperty @webviewNode, 'request', value: request, enumerable: true
setupFocusPropagation: ->
unless @webviewNode.hasAttribute 'tabIndex'
# <webview> needs a tabIndex in order to be focusable.
# TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
# to allow <webview> to be focusable.
# See http://crbug.com/231664.
@webviewNode.setAttribute 'tabIndex', -1
@webviewNode.addEventListener 'focus', (e) =>
# Focus the BrowserPlugin when the <webview> takes focus.
@browserPluginNode.focus()
@webviewNode.addEventListener 'blur', (e) =>
# Blur the BrowserPlugin when the <webview> loses focus.
@browserPluginNode.blur()
setupWebviewNodeProperties: ->
# We cannot use {writable: true} property descriptor because we want a
# dynamic getter value.
Object.defineProperty @webviewNode, 'contentWindow',
get: =>
return @contentWindow if @contentWindow?
window.console.error webViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE
# No setter.
enumerable: true
# This observer monitors mutations to attributes of the <webview> and
# updates the BrowserPlugin properties accordingly. In turn, updating
# a BrowserPlugin property will update the corresponding BrowserPlugin
# attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
# details.
handleWebviewAttributeMutation: (attributeName, oldValue, newValue) ->
if not @attributes[attributeName] or @attributes[attributeName].ignoreMutation
return
# Let the changed attribute handle its own mutation;
@attributes[attributeName].handleMutation oldValue, newValue
handleBrowserPluginAttributeMutation: (attributeName, oldValue, newValue) ->
if attributeName is webViewConstants.ATTRIBUTE_INTERNALINSTANCEID and !oldValue and !!newValue
@browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID
@internalInstanceId = parseInt newValue
return unless @guestInstanceId
guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildAttachParams(), (w) => @contentWindow = w
onSizeChanged: (webViewEvent) ->
newWidth = webViewEvent.newWidth
newHeight = webViewEvent.newHeight
node = @webviewNode
width = node.offsetWidth
height = node.offsetHeight
# Check the current bounds to make sure we do not resize <webview>
# outside of current constraints.
maxWidth = @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width
maxHeight = @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width
minWidth = @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width
minHeight = @attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() | width
if not @attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() or
(newWidth >= minWidth and
newWidth <= maxWidth and
newHeight >= minHeight and
newHeight <= maxHeight)
node.style.width = newWidth + 'px'
node.style.height = newHeight + 'px'
# Only fire the DOM event if the size of the <webview> has actually
# changed.
@dispatchEvent webViewEvent
createGuest: ->
return if @pendingGuestCreation
params =
storagePartitionId: @attributes[webViewConstants.ATTRIBUTE_PARTITION].getValue()
guestViewInternal.createGuest 'webview', params, (guestInstanceId) =>
@pendingGuestCreation = false
unless @elementAttached
guestViewInternal.destroyGuest guestInstanceId
return
@attachWindow guestInstanceId
@pendingGuestCreation = true
dispatchEvent: (webViewEvent) ->
@webviewNode.dispatchEvent webViewEvent
# Adds an 'on<event>' property on the webview, which can be used to set/unset
# an event handler.
setupEventProperty: (eventName) ->
propertyName = 'on' + eventName.toLowerCase()
Object.defineProperty @webviewNode, propertyName,
get: => @on[propertyName]
set: (value) =>
if @on[propertyName]
@webviewNode.removeEventListener eventName, @on[propertyName]
@on[propertyName] = value
if value
@webviewNode.addEventListener eventName, value
enumerable: true
# Updates state upon loadcommit.
onLoadCommit: (@baseUrlForDataUrl, @currentEntryIndex, @entryCount, @processId, url, isTopLevel) ->
oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC
newValue = url
if isTopLevel and (oldValue != newValue)
# Touching the src attribute triggers a navigation. To avoid
# triggering a page reload on every guest-initiated navigation,
# we do not handle this mutation
@attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation newValue
onAttach: (storagePartitionId) ->
@attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue storagePartitionId
buildAttachParams: ->
params =
instanceId: @viewInstanceId
userAgentOverride: @userAgentOverride
for attributeName, attribute of @attributes
params[attributeName] = attribute.getValue()
params
attachWindow: (guestInstanceId) ->
@guestInstanceId = guestInstanceId
params = @buildAttachParams()
return true unless @internalInstanceId
guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w
# Registers browser plugin <object> custom element.
registerBrowserPluginElement = ->
proto = Object.create HTMLObjectElement.prototype
proto.createdCallback = ->
@setAttribute 'type', 'application/browser-plugin'
@setAttribute 'id', 'browser-plugin-' + getNextId()
# The <object> node fills in the <webview> container.
@style.width = '100%'
@style.height = '100%'
proto.attributeChangedCallback = (name, oldValue, newValue) ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
internal.handleBrowserPluginAttributeMutation name, oldValue, newValue
proto.attachedCallback = ->
# Load the plugin immediately.
unused = this.nonExistentAttribute
WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin',
extends: 'object', prototype: proto
delete proto.createdCallback
delete proto.attachedCallback
delete proto.detachedCallback
delete proto.attributeChangedCallback
# Registers <webview> custom element.
registerWebViewElement = ->
proto = Object.create HTMLObjectElement.prototype
proto.createdCallback = ->
new WebViewImpl(this)
proto.attributeChangedCallback = (name, oldValue, newValue) ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
internal.handleWebviewAttributeMutation name, oldValue, newValue
proto.detachedCallback = ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
internal.elementAttached = false
internal.reset()
proto.attachedCallback = ->
internal = v8Util.getHiddenValue this, 'internal'
return unless internal
unless internal.elementAttached
internal.elementAttached = true
internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse()
# Public-facing API methods.
methods = [
"getUrl"
"getTitle"
"isLoading"
"isWaitingForResponse"
"stop"
"reload"
"reloadIgnoringCache"
"canGoBack"
"canGoForward"
"canGoToOffset"
"goBack"
"goForward"
"goToIndex"
"goToOffset"
"isCrashed"
"setUserAgent"
"executeJavaScript"
"insertCSS"
"openDevTools"
"closeDevTools"
"isDevToolsOpened"
"send"
"getId"
]
# Forward proto.foo* method calls to WebViewImpl.foo*.
createHandler = (m) ->
(args...) ->
internal = v8Util.getHiddenValue this, 'internal'
remote.getGuestWebContents(internal.guestInstanceId)[m] args...
proto[m] = createHandler m for m in methods
window.WebView = webFrame.registerEmbedderCustomElement 'webview',
prototype: proto
# Delete the callbacks so developers cannot call them and produce unexpected
# behavior.
delete proto.createdCallback
delete proto.attachedCallback
delete proto.detachedCallback
delete proto.attributeChangedCallback
useCapture = true
listener = (event) ->
return if document.readyState == 'loading'
registerBrowserPluginElement()
registerWebViewElement()
window.removeEventListener event.type, listener, useCapture
window.addEventListener 'readystatechange', listener, true
module.exports = WebViewImpl

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.github.atom.helper</string>
<string>com.github.atom-shell.helper</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>

View File

@@ -32,29 +32,25 @@ void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
namespace printing {
PrintJob::PrintJob()
: ui_message_loop_(base::MessageLoop::current()),
source_(NULL),
: source_(NULL),
worker_(),
settings_(),
is_job_pending_(false),
is_canceling_(false),
quit_factory_(this) {
DCHECK(ui_message_loop_);
// This is normally a UI message loop, but in unit tests, the message loop is
// of the 'default' type.
DCHECK(base::MessageLoopForUI::IsCurrent() ||
ui_message_loop_->type() == base::MessageLoop::TYPE_DEFAULT);
ui_message_loop_->AddDestructionObserver(this);
base::MessageLoop::current()->type() ==
base::MessageLoop::TYPE_DEFAULT);
}
PrintJob::~PrintJob() {
ui_message_loop_->RemoveDestructionObserver(this);
// The job should be finished (or at least canceled) when it is destroyed.
DCHECK(!is_job_pending_);
DCHECK(!is_canceling_);
if (worker_.get())
DCHECK(worker_->message_loop() == NULL);
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(!worker_ || !worker_->IsRunning());
DCHECK(RunsTasksOnCurrentThread());
}
void PrintJob::Initialize(PrintJobWorkerOwner* job,
@@ -85,7 +81,7 @@ void PrintJob::Initialize(PrintJobWorkerOwner* job,
void PrintJob::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(RunsTasksOnCurrentThread());
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
@@ -107,10 +103,6 @@ PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
return NULL;
}
base::MessageLoop* PrintJob::message_loop() {
return ui_message_loop_;
}
const PrintSettings& PrintJob::settings() const {
return settings_;
}
@@ -122,23 +114,20 @@ int PrintJob::cookie() const {
return document_->cookie();
}
void PrintJob::WillDestroyCurrentMessageLoop() {
NOTREACHED();
}
void PrintJob::StartPrinting() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(worker_->message_loop());
DCHECK(RunsTasksOnCurrentThread());
DCHECK(worker_->IsRunning());
DCHECK(!is_job_pending_);
if (!worker_->message_loop() || is_job_pending_)
if (!worker_->IsRunning() || is_job_pending_)
return;
// Real work is done in PrintJobWorker::StartPrinting().
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(this),
base::Bind(&PrintJobWorker::StartPrinting,
base::Unretained(worker_.get()), document_)));
worker_->PostTask(FROM_HERE,
base::Bind(&HoldRefCallback,
make_scoped_refptr(this),
base::Bind(&PrintJobWorker::StartPrinting,
base::Unretained(worker_.get()),
document_)));
// Set the flag right now.
is_job_pending_ = true;
@@ -152,7 +141,7 @@ void PrintJob::StartPrinting() {
}
void PrintJob::Stop() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(RunsTasksOnCurrentThread());
if (quit_factory_.HasWeakPtrs()) {
// In case we're running a nested message loop to wait for a job to finish,
@@ -164,7 +153,7 @@ void PrintJob::Stop() {
// Be sure to live long enough.
scoped_refptr<PrintJob> handle(this);
if (worker_->message_loop()) {
if (worker_->IsRunning()) {
ControlledWorkerShutdown();
} else {
// Flush the cached document.
@@ -180,10 +169,8 @@ void PrintJob::Cancel() {
// Be sure to live long enough.
scoped_refptr<PrintJob> handle(this);
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
base::MessageLoop* worker_loop =
worker_.get() ? worker_->message_loop() : NULL;
if (worker_loop) {
DCHECK(RunsTasksOnCurrentThread());
if (worker_ && worker_->IsRunning()) {
// Call this right now so it renders the context invalid. Do not use
// InvokeLater since it would take too much time.
worker_->Cancel();
@@ -237,14 +224,15 @@ void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
settings_ = document_->settings();
}
if (worker_.get() && worker_->message_loop()) {
if (worker_) {
DCHECK(!is_job_pending_);
// Sync the document with the worker.
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(this),
base::Bind(&PrintJobWorker::OnDocumentChanged,
base::Unretained(worker_.get()), document_)));
worker_->PostTask(FROM_HERE,
base::Bind(&HoldRefCallback,
make_scoped_refptr(this),
base::Bind(&PrintJobWorker::OnDocumentChanged,
base::Unretained(worker_.get()),
document_)));
}
}
@@ -264,7 +252,6 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::JOB_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
@@ -276,6 +263,8 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
break;
}
case JobEventDetails::PAGE_DONE:
break;
default: {
NOTREACHED();
break;
@@ -300,7 +289,7 @@ void PrintJob::OnDocumentDone() {
}
void PrintJob::ControlledWorkerShutdown() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(RunsTasksOnCurrentThread());
// The deadlock this code works around is specific to window messaging on
// Windows, so we aren't likely to need it on any other platforms.

View File

@@ -15,15 +15,19 @@
class Thread;
namespace base {
class RefCountedMemory;
}
namespace printing {
// See definition below.
class JobEventDetails;
class MetafilePlayer;
class PdfToEmfConverter;
class PrintJobWorker;
class PrintedDocument;
class PrintedPage;
class PrintedPagesSource;
class PrintJobWorker;
class PrinterQuery;
// Manages the print work for a specific document. Talks to the printer through
@@ -33,8 +37,7 @@ class PrinterQuery;
// reference to the job to be sure it is kept alive. All the code in this class
// runs in the UI thread.
class PrintJob : public PrintJobWorkerOwner,
public content::NotificationObserver,
public base::MessageLoop::DestructionObserver {
public content::NotificationObserver {
public:
// Create a empty PrintJob. When initializing with this constructor,
// post-constructor initialization must be done with Initialize().
@@ -54,13 +57,9 @@ class PrintJob : public PrintJobWorkerOwner,
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) OVERRIDE;
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
virtual base::MessageLoop* message_loop() OVERRIDE;
virtual const PrintSettings& settings() const OVERRIDE;
virtual int cookie() const OVERRIDE;
// DestructionObserver implementation.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
// Starts the actual printing. Signals the worker that it should begin to
// spool as soon as data is available.
void StartPrinting();
@@ -116,10 +115,6 @@ class PrintJob : public PrintJobWorkerOwner,
content::NotificationRegistrar registrar_;
// Main message loop reference. Used to send notifications in the right
// thread.
base::MessageLoop* const ui_message_loop_;
// Source that generates the PrintedPage's (i.e. a WebContents). It will be
// set back to NULL if the source is deleted before this object.
PrintedPagesSource* source_;

View File

@@ -22,11 +22,6 @@ PrintQueriesQueue::~PrintQueriesQueue() {
queued_queries_.clear();
}
void PrintQueriesQueue::SetDestination(PrintDestinationInterface* destination) {
base::AutoLock lock(lock_);
destination_ = destination;
}
void PrintQueriesQueue::QueuePrinterQuery(PrinterQuery* job) {
base::AutoLock lock(lock_);
DCHECK(job);
@@ -49,17 +44,27 @@ scoped_refptr<PrinterQuery> PrintQueriesQueue::PopPrinterQuery(
return NULL;
}
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery() {
scoped_refptr<PrinterQuery> job = new printing::PrinterQuery;
base::AutoLock lock(lock_);
job->SetWorkerDestination(destination_);
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery(
int render_process_id,
int render_view_id) {
scoped_refptr<PrinterQuery> job =
new printing::PrinterQuery(render_process_id, render_view_id);
return job;
}
void PrintQueriesQueue::Shutdown() {
base::AutoLock lock(lock_);
queued_queries_.clear();
destination_ = NULL;
PrinterQueries queries_to_stop;
{
base::AutoLock lock(lock_);
queued_queries_.swap(queries_to_stop);
}
// Stop all pending queries, requests to generate print preview do not have
// corresponding PrintJob, so any pending preview requests are not covered
// by PrintJobManager::StopJobs and should be stopped explicitly.
for (PrinterQueries::iterator itr = queries_to_stop.begin();
itr != queries_to_stop.end(); ++itr) {
(*itr)->PostTask(FROM_HERE, base::Bind(&PrinterQuery::StopWorker, *itr));
}
}
PrintJobManager::PrintJobManager() : is_shutdown_(false) {
@@ -72,7 +77,7 @@ PrintJobManager::~PrintJobManager() {
scoped_refptr<PrintQueriesQueue> PrintJobManager::queue() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!queue_)
if (!queue_.get())
queue_ = new PrintQueriesQueue();
return queue_;
}
@@ -83,7 +88,7 @@ void PrintJobManager::Shutdown() {
is_shutdown_ = true;
registrar_.RemoveAll();
StopJobs(true);
if (queue_)
if (queue_.get())
queue_->Shutdown();
queue_ = NULL;
}

View File

@@ -10,11 +10,11 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "printing/print_destination_interface.h"
namespace printing {
@@ -26,9 +26,6 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> {
public:
PrintQueriesQueue();
// Sets the print destination to be set on the next print job.
void SetDestination(PrintDestinationInterface* destination);
// Queues a semi-initialized worker thread. Can be called from any thread.
// Current use case is queuing from the I/O thread.
// TODO(maruel): Have them vanish after a timeout (~5 minutes?)
@@ -39,7 +36,8 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> {
scoped_refptr<PrinterQuery> PopPrinterQuery(int document_cookie);
// Creates new query.
scoped_refptr<PrinterQuery> CreatePrinterQuery();
scoped_refptr<PrinterQuery> CreatePrinterQuery(int render_process_id,
int render_view_id);
void Shutdown();
@@ -54,8 +52,6 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> {
PrinterQueries queued_queries_;
scoped_refptr<PrintDestinationInterface> destination_;
DISALLOW_COPY_AND_ASSIGN(PrintQueriesQueue);
};

View File

@@ -13,10 +13,10 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "printing/print_job_constants.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
@@ -25,6 +25,8 @@
using content::BrowserThread;
namespace printing {
namespace {
// Helper function to ensure |owner| is valid until at least |callback| returns.
@@ -33,9 +35,41 @@ void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
callback.Run();
}
} // namespace
class PrintingContextDelegate : public PrintingContext::Delegate {
public:
PrintingContextDelegate(int render_process_id, int render_view_id);
virtual ~PrintingContextDelegate();
namespace printing {
virtual gfx::NativeView GetParentView() OVERRIDE;
virtual std::string GetAppLocale() OVERRIDE;
private:
int render_process_id_;
int render_view_id_;
};
PrintingContextDelegate::PrintingContextDelegate(int render_process_id,
int render_view_id)
: render_process_id_(render_process_id),
render_view_id_(render_view_id) {
}
PrintingContextDelegate::~PrintingContextDelegate() {
}
gfx::NativeView PrintingContextDelegate::GetParentView() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::RenderViewHost* view =
content::RenderViewHost::FromID(render_process_id_, render_view_id_);
if (!view)
return NULL;
content::WebContents* wc = content::WebContents::FromRenderViewHost(view);
return wc ? wc->GetNativeView() : NULL;
}
std::string PrintingContextDelegate::GetAppLocale() {
return g_browser_process->GetApplicationLocale();
}
void NotificationCallback(PrintJobWorkerOwner* print_job,
JobEventDetails::Type detail_type,
@@ -49,22 +83,25 @@ void NotificationCallback(PrintJobWorkerOwner* print_job,
content::Details<JobEventDetails>(details));
}
PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner)
: Thread("Printing_Worker"),
owner_(owner),
weak_factory_(this) {
// The object is created in the IO thread.
DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current());
} // namespace
printing_context_.reset(PrintingContext::Create(
g_browser_process->GetApplicationLocale()));
PrintJobWorker::PrintJobWorker(int render_process_id,
int render_view_id,
PrintJobWorkerOwner* owner)
: owner_(owner), thread_("Printing_Worker"), weak_factory_(this) {
// The object is created in the IO thread.
DCHECK(owner_->RunsTasksOnCurrentThread());
printing_context_delegate_.reset(
new PrintingContextDelegate(render_process_id, render_view_id));
printing_context_ = PrintingContext::Create(printing_context_delegate_.get());
}
PrintJobWorker::~PrintJobWorker() {
// The object is normally deleted in the UI thread, but when the user
// cancels printing or in the case of print preview, the worker is destroyed
// on the I/O thread.
DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current());
DCHECK(owner_->RunsTasksOnCurrentThread());
Stop();
}
@@ -73,18 +110,12 @@ void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) {
owner_ = new_owner;
}
void PrintJobWorker::SetPrintDestination(
PrintDestinationInterface* destination) {
destination_ = destination;
}
void PrintJobWorker::GetSettings(
bool ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection,
MarginType margin_type) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK_EQ(page_number_, PageNumber::npos());
// Recursive task processing is needed for the dialog in case it needs to be
@@ -97,13 +128,12 @@ void PrintJobWorker::GetSettings(
// When we delegate to a destination, we don't ask the user for settings.
// TODO(mad): Ask the destination for settings.
if (ask_user_for_settings && destination_.get() == NULL) {
if (ask_user_for_settings) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsWithUI,
base::Unretained(this),
base::Passed(&web_contents_observer),
document_page_count,
has_selection)));
} else {
@@ -116,8 +146,8 @@ void PrintJobWorker::GetSettings(
}
void PrintJobWorker::SetSettings(
const base::DictionaryValue* const new_settings) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
scoped_ptr<base::DictionaryValue> new_settings) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
BrowserThread::PostTask(
BrowserThread::UI,
@@ -126,11 +156,12 @@ void PrintJobWorker::SetSettings(
make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::UpdatePrintSettings,
base::Unretained(this),
base::Owned(new_settings))));
base::Passed(&new_settings))));
}
void PrintJobWorker::UpdatePrintSettings(
const base::DictionaryValue* const new_settings) {
scoped_ptr<base::DictionaryValue> new_settings) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PrintingContext::Result result =
printing_context_->UpdatePrintSettings(*new_settings);
GetSettingsDone(result);
@@ -147,36 +178,31 @@ void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
// We can't use OnFailure() here since owner_ may not support notifications.
// PrintJob will create the new PrintedDocument.
owner_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorkerOwner::GetSettingsDone,
make_scoped_refptr(owner_), printing_context_->settings(),
result));
owner_->PostTask(FROM_HERE,
base::Bind(&PrintJobWorkerOwner::GetSettingsDone,
make_scoped_refptr(owner_),
printing_context_->settings(),
result));
}
void PrintJobWorker::GetSettingsWithUI(
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
gfx::NativeView parent_view = web_contents_observer->GetParentView();
if (!parent_view) {
GetSettingsWithUIDone(printing::PrintingContext::FAILED);
return;
}
printing_context_->AskUserForSettings(
parent_view, document_page_count, has_selection,
document_page_count,
has_selection,
base::Bind(&PrintJobWorker::GetSettingsWithUIDone,
base::Unretained(this)));
}
void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) {
message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsDone,
base::Unretained(this), result)));
PostTask(FROM_HERE,
base::Bind(&HoldRefCallback,
make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsDone,
base::Unretained(this),
result)));
}
void PrintJobWorker::UseDefaultSettings() {
@@ -185,9 +211,9 @@ void PrintJobWorker::UseDefaultSettings() {
}
void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK_EQ(document_, new_document);
DCHECK_EQ(document_.get(), new_document);
DCHECK(document_.get());
if (!document_.get() || page_number_ != PageNumber::npos() ||
@@ -216,7 +242,7 @@ void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
}
void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK_EQ(page_number_, PageNumber::npos());
if (page_number_ != PageNumber::npos())
@@ -230,7 +256,7 @@ void PrintJobWorker::OnNewPage() {
return;
// message_loop() could return NULL when the print job is cancelled.
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
if (page_number_ == PageNumber::npos()) {
// Find first page to print.
@@ -243,15 +269,13 @@ void PrintJobWorker::OnNewPage() {
}
// We have enough information to initialize page_number_.
page_number_.Init(document_->settings(), page_count);
if (destination_.get() != NULL)
destination_->SetPageCount(page_count);
}
DCHECK_NE(page_number_, PageNumber::npos());
while (true) {
// Is the page available?
scoped_refptr<PrintedPage> page = document_->GetPage(page_number_.ToInt());
if (!page) {
if (!page.get()) {
// We need to wait for the page to be available.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
@@ -277,8 +301,33 @@ void PrintJobWorker::Cancel() {
// context we run.
}
bool PrintJobWorker::IsRunning() const {
return thread_.IsRunning();
}
bool PrintJobWorker::PostTask(const tracked_objects::Location& from_here,
const base::Closure& task) {
if (task_runner_.get())
return task_runner_->PostTask(from_here, task);
return false;
}
void PrintJobWorker::StopSoon() {
thread_.StopSoon();
}
void PrintJobWorker::Stop() {
thread_.Stop();
}
bool PrintJobWorker::Start() {
bool result = thread_.Start();
task_runner_ = thread_.task_runner();
return result;
}
void PrintJobWorker::OnDocumentDone() {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK(document_.get());
@@ -287,24 +336,28 @@ void PrintJobWorker::OnDocumentDone() {
return;
}
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::DOC_DONE, document_,
scoped_refptr<PrintedPage>()));
owner_->PostTask(FROM_HERE,
base::Bind(&NotificationCallback,
make_scoped_refptr(owner_),
JobEventDetails::DOC_DONE,
document_,
scoped_refptr<PrintedPage>()));
// Makes sure the variables are reinitialized.
document_ = NULL;
}
void PrintJobWorker::SpoolPage(PrintedPage* page) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK_NE(page_number_, PageNumber::npos());
// Signal everyone that the page is about to be printed.
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::NEW_PAGE, document_,
make_scoped_refptr(page)));
owner_->PostTask(FROM_HERE,
base::Bind(&NotificationCallback,
make_scoped_refptr(owner_),
JobEventDetails::NEW_PAGE,
document_,
make_scoped_refptr(page)));
// Preprocess.
if (printing_context_->NewPage() != PrintingContext::OK) {
@@ -312,18 +365,6 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) {
return;
}
if (destination_.get() != NULL) {
std::vector<uint8> metabytes(page->metafile()->GetDataSize());
bool success = page->metafile()->GetData(
reinterpret_cast<void*>(&metabytes[0]), metabytes.size());
DCHECK(success) << "Failed to get metafile data.";
destination_->SetPageContent(
page->page_number(),
reinterpret_cast<void*>(&metabytes[0]),
metabytes.size());
return;
}
// Actual printing.
#if defined(OS_WIN) || defined(OS_MACOSX)
document_->RenderPrintedPage(*page, printing_context_->context());
@@ -338,23 +379,26 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) {
}
// Signal everyone that the page is printed.
owner_->message_loop()->PostTask(
FROM_HERE,
base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::PAGE_DONE, document_,
make_scoped_refptr(page)));
owner_->PostTask(FROM_HERE,
base::Bind(&NotificationCallback,
make_scoped_refptr(owner_),
JobEventDetails::PAGE_DONE,
document_,
make_scoped_refptr(page)));
}
void PrintJobWorker::OnFailure() {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
// We may loose our last reference by broadcasting the FAILED event.
scoped_refptr<PrintJobWorkerOwner> handle(owner_);
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::FAILED, document_,
scoped_refptr<PrintedPage>()));
owner_->PostTask(FROM_HERE,
base::Bind(&NotificationCallback,
make_scoped_refptr(owner_),
JobEventDetails::FAILED,
document_,
scoped_refptr<PrintedPage>()));
Cancel();
// Makes sure the variables are reinitialized.

View File

@@ -9,12 +9,10 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "content/public/browser/browser_thread.h"
#include "printing/page_number.h"
#include "printing/print_destination_interface.h"
#include "printing/printing_context.h"
#include "printing/print_job_constants.h"
class PrintingUIWebContentsObserver;
#include "printing/printing_context.h"
namespace base {
class DictionaryValue;
@@ -22,39 +20,35 @@ class DictionaryValue;
namespace printing {
class PrintedDocument;
class PrintedPage;
class PrintJob;
class PrintJobWorkerOwner;
class PrintedDocument;
class PrintedPage;
// Worker thread code. It manages the PrintingContext, which can be blocking
// and/or run a message loop. This is the object that generates most
// NOTIFY_PRINT_JOB_EVENT notifications, but they are generated through a
// NotificationTask task to be executed from the right thread, the UI thread.
// PrintJob always outlives its worker instance.
class PrintJobWorker : public base::Thread {
class PrintJobWorker {
public:
explicit PrintJobWorker(PrintJobWorkerOwner* owner);
PrintJobWorker(int render_process_id,
int render_view_id,
PrintJobWorkerOwner* owner);
virtual ~PrintJobWorker();
void SetNewOwner(PrintJobWorkerOwner* new_owner);
// Set a destination for print.
// This supercedes the document's rendering destination.
void SetPrintDestination(PrintDestinationInterface* destination);
// Initializes the print settings. If |ask_user_for_settings| is true, a
// Print... dialog box will be shown to ask the user his preference.
void GetSettings(
bool ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection,
MarginType margin_type);
// Set the new print settings. This function takes ownership of
// |new_settings|.
void SetSettings(const base::DictionaryValue* const new_settings);
// Set the new print settings.
void SetSettings(scoped_ptr<base::DictionaryValue> new_settings);
// Starts the printing loop. Every pages are printed as soon as the data is
// available. Makes sure the new_document is the right one.
@@ -71,6 +65,22 @@ class PrintJobWorker : public base::Thread {
// This is the only function that can be called in a thread.
void Cancel();
// Returns true if the thread has been started, and not yet stopped.
bool IsRunning() const;
// Posts the given task to be run.
bool PostTask(const tracked_objects::Location& from_here,
const base::Closure& task);
// Signals the thread to exit in the near future.
void StopSoon();
// Signals the thread to exit and returns once the thread has exited.
void Stop();
// Starts the thread.
bool Start();
protected:
// Retrieves the context for testing only.
PrintingContext* printing_context() { return printing_context_.get(); }
@@ -97,7 +107,6 @@ class PrintJobWorker : public base::Thread {
// Required on Mac and Linux. Windows can display UI from non-main threads,
// but sticks with this for consistency.
void GetSettingsWithUI(
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection);
@@ -106,9 +115,8 @@ class PrintJobWorker : public base::Thread {
// back into the IO thread for GetSettingsDone().
void GetSettingsWithUIDone(PrintingContext::Result result);
// Called on the UI thread to update the print settings. This function takes
// the ownership of |new_settings|.
void UpdatePrintSettings(const base::DictionaryValue* const new_settings);
// Called on the UI thread to update the print settings.
void UpdatePrintSettings(scoped_ptr<base::DictionaryValue> new_settings);
// Reports settings back to owner_.
void GetSettingsDone(PrintingContext::Result result);
@@ -118,15 +126,15 @@ class PrintJobWorker : public base::Thread {
// systems.
void UseDefaultSettings();
// Printing context delegate.
scoped_ptr<PrintingContext::Delegate> printing_context_delegate_;
// Information about the printer setting.
scoped_ptr<PrintingContext> printing_context_;
// The printed document. Only has read-only access.
scoped_refptr<PrintedDocument> document_;
// The print destination, may be NULL.
scoped_refptr<PrintDestinationInterface> destination_;
// The print job owning this worker thread. It is guaranteed to outlive this
// object.
PrintJobWorkerOwner* owner_;
@@ -134,6 +142,12 @@ class PrintJobWorker : public base::Thread {
// Current page number to print.
PageNumber page_number_;
// Thread to run worker tasks.
base::Thread thread_;
// Tread-safe pointer to task runner of the |thread_|.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Used to generate a WeakPtr for callbacks.
base::WeakPtrFactory<PrintJobWorker> weak_factory_;

View File

@@ -0,0 +1,27 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "base/message_loop/message_loop.h"
namespace printing {
PrintJobWorkerOwner::PrintJobWorkerOwner()
: task_runner_(base::MessageLoop::current()->task_runner()) {
}
PrintJobWorkerOwner::~PrintJobWorkerOwner() {
}
bool PrintJobWorkerOwner::RunsTasksOnCurrentThread() const {
return task_runner_->RunsTasksOnCurrentThread();
}
bool PrintJobWorkerOwner::PostTask(const tracked_objects::Location& from_here,
const base::Closure& task) {
return task_runner_->PostTask(from_here, task);
}
} // namespace printing

View File

@@ -10,8 +10,12 @@
namespace base {
class MessageLoop;
class SequencedTaskRunner;
}
namespace tracked_objects {
class Location;
}
namespace printing {
@@ -21,6 +25,8 @@ class PrintSettings;
class PrintJobWorkerOwner
: public base::RefCountedThreadSafe<PrintJobWorkerOwner> {
public:
PrintJobWorkerOwner();
// Finishes the initialization began by PrintJobWorker::GetSettings().
// Creates a new PrintedDocument if necessary. Solely meant to be called by
// PrintJobWorker.
@@ -30,19 +36,29 @@ class PrintJobWorkerOwner
// Detach the PrintJobWorker associated to this object.
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) = 0;
// Retrieves the message loop that is expected to process GetSettingsDone.
virtual base::MessageLoop* message_loop() = 0;
// Access the current settings.
virtual const PrintSettings& settings() const = 0;
// Cookie uniquely identifying the PrintedDocument and/or loaded settings.
virtual int cookie() const = 0;
// Returns true if the current thread is a thread on which a task
// may be run, and false if no task will be run on the current
// thread.
bool RunsTasksOnCurrentThread() const;
// Posts the given task to be run.
bool PostTask(const tracked_objects::Location& from_here,
const base::Closure& task);
protected:
friend class base::RefCountedThreadSafe<PrintJobWorkerOwner>;
virtual ~PrintJobWorkerOwner() {}
virtual ~PrintJobWorkerOwner();
// Task runner reference. Used to send notifications in the right
// thread.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
};
} // namespace printing

View File

@@ -24,11 +24,14 @@
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h"
#include "printing/metafile_impl.h"
#include "printing/pdf_metafile_skia.h"
#include "printing/printed_document.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(ENABLE_FULL_PRINTING)
#include "chrome/browser/printing/print_error_dialog.h"
#endif
using base::TimeDelta;
using content::BrowserThread;
@@ -36,11 +39,6 @@ namespace printing {
namespace {
#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)
// Limits memory usage by raster to 64 MiB.
const int kMaxRasterSizeInPixels = 16*1024*1024;
#endif
} // namespace
PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
@@ -50,11 +48,10 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
inside_inner_message_loop_(false),
cookie_(0),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \
defined(WIN_PDF_METAFILE_FOR_PRINTING)
DCHECK(queue_.get());
#if !defined(OS_MACOSX)
expecting_first_page_ = true;
#endif
#endif // OS_MACOSX
printing_enabled_ = true;
}
@@ -63,10 +60,12 @@ PrintViewManagerBase::~PrintViewManagerBase() {
DisconnectFromCurrentPrintJob();
}
#if !defined(DISABLE_BASIC_PRINTING)
bool PrintViewManagerBase::PrintNow(bool silent, bool print_background) {
return PrintNowInternal(new PrintMsg_PrintPages(
routing_id(), silent, print_background));
}
#endif // !DISABLE_BASIC_PRINTING
void PrintViewManagerBase::NavigationStopped() {
// Cancel the current job, wait for the worker to finish.
@@ -117,13 +116,12 @@ void PrintViewManagerBase::OnDidPrintPage(
return;
}
#if (defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)) || \
defined(OS_MACOSX)
#if defined(OS_MACOSX)
const bool metafile_must_be_valid = true;
#elif defined(OS_POSIX) || defined(WIN_PDF_METAFILE_FOR_PRINTING)
#else
const bool metafile_must_be_valid = expecting_first_page_;
expecting_first_page_ = false;
#endif
#endif // OS_MACOSX
base::SharedMemory shared_buf(params.metafile_data_handle, true);
if (metafile_must_be_valid) {
@@ -134,7 +132,7 @@ void PrintViewManagerBase::OnDidPrintPage(
}
}
scoped_ptr<NativeMetafile> metafile(new NativeMetafile);
scoped_ptr<PdfMetafileSkia> metafile(new PdfMetafileSkia);
if (metafile_must_be_valid) {
if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) {
NOTREACHED() << "Invalid metafile header";
@@ -143,32 +141,10 @@ void PrintViewManagerBase::OnDidPrintPage(
}
}
#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)
bool big_emf = (params.data_size && params.data_size >= kMetafileMaxSize);
int raster_size =
std::min(params.page_size.GetArea(), kMaxRasterSizeInPixels);
if (big_emf) {
scoped_ptr<NativeMetafile> raster_metafile(
metafile->RasterizeMetafile(raster_size));
if (raster_metafile.get()) {
metafile.swap(raster_metafile);
} else if (big_emf) {
// Don't fall back to emf here.
NOTREACHED() << "size:" << params.data_size;
TerminatePrintJob(true);
web_contents()->Stop();
return;
}
}
#endif // OS_WIN && !WIN_PDF_METAFILE_FOR_PRINTING
#if !defined(WIN_PDF_METAFILE_FOR_PRINTING)
#if !defined(OS_WIN)
// Update the rendered document. It will send notifications to the listener.
document->SetPage(params.page_number,
metafile.release(),
#if defined(OS_WIN)
params.actual_shrink,
#endif // OS_WIN
metafile.PassAs<MetafilePlayer>(),
params.page_size,
params.content_area);
@@ -180,19 +156,8 @@ void PrintViewManagerBase::OnDidPrintPage(
params.data_size);
document->DebugDumpData(bytes, FILE_PATH_LITERAL(".pdf"));
if (!pdf_to_emf_converter_)
pdf_to_emf_converter_ = PdfToEmfConverter::CreateDefault();
const int kPrinterDpi = print_job_->settings().dpi();
pdf_to_emf_converter_->Start(
bytes,
printing::PdfRenderSettings(params.content_area, kPrinterDpi, true),
base::Bind(&PrintViewManagerBase::OnPdfToEmfConverted,
base::Unretained(this),
params));
}
#endif // !WIN_PDF_METAFILE_FOR_PRINTING
#endif // !OS_WIN
}
void PrintViewManagerBase::OnPrintingFailed(int cookie) {
@@ -386,10 +351,9 @@ void PrintViewManagerBase::DisconnectFromCurrentPrintJob() {
// DO NOT wait for the job to finish.
ReleasePrintJob();
}
#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \
defined(WIN_PDF_METAFILE_FOR_PRINTING)
#if !defined(OS_MACOSX)
expecting_first_page_ = true;
#endif
#endif // OS_MACOSX
}
void PrintViewManagerBase::PrintingDone(bool success) {
@@ -481,12 +445,12 @@ bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
// The job was initiated by a script. Time to get the corresponding worker
// thread.
scoped_refptr<PrinterQuery> queued_query = queue_->PopPrinterQuery(cookie);
if (!queued_query) {
if (!queued_query.get()) {
NOTREACHED();
return false;
}
if (!CreateNewPrintJob(queued_query)) {
if (!CreateNewPrintJob(queued_query.get())) {
// Don't kill anything.
return false;
}
@@ -512,8 +476,6 @@ void PrintViewManagerBase::ReleasePrinterQuery() {
int cookie = cookie_;
cookie_ = 0;
queue_->SetDestination(NULL);
printing::PrintJobManager* print_job_manager =
g_browser_process->print_job_manager();
@@ -523,7 +485,7 @@ void PrintViewManagerBase::ReleasePrinterQuery() {
scoped_refptr<printing::PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(cookie);
if (!printer_query)
if (!printer_query.get())
return;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,

View File

@@ -23,7 +23,7 @@ class RenderViewHost;
namespace printing {
class JobEventDetails;
class PdfToEmfConverter;
class MetafilePlayer;
class PrintJob;
class PrintJobWorkerOwner;
class PrintQueriesQueue;
@@ -35,10 +35,12 @@ class PrintViewManagerBase : public content::NotificationObserver,
public:
virtual ~PrintViewManagerBase();
#if !defined(DISABLE_BASIC_PRINTING)
// Prints the current document immediately. Since the rendering is
// asynchronous, the actual printing will not be completed on the return of
// this function. Returns false if printing is impossible at the moment.
virtual bool PrintNow(bool silent, bool print_background);
#endif // !DISABLE_BASIC_PRINTING
// PrintedPagesSource implementation.
virtual base::string16 RenderSourceName() OVERRIDE;
@@ -140,11 +142,10 @@ class PrintViewManagerBase : public content::NotificationObserver,
// print settings are being loaded.
bool inside_inner_message_loop_;
#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \
defined(WIN_PDF_METAFILE_FOR_PRINTING)
#if !defined(OS_MACOSX)
// Set to true when OnDidPrintPage() should be expecting the first page.
bool expecting_first_page_;
#endif
#endif // OS_MACOSX
// The document cookie of the current PrinterQuery.
int cookie_;

View File

@@ -10,13 +10,11 @@
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
namespace printing {
PrinterQuery::PrinterQuery()
: io_message_loop_(base::MessageLoop::current()),
worker_(new PrintJobWorker(this)),
PrinterQuery::PrinterQuery(int render_process_id, int render_view_id)
: worker_(new PrintJobWorker(render_process_id, render_view_id, this)),
is_print_dialog_box_shown_(false),
cookie_(PrintSettings::NewCookie()),
last_status_(PrintingContext::FAILED) {
@@ -57,10 +55,6 @@ PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
return worker_.release();
}
base::MessageLoop* PrinterQuery::message_loop() {
return io_message_loop_;
}
const PrintSettings& PrinterQuery::settings() const {
return settings_;
}
@@ -71,43 +65,34 @@ int PrinterQuery::cookie() const {
void PrinterQuery::GetSettings(
GetSettingsAskParam ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int expected_page_count,
bool has_selection,
MarginType margin_type,
const base::Closure& callback) {
DCHECK_EQ(io_message_loop_, base::MessageLoop::current());
DCHECK(RunsTasksOnCurrentThread());
DCHECK(!is_print_dialog_box_shown_);
StartWorker(callback);
// Real work is done in PrintJobWorker::GetSettings().
is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER;
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings,
base::Unretained(worker_.get()),
is_print_dialog_box_shown_,
base::Passed(&web_contents_observer),
expected_page_count,
has_selection,
margin_type));
worker_->PostTask(FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings,
base::Unretained(worker_.get()),
is_print_dialog_box_shown_,
expected_page_count,
has_selection,
margin_type));
}
void PrinterQuery::SetSettings(const base::DictionaryValue& new_settings,
void PrinterQuery::SetSettings(scoped_ptr<base::DictionaryValue> new_settings,
const base::Closure& callback) {
StartWorker(callback);
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::SetSettings,
base::Unretained(worker_.get()),
new_settings.DeepCopy()));
}
void PrinterQuery::SetWorkerDestination(
PrintDestinationInterface* destination) {
worker_->SetPrintDestination(destination);
worker_->PostTask(FROM_HERE,
base::Bind(&PrintJobWorker::SetSettings,
base::Unretained(worker_.get()),
base::Passed(&new_settings)));
}
void PrinterQuery::StartWorker(const base::Closure& callback) {
@@ -115,7 +100,7 @@ void PrinterQuery::StartWorker(const base::Closure& callback) {
DCHECK(worker_.get());
// Lazily create the worker thread. There is one worker thread per print job.
if (!worker_->message_loop())
if (!worker_->IsRunning())
worker_->Start();
callback_ = callback;

View File

@@ -11,11 +11,8 @@
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "printing/print_job_constants.h"
class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
class MessageLoop;
}
namespace printing {
@@ -32,13 +29,12 @@ class PrinterQuery : public PrintJobWorkerOwner {
ASK_USER,
};
PrinterQuery();
PrinterQuery(int render_process_id, int render_view_id);
// PrintJobWorkerOwner implementation.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) OVERRIDE;
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
virtual base::MessageLoop* message_loop() OVERRIDE;
virtual const PrintSettings& settings() const OVERRIDE;
virtual int cookie() const OVERRIDE;
@@ -48,19 +44,15 @@ class PrinterQuery : public PrintJobWorkerOwner {
// |ask_for_user_settings| is DEFAULTS.
void GetSettings(
GetSettingsAskParam ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int expected_page_count,
bool has_selection,
MarginType margin_type,
const base::Closure& callback);
// Updates the current settings with |new_settings| dictionary values.
void SetSettings(const base::DictionaryValue& new_settings,
void SetSettings(scoped_ptr<base::DictionaryValue> new_settings,
const base::Closure& callback);
// Set a destination for the worker.
void SetWorkerDestination(PrintDestinationInterface* destination);
// Stops the worker thread since the client is done with this object.
void StopWorker();
@@ -78,10 +70,6 @@ class PrinterQuery : public PrintJobWorkerOwner {
// Lazy create the worker thread. There is one worker thread per print job.
void StartWorker(const base::Closure& callback);
// Main message loop reference. Used to send notifications in the right
// thread.
base::MessageLoop* const io_message_loop_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
// worker thread per print job.

View File

@@ -8,21 +8,56 @@
#include "base/bind.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#if defined(ENABLE_FULL_PRINTING)
#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
#endif
#if defined(OS_CHROMEOS)
#include <fcntl.h>
#include <map>
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "chrome/browser/printing/print_dialog_cloud.h"
#endif
#if defined(OS_ANDROID)
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "printing/printing_context_android.h"
#endif
using content::BrowserThread;
namespace printing {
namespace {
void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
#if defined(OS_CHROMEOS)
typedef std::map<int, base::FilePath> SequenceToPathMap;
struct PrintingSequencePathMap {
SequenceToPathMap map;
int sequence;
};
// No locking, only access on the FILE thread.
static base::LazyInstance<PrintingSequencePathMap>
g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER;
#endif
void RenderParamsFromPrintSettings(const PrintSettings& settings,
PrintMsg_Print_Params* params) {
params->page_size = settings.page_setup_device_units().physical_size();
params->content_size.SetSize(
@@ -57,21 +92,45 @@ PrintingMessageFilter::PrintingMessageFilter(int render_process_id)
: BrowserMessageFilter(PrintMsgStart),
render_process_id_(render_process_id),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
DCHECK(queue_.get());
}
PrintingMessageFilter::~PrintingMessageFilter() {
}
void PrintingMessageFilter::OverrideThreadForMessage(
const IPC::Message& message, BrowserThread::ID* thread) {
#if defined(OS_CHROMEOS)
if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
*thread = BrowserThread::FILE;
}
#elif defined(OS_ANDROID)
if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
*thread = BrowserThread::UI;
}
#endif
}
bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
#endif
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting,
OnAllocateTempFileForPrinting)
IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten,
OnTempFileForPrintingWritten)
#endif
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
#if defined(ENABLE_FULL_PRINTING)
IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -88,6 +147,102 @@ void PrintingMessageFilter::OnDuplicateSection(
}
#endif
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
void PrintingMessageFilter::OnAllocateTempFileForPrinting(
int render_view_id,
base::FileDescriptor* temp_file_fd,
int* sequence_number) {
#if defined(OS_CHROMEOS)
// TODO(thestig): Use |render_view_id| for Chrome OS.
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
temp_file_fd->fd = *sequence_number = -1;
temp_file_fd->auto_close = false;
SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
*sequence_number = g_printing_file_descriptor_map.Get().sequence++;
base::FilePath path;
if (base::CreateTemporaryFile(&path)) {
int fd = open(path.value().c_str(), O_WRONLY);
if (fd >= 0) {
SequenceToPathMap::iterator it = map->find(*sequence_number);
if (it != map->end()) {
NOTREACHED() << "Sequence number already in use. seq=" <<
*sequence_number;
} else {
(*map)[*sequence_number] = path;
temp_file_fd->fd = fd;
temp_file_fd->auto_close = true;
}
}
}
#elif defined(OS_ANDROID)
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
PrintViewManagerBasic* print_view_manager =
PrintViewManagerBasic::FromWebContents(wc);
// The file descriptor is originally created in & passed from the Android
// side, and it will handle the closing.
const base::FileDescriptor& file_descriptor =
print_view_manager->file_descriptor();
temp_file_fd->fd = file_descriptor.fd;
temp_file_fd->auto_close = false;
#endif
}
void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id,
int sequence_number) {
#if defined(OS_CHROMEOS)
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
SequenceToPathMap::iterator it = map->find(sequence_number);
if (it == map->end()) {
NOTREACHED() << "Got a sequence that we didn't pass to the "
"renderer: " << sequence_number;
return;
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::CreatePrintDialogForFile,
this, render_view_id, it->second));
// Erase the entry in the map.
map->erase(it);
#elif defined(OS_ANDROID)
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
PrintViewManagerBasic* print_view_manager =
PrintViewManagerBasic::FromWebContents(wc);
const base::FileDescriptor& file_descriptor =
print_view_manager->file_descriptor();
PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true);
// Invalidate the file descriptor so it doesn't accidentally get reused.
print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false));
#endif
}
#endif // defined(OS_CHROMEOS) || defined(OS_ANDROID)
#if defined(OS_CHROMEOS)
void PrintingMessageFilter::CreatePrintDialogForFile(
int render_view_id,
const base::FilePath& path) {
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
print_dialog_cloud::CreatePrintDialogForFile(
wc->GetBrowserContext(),
wc->GetTopLevelNativeWindow(),
path,
wc->GetTitle(),
base::string16(),
std::string("application/pdf"));
}
#endif // defined(OS_CHROMEOS)
content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
int render_view_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -96,80 +251,41 @@ content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
return view ? content::WebContents::FromRenderViewHost(view) : NULL;
}
struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams {
printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings;
int expected_page_count;
bool has_selection;
printing::MarginType margin_type;
};
void PrintingMessageFilter::GetPrintSettingsForRenderView(
int render_view_id,
GetPrintSettingsForRenderViewParams params,
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (wc) {
scoped_ptr<PrintingUIWebContentsObserver> wc_observer(
new PrintingUIWebContentsObserver(wc));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
params.ask_user_for_settings, base::Passed(&wc_observer),
params.expected_page_count, params.has_selection,
params.margin_type, callback));
} else {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PrintingMessageFilter::OnGetPrintSettingsFailed, this,
callback, printer_query));
}
}
void PrintingMessageFilter::OnGetPrintSettingsFailed(
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
printer_query->GetSettingsDone(printing::PrintSettings(),
printing::PrintingContext::FAILED);
callback.Run();
}
void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<printing::PrinterQuery> printer_query;
if (false) {
scoped_refptr<PrinterQuery> printer_query;
#if 0
if (!profile_io_data_->printing_enabled()->GetValue()) {
// Reply with NULL query.
OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
return;
}
#endif
printer_query = queue_->PopPrinterQuery(0);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
if (!printer_query.get()) {
printer_query =
queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id());
}
// Loads default settings. This is asynchronous, only the IPC message sender
// will hang until the settings are retrieved.
GetPrintSettingsForRenderViewParams params;
params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS;
params.expected_page_count = 0;
params.has_selection = false;
params.margin_type = printing::DEFAULT_MARGINS;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
reply_msg->routing_id(), params,
base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
this, printer_query, reply_msg),
printer_query));
printer_query->GetSettings(
PrinterQuery::DEFAULTS,
0,
false,
DEFAULT_MARGINS,
base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
this,
printer_query,
reply_msg));
}
void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_Print_Params params;
if (!printer_query.get() ||
printer_query->last_status() != printing::PrintingContext::OK) {
printer_query->last_status() != PrintingContext::OK) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params);
@@ -191,43 +307,69 @@ void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
void PrintingMessageFilter::OnScriptedPrint(
const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg) {
scoped_refptr<printing::PrinterQuery> printer_query =
scoped_refptr<PrinterQuery> printer_query =
queue_->PopPrinterQuery(params.cookie);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
GetPrintSettingsForRenderViewParams settings_params;
settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER;
settings_params.expected_page_count = params.expected_pages_count;
settings_params.has_selection = params.has_selection;
settings_params.margin_type = params.margin_type;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
reply_msg->routing_id(), settings_params,
base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this,
printer_query, reply_msg),
printer_query));
if (!printer_query.get()) {
printer_query =
queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id());
}
printer_query->GetSettings(
PrinterQuery::ASK_USER,
params.expected_pages_count,
params.has_selection,
params.margin_type,
base::Bind(&PrintingMessageFilter::OnScriptedPrintReply,
this,
printer_query,
reply_msg));
}
void PrintingMessageFilter::OnScriptedPrintReply(
scoped_refptr<printing::PrinterQuery> printer_query,
scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_PrintPages_Params params;
if (printer_query->last_status() != printing::PrintingContext::OK ||
#if defined(OS_ANDROID)
// We need to save the routing ID here because Send method below deletes the
// |reply_msg| before we can get the routing ID for the Android code.
int routing_id = reply_msg->routing_id();
#endif
if (printer_query->last_status() != PrintingContext::OK ||
!printer_query->settings().dpi()) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
params.params.document_cookie = printer_query->cookie();
params.pages =
printing::PageRange::GetPages(printer_query->settings().ranges());
params.pages = PageRange::GetPages(printer_query->settings().ranges());
}
PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
Send(reply_msg);
if (params.params.dpi && params.params.document_cookie) {
#if defined(OS_ANDROID)
int file_descriptor;
const base::string16& device_name = printer_query->settings().device_name();
if (base::StringToInt(device_name, &file_descriptor)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this,
routing_id, file_descriptor));
}
#endif
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}
#if defined(OS_ANDROID)
void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
PrintViewManagerBasic* print_view_manager =
PrintViewManagerBasic::FromWebContents(wc);
print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false));
}
#endif
} // namespace printing

View File

@@ -15,6 +15,8 @@
#endif
struct PrintHostMsg_ScriptedPrint_Params;
class Profile;
class ProfileIOData;
namespace base {
class DictionaryValue;
@@ -26,18 +28,21 @@ class WebContents;
}
namespace printing {
class PrinterQuery;
class PrintJobManager;
class PrintQueriesQueue;
}
class PrinterQuery;
// This class filters out incoming printing related IPC messages for the
// renderer process on the IPC thread.
class PrintingMessageFilter : public content::BrowserMessageFilter {
public:
explicit PrintingMessageFilter(int render_process_id);
PrintingMessageFilter(int render_process_id);
// content::BrowserMessageFilter methods.
virtual void OverrideThreadForMessage(
const IPC::Message& message,
content::BrowserThread::ID* thread) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
private:
@@ -49,6 +54,25 @@ class PrintingMessageFilter : public content::BrowserMessageFilter {
base::SharedMemoryHandle* browser_handle);
#endif
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
// Used to ask the browser allocate a temporary file for the renderer
// to fill in resulting PDF in renderer.
void OnAllocateTempFileForPrinting(int render_view_id,
base::FileDescriptor* temp_file_fd,
int* sequence_number);
void OnTempFileForPrintingWritten(int render_view_id, int sequence_number);
#endif
#if defined(OS_CHROMEOS)
void CreatePrintDialogForFile(int render_view_id, const base::FilePath& path);
#endif
#if defined(OS_ANDROID)
// Updates the file descriptor for the PrintViewManagerBasic of a given
// render_view_id.
void UpdateFileDescriptor(int render_view_id, int fd);
#endif
// Given a render_view_id get the corresponding WebContents.
// Must be called on the UI thread.
content::WebContents* GetWebContentsForRenderView(int render_view_id);
@@ -59,38 +83,33 @@ class PrintingMessageFilter : public content::BrowserMessageFilter {
// to base::Bind.
struct GetPrintSettingsForRenderViewParams;
// Retrieve print settings. Uses |render_view_id| to get a parent
// for any UI created if needed.
void GetPrintSettingsForRenderView(
int render_view_id,
GetPrintSettingsForRenderViewParams params,
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query);
void OnGetPrintSettingsFailed(
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query);
// Get the default print setting.
void OnGetDefaultPrintSettings(IPC::Message* reply_msg);
void OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
void OnGetDefaultPrintSettingsReply(scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg);
// The renderer host have to show to the user the print dialog and returns
// the selected print settings. The task is handled by the print worker
// thread and the UI thread. The reply occurs on the IO thread.
void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg);
void OnScriptedPrintReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
void OnScriptedPrintReply(scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg);
#if defined(ENABLE_FULL_PRINTING)
// Check to see if print preview has been cancelled.
void OnCheckForCancel(int32 preview_ui_id,
int preview_request_id,
bool* cancel);
#endif
const int render_process_id_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
scoped_refptr<PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_

View File

@@ -1,123 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h"
#include <gtk/gtk.h>
#include "base/bind.h"
#include "base/debug/leak_annotations.h"
#include "chrome/browser/ui/libgtk2ui/menu_util.h"
#include "ui/base/models/menu_model.h"
namespace libgtk2ui {
AppIndicatorIconMenu::AppIndicatorIconMenu(ui::MenuModel* model)
: menu_model_(model),
click_action_replacement_menu_item_added_(false),
gtk_menu_(NULL),
block_activation_(false) {
{
ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/378770
gtk_menu_ = gtk_menu_new();
}
g_object_ref_sink(gtk_menu_);
if (menu_model_) {
BuildSubmenuFromModel(menu_model_,
gtk_menu_,
G_CALLBACK(OnMenuItemActivatedThunk),
&block_activation_,
this);
Refresh();
}
}
AppIndicatorIconMenu::~AppIndicatorIconMenu() {
gtk_widget_destroy(gtk_menu_);
g_object_unref(gtk_menu_);
}
void AppIndicatorIconMenu::UpdateClickActionReplacementMenuItem(
const char* label,
const base::Closure& callback) {
click_action_replacement_callback_ = callback;
if (click_action_replacement_menu_item_added_) {
GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_));
for (GList* child = children; child; child = g_list_next(child)) {
if (g_object_get_data(G_OBJECT(child->data), "click-action-item") !=
NULL) {
gtk_menu_item_set_label(GTK_MENU_ITEM(child->data), label);
break;
}
}
g_list_free(children);
} else {
click_action_replacement_menu_item_added_ = true;
// If |menu_model_| is non empty, add a separator to separate the
// "click action replacement menu item" from the other menu items.
if (menu_model_ && menu_model_->GetItemCount() > 0) {
GtkWidget* menu_item = gtk_separator_menu_item_new();
gtk_widget_show(menu_item);
gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
}
GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(label);
g_object_set_data(
G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1));
g_signal_connect(menu_item,
"activate",
G_CALLBACK(OnClickActionReplacementMenuItemActivatedThunk),
this);
gtk_widget_show(menu_item);
gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
}
}
void AppIndicatorIconMenu::Refresh() {
gtk_container_foreach(
GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
}
GtkMenu* AppIndicatorIconMenu::GetGtkMenu() {
return GTK_MENU(gtk_menu_);
}
void AppIndicatorIconMenu::OnClickActionReplacementMenuItemActivated(
GtkWidget* menu_item) {
click_action_replacement_callback_.Run();
}
void AppIndicatorIconMenu::OnMenuItemActivated(GtkWidget* menu_item) {
if (block_activation_)
return;
ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item));
if (!model) {
// There won't be a model for "native" submenus like the "Input Methods"
// context menu. We don't need to handle activation messages for submenus
// anyway, so we can just return here.
DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)));
return;
}
// The activate signal is sent to radio items as they get deselected;
// ignore it in this case.
if (GTK_IS_RADIO_MENU_ITEM(menu_item) &&
!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) {
return;
}
int id;
if (!GetMenuItemID(menu_item, &id))
return;
// The menu item can still be activated by hotkeys even if it is disabled.
if (menu_model_->IsEnabledAt(id))
ExecuteCommand(model, id);
}
} // namespace libgtk2ui

View File

@@ -1,66 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_
#define CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_
#include "base/callback.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
typedef struct _GtkMenu GtkMenu;
typedef struct _GtkWidget GtkWidget;
namespace ui {
class MenuModel;
}
namespace libgtk2ui {
// The app indicator icon's menu.
class AppIndicatorIconMenu {
public:
explicit AppIndicatorIconMenu(ui::MenuModel* model);
virtual ~AppIndicatorIconMenu();
// Sets a menu item at the top of |gtk_menu_| as a replacement for the app
// indicator icon's click action. |callback| is called when the menu item
// is activated.
void UpdateClickActionReplacementMenuItem(const char* label,
const base::Closure& callback);
// Refreshes all the menu item labels and menu item checked/enabled states.
void Refresh();
GtkMenu* GetGtkMenu();
private:
// Callback for when the "click action replacement" menu item is activated.
CHROMEGTK_CALLBACK_0(AppIndicatorIconMenu,
void,
OnClickActionReplacementMenuItemActivated);
// Callback for when a menu item is activated.
CHROMEGTK_CALLBACK_0(AppIndicatorIconMenu, void, OnMenuItemActivated);
// Not owned.
ui::MenuModel* menu_model_;
// Whether a "click action replacement" menu item has been added to the menu.
bool click_action_replacement_menu_item_added_;
// Called when the click action replacement menu item is activated. When a
// menu item from |menu_model_| is activated, MenuModel::ActivatedAt() is
// invoked and is assumed to do any necessary processing.
base::Closure click_action_replacement_callback_;
GtkWidget* gtk_menu_;
bool block_activation_;
DISALLOW_COPY_AND_ASSIGN(AppIndicatorIconMenu);
};
} // namespace libgtk2ui
#endif // CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_

View File

@@ -1,80 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h"
#include <gtk/gtk.h>
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h"
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/image/image_skia.h"
namespace libgtk2ui {
Gtk2StatusIcon::Gtk2StatusIcon(const gfx::ImageSkia& image,
const base::string16& tool_tip) {
GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap());
gtk_status_icon_ = gtk_status_icon_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
g_signal_connect(gtk_status_icon_, "activate", G_CALLBACK(OnClickThunk),
this);
g_signal_connect(gtk_status_icon_, "popup_menu",
G_CALLBACK(OnContextMenuRequestedThunk), this);
SetToolTip(tool_tip);
}
Gtk2StatusIcon::~Gtk2StatusIcon() {
g_object_unref(gtk_status_icon_);
}
void Gtk2StatusIcon::SetImage(const gfx::ImageSkia& image) {
GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap());
gtk_status_icon_set_from_pixbuf(gtk_status_icon_, pixbuf);
g_object_unref(pixbuf);
}
void Gtk2StatusIcon::SetPressedImage(const gfx::ImageSkia& image) {
// Ignore pressed images, since the standard on Linux is to not highlight
// pressed status icons.
}
void Gtk2StatusIcon::SetToolTip(const base::string16& tool_tip) {
gtk_status_icon_set_tooltip_text(gtk_status_icon_,
base::UTF16ToUTF8(tool_tip).c_str());
}
void Gtk2StatusIcon::UpdatePlatformContextMenu(ui::MenuModel* model) {
menu_.reset();
if (model)
menu_.reset(new AppIndicatorIconMenu(model));
}
void Gtk2StatusIcon::RefreshPlatformContextMenu() {
if (menu_.get())
menu_->Refresh();
}
void Gtk2StatusIcon::OnClick(GtkStatusIcon* status_icon) {
if (delegate())
delegate()->OnClick();
}
void Gtk2StatusIcon::OnContextMenuRequested(GtkStatusIcon* status_icon,
guint button,
guint32 activate_time) {
if (menu_.get()) {
gtk_menu_popup(menu_->GetGtkMenu(),
NULL,
NULL,
gtk_status_icon_position_menu,
gtk_status_icon_,
button,
activate_time);
}
}
} // namespace libgtk2ui

View File

@@ -1,61 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_
#define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
#include "ui/base/glib/glib_integers.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/views/linux_ui/status_icon_linux.h"
typedef struct _GtkStatusIcon GtkStatusIcon;
namespace gfx {
class ImageSkia;
}
namespace ui {
class MenuModel;
}
namespace libgtk2ui {
class AppIndicatorIconMenu;
// Status icon implementation which uses the system tray X11 spec (via
// GtkStatusIcon).
class Gtk2StatusIcon : public views::StatusIconLinux {
public:
Gtk2StatusIcon(const gfx::ImageSkia& image, const base::string16& tool_tip);
virtual ~Gtk2StatusIcon();
// Overridden from views::StatusIconLinux:
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetToolTip(const base::string16& tool_tip) OVERRIDE;
virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE;
virtual void RefreshPlatformContextMenu() OVERRIDE;
private:
CHROMEG_CALLBACK_0(Gtk2StatusIcon, void, OnClick, GtkStatusIcon*);
CHROMEG_CALLBACK_2(Gtk2StatusIcon,
void,
OnContextMenuRequested,
GtkStatusIcon*,
guint,
guint);
GtkStatusIcon* gtk_status_icon_;
scoped_ptr<AppIndicatorIconMenu> menu_;
DISALLOW_COPY_AND_ASSIGN(Gtk2StatusIcon);
};
} // namespace libgtk2ui
#endif // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_

View File

@@ -1,236 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
namespace {
////////////////////////////////////////////////////////////////////////////////
// Status Tray API
// The folowing describes the interface to the undocumented Windows Exporer APIs
// for manipulating with the status tray area. This code should be used with
// care as it can change with versions (even minor versions) of Windows.
// ITrayNotify is an interface describing the API for manipulating the state of
// the Windows notification area, as well as for registering for change
// notifications.
class __declspec(uuid("FB852B2C-6BAD-4605-9551-F15F87830935")) ITrayNotify
: public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE
RegisterCallback(INotificationCB* callback) = 0;
virtual HRESULT STDMETHODCALLTYPE
SetPreference(const NOTIFYITEM* notify_item) = 0;
virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL enabled) = 0;
};
// ITrayNotifyWin8 is the interface that replaces ITrayNotify for newer versions
// of Windows.
class __declspec(uuid("D133CE13-3537-48BA-93A7-AFCD5D2053B4")) ITrayNotifyWin8
: public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE
RegisterCallback(INotificationCB* callback, unsigned long*) = 0;
virtual HRESULT STDMETHODCALLTYPE UnregisterCallback(unsigned long*) = 0;
virtual HRESULT STDMETHODCALLTYPE SetPreference(NOTIFYITEM const*) = 0;
virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL) = 0;
virtual HRESULT STDMETHODCALLTYPE DoAction(BOOL) = 0;
};
const CLSID CLSID_TrayNotify = {
0x25DEAD04,
0x1EAC,
0x4911,
{0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};
} // namespace
StatusTrayStateChangerWin::StatusTrayStateChangerWin(UINT icon_id, HWND window)
: interface_version_(INTERFACE_VERSION_UNKNOWN),
icon_id_(icon_id),
window_(window) {
wchar_t module_name[MAX_PATH];
::GetModuleFileName(NULL, module_name, MAX_PATH);
file_name_ = module_name;
}
void StatusTrayStateChangerWin::EnsureTrayIconVisible() {
DCHECK(CalledOnValidThread());
if (!CreateTrayNotify()) {
VLOG(1) << "Unable to create COM object for ITrayNotify.";
return;
}
scoped_ptr<NOTIFYITEM> notify_item = RegisterCallback();
// If the user has already hidden us explicitly, try to honor their choice by
// not changing anything.
if (notify_item->preference == PREFERENCE_SHOW_NEVER)
return;
// If we are already on the taskbar, return since nothing needs to be done.
if (notify_item->preference == PREFERENCE_SHOW_ALWAYS)
return;
notify_item->preference = PREFERENCE_SHOW_ALWAYS;
SendNotifyItemUpdate(notify_item.Pass());
}
STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::AddRef() {
DCHECK(CalledOnValidThread());
return base::win::IUnknownImpl::AddRef();
}
STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::Release() {
DCHECK(CalledOnValidThread());
return base::win::IUnknownImpl::Release();
}
STDMETHODIMP StatusTrayStateChangerWin::QueryInterface(REFIID riid,
PVOID* ptr_void) {
DCHECK(CalledOnValidThread());
if (riid == __uuidof(INotificationCB)) {
*ptr_void = static_cast<INotificationCB*>(this);
AddRef();
return S_OK;
}
return base::win::IUnknownImpl::QueryInterface(riid, ptr_void);
}
STDMETHODIMP StatusTrayStateChangerWin::Notify(ULONG event,
NOTIFYITEM* notify_item) {
DCHECK(CalledOnValidThread());
DCHECK(notify_item);
if (notify_item->hwnd != window_ || notify_item->id != icon_id_ ||
base::string16(notify_item->exe_name) != file_name_) {
return S_OK;
}
notify_item_.reset(new NOTIFYITEM(*notify_item));
return S_OK;
}
StatusTrayStateChangerWin::~StatusTrayStateChangerWin() {
DCHECK(CalledOnValidThread());
}
bool StatusTrayStateChangerWin::CreateTrayNotify() {
DCHECK(CalledOnValidThread());
tray_notify_.Release(); // Release so this method can be called more than
// once.
HRESULT hr = tray_notify_.CreateInstance(CLSID_TrayNotify);
if (FAILED(hr))
return false;
base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;
hr = tray_notify_win8.QueryFrom(tray_notify_);
if (SUCCEEDED(hr)) {
interface_version_ = INTERFACE_VERSION_WIN8;
return true;
}
base::win::ScopedComPtr<ITrayNotify> tray_notify_legacy;
hr = tray_notify_legacy.QueryFrom(tray_notify_);
if (SUCCEEDED(hr)) {
interface_version_ = INTERFACE_VERSION_LEGACY;
return true;
}
return false;
}
scoped_ptr<NOTIFYITEM> StatusTrayStateChangerWin::RegisterCallback() {
// |notify_item_| is used to store the result of the callback from
// Explorer.exe, which happens synchronously during
// RegisterCallbackWin8 or RegisterCallbackLegacy.
DCHECK(notify_item_.get() == NULL);
// TODO(dewittj): Add UMA logging here to report if either of our strategies
// has a tendency to fail on particular versions of Windows.
switch (interface_version_) {
case INTERFACE_VERSION_WIN8:
if (!RegisterCallbackWin8())
VLOG(1) << "Unable to successfully run RegisterCallbackWin8.";
break;
case INTERFACE_VERSION_LEGACY:
if (!RegisterCallbackLegacy())
VLOG(1) << "Unable to successfully run RegisterCallbackLegacy.";
break;
default:
NOTREACHED();
}
// Adding an intermediate scoped pointer here so that |notify_item_| is reset
// to NULL.
scoped_ptr<NOTIFYITEM> rv(notify_item_.release());
return rv.Pass();
}
bool StatusTrayStateChangerWin::RegisterCallbackWin8() {
base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;
HRESULT hr = tray_notify_win8.QueryFrom(tray_notify_);
if (FAILED(hr))
return false;
// The following two lines cause Windows Explorer to call us back with all the
// existing tray icons and their preference. It would also presumably notify
// us if changes were made in realtime while we registered as a callback, but
// we just want to modify our own entry so we immediately unregister.
unsigned long callback_id = 0;
hr = tray_notify_win8->RegisterCallback(this, &callback_id);
tray_notify_win8->UnregisterCallback(&callback_id);
if (FAILED(hr)) {
return false;
}
return true;
}
bool StatusTrayStateChangerWin::RegisterCallbackLegacy() {
base::win::ScopedComPtr<ITrayNotify> tray_notify;
HRESULT hr = tray_notify.QueryFrom(tray_notify_);
if (FAILED(hr)) {
return false;
}
// The following two lines cause Windows Explorer to call us back with all the
// existing tray icons and their preference. It would also presumably notify
// us if changes were made in realtime while we registered as a callback. In
// this version of the API, there can be only one registered callback so it is
// better to unregister as soon as possible.
// TODO(dewittj): Try to notice if the notification area icon customization
// window is open and postpone this call until the user closes it;
// registering the callback while the window is open can cause stale data to
// be displayed to the user.
hr = tray_notify->RegisterCallback(this);
tray_notify->RegisterCallback(NULL);
if (FAILED(hr)) {
return false;
}
return true;
}
void StatusTrayStateChangerWin::SendNotifyItemUpdate(
scoped_ptr<NOTIFYITEM> notify_item) {
if (interface_version_ == INTERFACE_VERSION_LEGACY) {
base::win::ScopedComPtr<ITrayNotify> tray_notify;
HRESULT hr = tray_notify.QueryFrom(tray_notify_);
if (SUCCEEDED(hr))
tray_notify->SetPreference(notify_item.get());
} else if (interface_version_ == INTERFACE_VERSION_WIN8) {
base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify;
HRESULT hr = tray_notify.QueryFrom(tray_notify_);
if (SUCCEEDED(hr))
tray_notify->SetPreference(notify_item.get());
}
}

View File

@@ -1,133 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_
#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/threading/non_thread_safe.h"
#include "base/win/iunknown_impl.h"
#include "base/win/scoped_comptr.h"
// The known values for NOTIFYITEM's dwPreference member.
enum NOTIFYITEM_PREFERENCE {
// In Windows UI: "Only show notifications."
PREFERENCE_SHOW_WHEN_ACTIVE = 0,
// In Windows UI: "Hide icon and notifications."
PREFERENCE_SHOW_NEVER = 1,
// In Windows UI: "Show icon and notifications."
PREFERENCE_SHOW_ALWAYS = 2
};
// NOTIFYITEM describes an entry in Explorer's registry of status icons.
// Explorer keeps entries around for a process even after it exits.
struct NOTIFYITEM {
PWSTR exe_name; // The file name of the creating executable.
PWSTR tip; // The last hover-text value associated with this status
// item.
HICON icon; // The icon associated with this status item.
HWND hwnd; // The HWND associated with the status item.
DWORD preference; // Determines the behavior of the icon with respect to
// the taskbar. Values taken from NOTIFYITEM_PREFERENCE.
UINT id; // The ID specified by the application. (hWnd, uID) is
// unique.
GUID guid; // The GUID specified by the application, alternative to
// uID.
};
// INotificationCB is an interface that applications can implement in order to
// receive notifications about the state of the notification area manager.
class __declspec(uuid("D782CCBA-AFB0-43F1-94DB-FDA3779EACCB")) INotificationCB
: public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE
Notify(ULONG event, NOTIFYITEM* notify_item) = 0;
};
// A class that is capable of reading and writing the state of the notification
// area in the Windows taskbar. It is used to promote a tray icon from the
// overflow area to the taskbar, and refuses to do anything if the user has
// explicitly marked an icon to be always hidden.
class StatusTrayStateChangerWin : public INotificationCB,
public base::win::IUnknownImpl,
public base::NonThreadSafe {
public:
StatusTrayStateChangerWin(UINT icon_id, HWND window);
// Call this method to move the icon matching |icon_id| and |window| to the
// taskbar from the overflow area. This will not make any changes if the
// icon has been set to |PREFERENCE_SHOW_NEVER|, in order to comply with
// the explicit wishes/configuration of the user.
void EnsureTrayIconVisible();
// IUnknown.
virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE;
virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE;
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, PVOID*) OVERRIDE;
// INotificationCB.
// Notify is called in response to RegisterCallback for each current
// entry in Explorer's list of notification area icons, and ever time
// one of them changes, until UnregisterCallback is called or |this|
// is destroyed.
virtual HRESULT STDMETHODCALLTYPE Notify(ULONG, NOTIFYITEM*);
protected:
virtual ~StatusTrayStateChangerWin();
private:
friend class StatusTrayStateChangerWinTest;
enum InterfaceVersion {
INTERFACE_VERSION_LEGACY = 0,
INTERFACE_VERSION_WIN8,
INTERFACE_VERSION_UNKNOWN
};
// Creates an instance of TrayNotify, and ensures that it supports either
// ITrayNotify or ITrayNotifyWin8. Returns true on success.
bool CreateTrayNotify();
// Returns the NOTIFYITEM that corresponds to this executable and the
// HWND/ID pair that were used to create the StatusTrayStateChangerWin.
// Internally it calls the appropriate RegisterCallback{Win8,Legacy}.
scoped_ptr<NOTIFYITEM> RegisterCallback();
// Calls RegisterCallback with the appropriate interface required by
// different versions of Windows. This will result in |notify_item_| being
// updated when a matching item is passed into
// StatusTrayStateChangerWin::Notify.
bool RegisterCallbackWin8();
bool RegisterCallbackLegacy();
// Sends an update to Explorer with the passed NOTIFYITEM.
void SendNotifyItemUpdate(scoped_ptr<NOTIFYITEM> notify_item);
// Storing IUnknown since we will need to use different interfaces
// for different versions of Windows.
base::win::ScopedComPtr<IUnknown> tray_notify_;
InterfaceVersion interface_version_;
// The ID assigned to the notification area icon that we want to manipulate.
const UINT icon_id_;
// The HWND associated with the notification area icon that we want to
// manipulate. This is an unretained pointer, do not dereference.
const HWND window_;
// Executable name of the current program. Along with |icon_id_| and
// |window_|, this uniquely identifies a notification area entry to Explorer.
base::string16 file_name_;
// Temporary storage for the matched NOTIFYITEM. This is necessary because
// Notify doesn't return anything. The call flow looks like this:
// TrayNotify->RegisterCallback()
// ... other COM stack frames ..
// StatusTrayStateChangerWin->Notify(NOTIFYITEM);
// so we can't just return the notifyitem we're looking for.
scoped_ptr<NOTIFYITEM> notify_item_;
DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerWin);
};
#endif // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_

View File

@@ -22,8 +22,7 @@
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "net/base/escape.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/pdf_metafile_skia.h"
#include "printing/units.h"
#include "skia/ext/vector_platform_device_skia.h"
#include "third_party/WebKit/public/platform/WebSize.h"
@@ -65,7 +64,8 @@ bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) {
return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() &&
!params.printable_area.IsEmpty() && params.document_cookie &&
params.desired_dpi && params.max_shrink && params.min_shrink &&
params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0);
params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0) &&
params.dpi > kMinDpi && params.document_cookie != 0;
}
PrintMsg_Print_Params GetCssPrintParams(
@@ -409,8 +409,6 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
return expected_pages_count_;
}
gfx::Size GetPrintCanvasSize() const;
void FinishPrinting();
bool IsLoadingSelection() {
@@ -590,12 +588,6 @@ void PrepareFrameAndViewForPrint::CallOnReady() {
return on_ready_.Run(); // Can delete |this|.
}
gfx::Size PrepareFrameAndViewForPrint::GetPrintCanvasSize() const {
DCHECK(is_printing_started_);
return gfx::Size(web_print_params_.printContentArea.width,
web_print_params_.printContentArea.height);
}
void PrepareFrameAndViewForPrint::RestoreSize() {
if (frame()) {
blink::WebView* web_view = frame_.GetFrame()->view();
@@ -606,7 +598,7 @@ void PrepareFrameAndViewForPrint::RestoreSize() {
}
void PrepareFrameAndViewForPrint::FinishPrinting() {
blink::WebFrame* frame = frame_.GetFrame();
blink::WebLocalFrame* frame = frame_.GetFrame();
if (frame) {
blink::WebView* web_view = frame->view();
if (is_printing_started_) {
@@ -630,10 +622,15 @@ void PrepareFrameAndViewForPrint::FinishPrinting() {
PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view)
: content::RenderViewObserver(render_view),
content::RenderViewObserverTracker<PrintWebViewHelper>(render_view),
reset_prep_frame_view_(false),
is_print_ready_metafile_sent_(false),
ignore_css_margins_(false),
is_scripted_printing_blocked_(false),
notify_browser_of_print_failure_(true),
print_for_preview_(false),
print_node_in_progress_(false),
is_loading_(false),
is_scripted_preview_delayed_(false),
weak_ptr_factory_(this) {
}
@@ -673,11 +670,13 @@ bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) {
return true;
}
#if !defined(DISABLE_BASIC_PRINTING)
void PrintWebViewHelper::OnPrintPages(bool silent, bool print_background) {
blink::WebLocalFrame* frame;
if (GetPrintFrame(&frame))
Print(frame, blink::WebNode(), silent, print_background);
}
#endif // !DISABLE_BASIC_PRINTING
void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
const PageSizeMargins& page_layout_in_points,
@@ -726,9 +725,6 @@ void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
}
print_node_in_progress_ = true;
// Make a copy of the node, in case RenderView::OnContextMenuClosed resets
// its |context_menu_node_|.
blink::WebNode duplicate_node(node);
Print(duplicate_node.document().frame(), duplicate_node);
@@ -783,7 +779,7 @@ void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
break;
case FAIL_PRINT:
if (notify_browser_of_print_failure_ && print_pages_params_.get()) {
if (notify_browser_of_print_failure_ && print_pages_params_) {
int cookie = print_pages_params_->params.document_cookie;
Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
}
@@ -821,8 +817,7 @@ void PrintWebViewHelper::PrintPages() {
page_count));
#endif // !defined(OS_CHROMEOS)
if (!PrintPagesNative(prep_frame_view_->frame(), page_count,
prep_frame_view_->GetPrintCanvasSize())) {
if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) {
LOG(ERROR) << "Printing failed.";
return DidFinishPrinting(FAIL_PRINT);
}
@@ -832,10 +827,9 @@ void PrintWebViewHelper::FinishFramePrinting() {
prep_frame_view_.reset();
}
#if defined(OS_MACOSX) || defined(OS_WIN)
#if defined(OS_MACOSX)
bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
int page_count,
const gfx::Size& canvas_size) {
int page_count) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
@@ -844,20 +838,20 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
if (params.pages.empty()) {
for (int i = 0; i < page_count; ++i) {
page_params.page_number = i;
PrintPageInternal(page_params, canvas_size, frame);
PrintPageInternal(page_params, frame);
}
} else {
for (size_t i = 0; i < params.pages.size(); ++i) {
if (params.pages[i] >= page_count)
break;
page_params.page_number = params.pages[i];
PrintPageInternal(page_params, canvas_size, frame);
PrintPageInternal(page_params, frame);
}
}
return true;
}
#endif // OS_MACOSX || OS_WIN
#endif // OS_MACOSX
// static - Not anonymous so that platform implementations can use it.
void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
@@ -886,13 +880,6 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
if (!PrintMsg_Print_Params_IsValid(settings.params))
result = false;
if (result &&
(settings.params.dpi < kMinDpi || settings.params.document_cookie == 0)) {
// Invalid print page settings.
NOTREACHED();
result = false;
}
// Reset to default values.
ignore_css_margins_ = false;
settings.pages.clear();
@@ -904,7 +891,7 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
blink::WebPrintScalingOptionFitToPrintableArea;
}
print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
SetPrintPagesParams(settings);
return result;
}
@@ -923,8 +910,6 @@ bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
PrepareFrameAndViewForPrint prepare(params, frame, node, ignore_css_margins_);
prepare.StartPrinting();
Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
params.document_cookie));
*number_of_pages = prepare.GetExpectedPageCount();
return true;
}
@@ -953,9 +938,8 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame,
new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings);
msg->EnableMessagePumping();
Send(msg);
print_pages_params_.reset(new PrintMsg_PrintPages_Params(print_settings));
print_pages_params_->params.print_scaling_option = scaling_option;
print_settings.params.print_scaling_option = scaling_option;
SetPrintPagesParams(print_settings);
return (print_settings.params.dpi && print_settings.params.document_cookie);
}
@@ -965,9 +949,8 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
return false;
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
prep_frame_view_.reset(
new PrepareFrameAndViewForPrint(print_params, frame, node,
ignore_css_margins_));
prep_frame_view_.reset(new PrepareFrameAndViewForPrint(
print_params, frame, node, ignore_css_margins_));
DCHECK(!print_pages_params_->params.selection_only ||
print_pages_params_->pages.empty());
prep_frame_view_->CopySelectionIfNeeded(
@@ -979,24 +962,27 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
#if defined(OS_POSIX)
bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
Metafile* metafile,
PdfMetafileSkia* metafile,
base::SharedMemoryHandle* shared_mem_handle) {
uint32 buf_size = metafile->GetDataSize();
scoped_ptr<base::SharedMemory> shared_buf(
content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
buf_size).release());
if (shared_buf.get()) {
if (shared_buf) {
if (shared_buf->Map(buf_size)) {
metafile->GetData(shared_buf->memory(), buf_size);
shared_buf->GiveToProcess(base::GetCurrentProcessHandle(),
shared_mem_handle);
return true;
return shared_buf->GiveToProcess(base::GetCurrentProcessHandle(),
shared_mem_handle);
}
}
NOTREACHED();
return false;
}
#endif // defined(OS_POSIX)
void PrintWebViewHelper::SetPrintPagesParams(
const PrintMsg_PrintPages_Params& settings) {
print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
}
} // namespace printing

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