feat: add support for share menu on macOS (#25629)
This commit is contained in:
		
					parent
					
						
							
								89c04b3c6c
							
						
					
				
			
			
				commit
				
					
						6b6ffbdd10
					
				
			
		
					 17 changed files with 316 additions and 6 deletions
				
			
		| 
						 | 
					@ -14,7 +14,7 @@ See [`Menu`](menu.md) for examples.
 | 
				
			||||||
    * `menuItem` MenuItem
 | 
					    * `menuItem` MenuItem
 | 
				
			||||||
    * `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open.
 | 
					    * `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open.
 | 
				
			||||||
    * `event` [KeyboardEvent](structures/keyboard-event.md)
 | 
					    * `event` [KeyboardEvent](structures/keyboard-event.md)
 | 
				
			||||||
  * `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
 | 
					  * `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
 | 
				
			||||||
    `click` property will be ignored. See [roles](#roles).
 | 
					    `click` property will be ignored. See [roles](#roles).
 | 
				
			||||||
  * `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or
 | 
					  * `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or
 | 
				
			||||||
    `radio`.
 | 
					    `radio`.
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ See [`Menu`](menu.md) for examples.
 | 
				
			||||||
    menu items.
 | 
					    menu items.
 | 
				
			||||||
  * `registerAccelerator` Boolean (optional) _Linux_ _Windows_ - If false, the accelerator won't be registered
 | 
					  * `registerAccelerator` Boolean (optional) _Linux_ _Windows_ - If false, the accelerator won't be registered
 | 
				
			||||||
    with the system, but it will still be displayed. Defaults to true.
 | 
					    with the system, but it will still be displayed. Defaults to true.
 | 
				
			||||||
 | 
					  * `sharingItem` SharingItem (optional) _macOS_ - The item to share when the `role` is `shareMenu`.
 | 
				
			||||||
  * `submenu` (MenuItemConstructorOptions[] | [Menu](menu.md)) (optional) - Should be specified
 | 
					  * `submenu` (MenuItemConstructorOptions[] | [Menu](menu.md)) (optional) - Should be specified
 | 
				
			||||||
    for `submenu` type menu items. If `submenu` is specified, the `type: 'submenu'` can be omitted.
 | 
					    for `submenu` type menu items. If `submenu` is specified, the `type: 'submenu'` can be omitted.
 | 
				
			||||||
    If the value is not a [`Menu`](menu.md) then it will be automatically converted to one using
 | 
					    If the value is not a [`Menu`](menu.md) then it will be automatically converted to one using
 | 
				
			||||||
| 
						 | 
					@ -112,6 +113,7 @@ The following additional roles are available on _macOS_:
 | 
				
			||||||
* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is *not* the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron.
 | 
					* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is *not* the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron.
 | 
				
			||||||
* `recentDocuments` - The submenu is an "Open Recent" menu.
 | 
					* `recentDocuments` - The submenu is an "Open Recent" menu.
 | 
				
			||||||
* `clearRecentDocuments` - Map to the `clearRecentDocuments` action.
 | 
					* `clearRecentDocuments` - Map to the `clearRecentDocuments` action.
 | 
				
			||||||
 | 
					* `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When specifying a `role` on macOS, `label` and `accelerator` are the only
 | 
					When specifying a `role` on macOS, `label` and `accelerator` are the only
 | 
				
			||||||
options that will affect the menu item. All other options will be ignored.
 | 
					options that will affect the menu item. All other options will be ignored.
 | 
				
			||||||
| 
						 | 
					@ -200,6 +202,12 @@ system or just displayed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This property can be dynamically changed.
 | 
					This property can be dynamically changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `menuItem.sharingItem` _macOS_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A `SharingItem` indicating the item to share when the `role` is `shareMenu`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This property can be dynamically changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `menuItem.commandId`
 | 
					#### `menuItem.commandId`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A `Number` indicating an item's sequential unique id.
 | 
					A `Number` indicating an item's sequential unique id.
 | 
				
			||||||
| 
						 | 
					@ -207,3 +215,5 @@ A `Number` indicating an item's sequential unique id.
 | 
				
			||||||
#### `menuItem.menu`
 | 
					#### `menuItem.menu`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A `Menu` that the item is a part of.
 | 
					A `Menu` that the item is a part of.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ShareMenu]: https://developer.apple.com/design/human-interface-guidelines/macos/extensions/share-extensions/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										45
									
								
								docs/api/share-menu.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								docs/api/share-menu.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,45 @@
 | 
				
			||||||
 | 
					## Class: ShareMenu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Create share menu on macOS.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Process: [Main](../glossary.md#main-process)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `ShareMenu` class creates [Share Menu][share-menu] on macOS, which can be
 | 
				
			||||||
 | 
					used to share information from the current context to apps, social media
 | 
				
			||||||
 | 
					accounts, and other services.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For including the share menu as a submenu of other menus, please use the
 | 
				
			||||||
 | 
					`shareMenu` role of [`MenuItem`](menu-item.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### `new ShareMenu(sharingItem)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `sharingItem` SharingItem - The item to share.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Creates a new share menu.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Instance Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `shareMenu` object has the following instance methods:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `shareMenu.popup([options])`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `options` PopupOptions (optional)
 | 
				
			||||||
 | 
					  * `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window.
 | 
				
			||||||
 | 
					  * `x` Number (optional) - Default is the current mouse cursor position.
 | 
				
			||||||
 | 
					    Must be declared if `y` is declared.
 | 
				
			||||||
 | 
					  * `y` Number (optional) - Default is the current mouse cursor position.
 | 
				
			||||||
 | 
					    Must be declared if `x` is declared.
 | 
				
			||||||
 | 
					  * `positioningItem` Number (optional) _macOS_ - The index of the menu item to
 | 
				
			||||||
 | 
					    be positioned under the mouse cursor at the specified coordinates. Default
 | 
				
			||||||
 | 
					    is -1.
 | 
				
			||||||
 | 
					  * `callback` Function (optional) - Called when menu is closed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pops up this menu as a context menu in the [`BrowserWindow`](browser-window.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `shareMenu.closePopup([browserWindow])`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Closes the context menu in the `browserWindow`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[share-menu]: https://developer.apple.com/design/human-interface-guidelines/macos/extensions/share-extensions/
 | 
				
			||||||
							
								
								
									
										5
									
								
								docs/api/structures/sharing-item.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								docs/api/structures/sharing-item.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					# SharingItem Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `texts` String[] (optional) - An array of text to share.
 | 
				
			||||||
 | 
					* `filePaths` String[] (optional) - An array of files to share.
 | 
				
			||||||
 | 
					* `urls` String[] (optional) - An array of URLs to share.
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,7 @@ auto_filenames = {
 | 
				
			||||||
    "docs/api/screen.md",
 | 
					    "docs/api/screen.md",
 | 
				
			||||||
    "docs/api/service-workers.md",
 | 
					    "docs/api/service-workers.md",
 | 
				
			||||||
    "docs/api/session.md",
 | 
					    "docs/api/session.md",
 | 
				
			||||||
 | 
					    "docs/api/share-menu.md",
 | 
				
			||||||
    "docs/api/shell.md",
 | 
					    "docs/api/shell.md",
 | 
				
			||||||
    "docs/api/structures",
 | 
					    "docs/api/structures",
 | 
				
			||||||
    "docs/api/synopsis.md",
 | 
					    "docs/api/synopsis.md",
 | 
				
			||||||
| 
						 | 
					@ -119,6 +120,7 @@ auto_filenames = {
 | 
				
			||||||
    "docs/api/structures/serial-port.md",
 | 
					    "docs/api/structures/serial-port.md",
 | 
				
			||||||
    "docs/api/structures/service-worker-info.md",
 | 
					    "docs/api/structures/service-worker-info.md",
 | 
				
			||||||
    "docs/api/structures/shared-worker-info.md",
 | 
					    "docs/api/structures/shared-worker-info.md",
 | 
				
			||||||
 | 
					    "docs/api/structures/sharing-item.md",
 | 
				
			||||||
    "docs/api/structures/shortcut-details.md",
 | 
					    "docs/api/structures/shortcut-details.md",
 | 
				
			||||||
    "docs/api/structures/size.md",
 | 
					    "docs/api/structures/size.md",
 | 
				
			||||||
    "docs/api/structures/task.md",
 | 
					    "docs/api/structures/task.md",
 | 
				
			||||||
| 
						 | 
					@ -219,6 +221,7 @@ auto_filenames = {
 | 
				
			||||||
    "lib/browser/api/protocol.ts",
 | 
					    "lib/browser/api/protocol.ts",
 | 
				
			||||||
    "lib/browser/api/screen.ts",
 | 
					    "lib/browser/api/screen.ts",
 | 
				
			||||||
    "lib/browser/api/session.ts",
 | 
					    "lib/browser/api/session.ts",
 | 
				
			||||||
 | 
					    "lib/browser/api/share-menu.ts",
 | 
				
			||||||
    "lib/browser/api/system-preferences.ts",
 | 
					    "lib/browser/api/system-preferences.ts",
 | 
				
			||||||
    "lib/browser/api/touch-bar.ts",
 | 
					    "lib/browser/api/touch-bar.ts",
 | 
				
			||||||
    "lib/browser/api/tray.ts",
 | 
					    "lib/browser/api/tray.ts",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ const isLinux = process.platform === 'linux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' |
 | 
					type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' |
 | 
				
			||||||
  'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' |
 | 
					  'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' |
 | 
				
			||||||
  'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu'
 | 
					  'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu' | 'sharemenu'
 | 
				
			||||||
interface Role {
 | 
					interface Role {
 | 
				
			||||||
  label: string;
 | 
					  label: string;
 | 
				
			||||||
  accelerator?: string;
 | 
					  accelerator?: string;
 | 
				
			||||||
| 
						 | 
					@ -261,6 +261,11 @@ export const roleList: Record<RoleId, Role> = {
 | 
				
			||||||
        { role: 'close' }
 | 
					        { role: 'close' }
 | 
				
			||||||
      ] as MenuItemConstructorOptions[])
 | 
					      ] as MenuItemConstructorOptions[])
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  // Share submenu
 | 
				
			||||||
 | 
					  sharemenu: {
 | 
				
			||||||
 | 
					    label: 'Share',
 | 
				
			||||||
 | 
					    submenu: []
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,12 @@ Menu.prototype._shouldRegisterAcceleratorForCommandId = function (id) {
 | 
				
			||||||
  return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : false;
 | 
					  return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (process.platform === 'darwin') {
 | 
				
			||||||
 | 
					  Menu.prototype._getSharingItemForCommandId = function (id) {
 | 
				
			||||||
 | 
					    return this.commandsMap[id] ? this.commandsMap[id].sharingItem : null;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Menu.prototype._executeCommand = function (event, id) {
 | 
					Menu.prototype._executeCommand = function (event, id) {
 | 
				
			||||||
  const command = this.commandsMap[id];
 | 
					  const command = this.commandsMap[id];
 | 
				
			||||||
  if (!command) return;
 | 
					  if (!command) return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
 | 
				
			||||||
  { name: 'protocol', loader: () => require('./protocol') },
 | 
					  { name: 'protocol', loader: () => require('./protocol') },
 | 
				
			||||||
  { name: 'screen', loader: () => require('./screen') },
 | 
					  { name: 'screen', loader: () => require('./screen') },
 | 
				
			||||||
  { name: 'session', loader: () => require('./session') },
 | 
					  { name: 'session', loader: () => require('./session') },
 | 
				
			||||||
 | 
					  { name: 'ShareMenu', loader: () => require('./share-menu') },
 | 
				
			||||||
  { name: 'systemPreferences', loader: () => require('./system-preferences') },
 | 
					  { name: 'systemPreferences', loader: () => require('./system-preferences') },
 | 
				
			||||||
  { name: 'TouchBar', loader: () => require('./touch-bar') },
 | 
					  { name: 'TouchBar', loader: () => require('./touch-bar') },
 | 
				
			||||||
  { name: 'Tray', loader: () => require('./tray') },
 | 
					  { name: 'Tray', loader: () => require('./tray') },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ export const browserModuleNames = [
 | 
				
			||||||
  'protocol',
 | 
					  'protocol',
 | 
				
			||||||
  'screen',
 | 
					  'screen',
 | 
				
			||||||
  'session',
 | 
					  'session',
 | 
				
			||||||
 | 
					  'ShareMenu',
 | 
				
			||||||
  'systemPreferences',
 | 
					  'systemPreferences',
 | 
				
			||||||
  'TouchBar',
 | 
					  'TouchBar',
 | 
				
			||||||
  'Tray',
 | 
					  'Tray',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								lib/browser/api/share-menu.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/browser/api/share-menu.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					import { BrowserWindow, Menu, SharingItem, PopupOptions } from 'electron/main';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ShareMenu {
 | 
				
			||||||
 | 
					  private menu: Menu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor (sharingItem: SharingItem) {
 | 
				
			||||||
 | 
					    this.menu = new (Menu as any)({ sharingItem });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  popup (options?: PopupOptions) {
 | 
				
			||||||
 | 
					    this.menu.popup(options);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closePopup (browserWindow?: BrowserWindow) {
 | 
				
			||||||
 | 
					    this.menu.closePopup(browserWindow);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ShareMenu;
 | 
				
			||||||
| 
						 | 
					@ -12,12 +12,39 @@
 | 
				
			||||||
#include "shell/browser/native_window.h"
 | 
					#include "shell/browser/native_window.h"
 | 
				
			||||||
#include "shell/common/gin_converters/accelerator_converter.h"
 | 
					#include "shell/common/gin_converters/accelerator_converter.h"
 | 
				
			||||||
#include "shell/common/gin_converters/callback_converter.h"
 | 
					#include "shell/common/gin_converters/callback_converter.h"
 | 
				
			||||||
 | 
					#include "shell/common/gin_converters/file_path_converter.h"
 | 
				
			||||||
 | 
					#include "shell/common/gin_converters/gurl_converter.h"
 | 
				
			||||||
#include "shell/common/gin_converters/image_converter.h"
 | 
					#include "shell/common/gin_converters/image_converter.h"
 | 
				
			||||||
#include "shell/common/gin_helper/dictionary.h"
 | 
					#include "shell/common/gin_helper/dictionary.h"
 | 
				
			||||||
#include "shell/common/gin_helper/object_template_builder.h"
 | 
					#include "shell/common/gin_helper/object_template_builder.h"
 | 
				
			||||||
#include "shell/common/node_includes.h"
 | 
					#include "shell/common/node_includes.h"
 | 
				
			||||||
#include "ui/base/models/image_model.h"
 | 
					#include "ui/base/models/image_model.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace gin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using SharingItem = electron::ElectronMenuModel::SharingItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <>
 | 
				
			||||||
 | 
					struct Converter<SharingItem> {
 | 
				
			||||||
 | 
					  static bool FromV8(v8::Isolate* isolate,
 | 
				
			||||||
 | 
					                     v8::Local<v8::Value> val,
 | 
				
			||||||
 | 
					                     SharingItem* out) {
 | 
				
			||||||
 | 
					    gin_helper::Dictionary dict;
 | 
				
			||||||
 | 
					    if (!ConvertFromV8(isolate, val, &dict))
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    dict.GetOptional("texts", &(out->texts));
 | 
				
			||||||
 | 
					    dict.GetOptional("filePaths", &(out->file_paths));
 | 
				
			||||||
 | 
					    dict.GetOptional("urls", &(out->urls));
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace gin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace electron {
 | 
					namespace electron {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
| 
						 | 
					@ -26,6 +53,15 @@ gin::WrapperInfo Menu::kWrapperInfo = {gin::kEmbedderNativeGin};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Menu::Menu(gin::Arguments* args) : model_(new ElectronMenuModel(this)) {
 | 
					Menu::Menu(gin::Arguments* args) : model_(new ElectronMenuModel(this)) {
 | 
				
			||||||
  model_->AddObserver(this);
 | 
					  model_->AddObserver(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					  gin_helper::Dictionary options;
 | 
				
			||||||
 | 
					  if (args->GetNext(&options)) {
 | 
				
			||||||
 | 
					    ElectronMenuModel::SharingItem item;
 | 
				
			||||||
 | 
					    if (options.Get("sharingItem", &item))
 | 
				
			||||||
 | 
					      model_->SetSharingItem(std::move(item));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Menu::~Menu() {
 | 
					Menu::~Menu() {
 | 
				
			||||||
| 
						 | 
					@ -81,6 +117,19 @@ bool Menu::ShouldRegisterAcceleratorForCommandId(int command_id) const {
 | 
				
			||||||
                          command_id);
 | 
					                          command_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					bool Menu::GetSharingItemForCommandId(
 | 
				
			||||||
 | 
					    int command_id,
 | 
				
			||||||
 | 
					    ElectronMenuModel::SharingItem* item) const {
 | 
				
			||||||
 | 
					  v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
 | 
				
			||||||
 | 
					  v8::HandleScope handle_scope(isolate);
 | 
				
			||||||
 | 
					  v8::Local<v8::Value> val =
 | 
				
			||||||
 | 
					      gin_helper::CallMethod(isolate, const_cast<Menu*>(this),
 | 
				
			||||||
 | 
					                             "_getSharingItemForCommandId", command_id);
 | 
				
			||||||
 | 
					  return gin::ConvertFromV8(isolate, val, item);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Menu::ExecuteCommand(int command_id, int flags) {
 | 
					void Menu::ExecuteCommand(int command_id, int flags) {
 | 
				
			||||||
  v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
 | 
					  v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
 | 
				
			||||||
  v8::HandleScope scope(isolate);
 | 
					  v8::HandleScope scope(isolate);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,11 @@ class Menu : public gin::Wrappable<Menu>,
 | 
				
			||||||
      bool use_default_accelerator,
 | 
					      bool use_default_accelerator,
 | 
				
			||||||
      ui::Accelerator* accelerator) const override;
 | 
					      ui::Accelerator* accelerator) const override;
 | 
				
			||||||
  bool ShouldRegisterAcceleratorForCommandId(int command_id) const override;
 | 
					  bool ShouldRegisterAcceleratorForCommandId(int command_id) const override;
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					  bool GetSharingItemForCommandId(
 | 
				
			||||||
 | 
					      int command_id,
 | 
				
			||||||
 | 
					      ElectronMenuModel::SharingItem* item) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  void ExecuteCommand(int command_id, int event_flags) override;
 | 
					  void ExecuteCommand(int command_id, int event_flags) override;
 | 
				
			||||||
  void OnMenuWillShow(ui::SimpleMenuModel* source) override;
 | 
					  void OnMenuWillShow(ui::SimpleMenuModel* source) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,8 @@ class ElectronMenuModel;
 | 
				
			||||||
// allow for hierarchical menus). The tag is the index into that model for
 | 
					// allow for hierarchical menus). The tag is the index into that model for
 | 
				
			||||||
// that particular item. It is important that the model outlives this object
 | 
					// that particular item. It is important that the model outlives this object
 | 
				
			||||||
// as it only maintains weak references.
 | 
					// as it only maintains weak references.
 | 
				
			||||||
@interface ElectronMenuController : NSObject <NSMenuDelegate> {
 | 
					@interface ElectronMenuController
 | 
				
			||||||
 | 
					    : NSObject <NSMenuDelegate, NSSharingServiceDelegate> {
 | 
				
			||||||
 @protected
 | 
					 @protected
 | 
				
			||||||
  base::WeakPtr<electron::ElectronMenuModel> model_;
 | 
					  base::WeakPtr<electron::ElectronMenuModel> model_;
 | 
				
			||||||
  base::scoped_nsobject<NSMenu> menu_;
 | 
					  base::scoped_nsobject<NSMenu> menu_;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#import "shell/browser/ui/cocoa/electron_menu_controller.h"
 | 
					#import "shell/browser/ui/cocoa/electron_menu_controller.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "base/logging.h"
 | 
					#include "base/logging.h"
 | 
				
			||||||
| 
						 | 
					@ -14,8 +15,11 @@
 | 
				
			||||||
#include "base/task/post_task.h"
 | 
					#include "base/task/post_task.h"
 | 
				
			||||||
#include "content/public/browser/browser_task_traits.h"
 | 
					#include "content/public/browser/browser_task_traits.h"
 | 
				
			||||||
#include "content/public/browser/browser_thread.h"
 | 
					#include "content/public/browser/browser_thread.h"
 | 
				
			||||||
 | 
					#include "net/base/mac/url_conversions.h"
 | 
				
			||||||
#include "shell/browser/mac/electron_application.h"
 | 
					#include "shell/browser/mac/electron_application.h"
 | 
				
			||||||
 | 
					#include "shell/browser/native_window.h"
 | 
				
			||||||
#include "shell/browser/ui/electron_menu_model.h"
 | 
					#include "shell/browser/ui/electron_menu_model.h"
 | 
				
			||||||
 | 
					#include "shell/browser/window_list.h"
 | 
				
			||||||
#include "ui/base/accelerators/accelerator.h"
 | 
					#include "ui/base/accelerators/accelerator.h"
 | 
				
			||||||
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
 | 
					#include "ui/base/accelerators/platform_accelerator_cocoa.h"
 | 
				
			||||||
#include "ui/base/l10n/l10n_util_mac.h"
 | 
					#include "ui/base/l10n/l10n_util_mac.h"
 | 
				
			||||||
| 
						 | 
					@ -24,6 +28,7 @@
 | 
				
			||||||
#include "ui/strings/grit/ui_strings.h"
 | 
					#include "ui/strings/grit/ui_strings.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using content::BrowserThread;
 | 
					using content::BrowserThread;
 | 
				
			||||||
 | 
					using SharingItem = electron::ElectronMenuModel::SharingItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +91,24 @@ NSMenu* MakeEmptySubmenu() {
 | 
				
			||||||
  return submenu.autorelease();
 | 
					  return submenu.autorelease();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convert an SharingItem to an array of NSObjects.
 | 
				
			||||||
 | 
					NSArray* ConvertSharingItemToNS(const SharingItem& item) {
 | 
				
			||||||
 | 
					  NSMutableArray* result = [NSMutableArray array];
 | 
				
			||||||
 | 
					  if (item.texts) {
 | 
				
			||||||
 | 
					    for (const std::string& str : *item.texts)
 | 
				
			||||||
 | 
					      [result addObject:base::SysUTF8ToNSString(str)];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (item.file_paths) {
 | 
				
			||||||
 | 
					    for (const base::FilePath& path : *item.file_paths)
 | 
				
			||||||
 | 
					      [result addObject:base::mac::FilePathToNSURL(path)];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (item.urls) {
 | 
				
			||||||
 | 
					    for (const GURL& url : *item.urls)
 | 
				
			||||||
 | 
					      [result addObject:net::NSURLWithGURL(url)];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This class stores a base::WeakPtr<electron::ElectronMenuModel> as an
 | 
					// This class stores a base::WeakPtr<electron::ElectronMenuModel> as an
 | 
				
			||||||
| 
						 | 
					@ -267,6 +290,31 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
 | 
				
			||||||
  recentDocumentsMenuItem_.reset([item retain]);
 | 
					  recentDocumentsMenuItem_.reset([item retain]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fill the menu with Share Menu items.
 | 
				
			||||||
 | 
					- (NSMenu*)createShareMenuForItem:(const SharingItem&)item {
 | 
				
			||||||
 | 
					  NSArray* items = ConvertSharingItemToNS(item);
 | 
				
			||||||
 | 
					  if ([items count] == 0)
 | 
				
			||||||
 | 
					    return MakeEmptySubmenu();
 | 
				
			||||||
 | 
					  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] init]);
 | 
				
			||||||
 | 
					  NSArray* services = [NSSharingService sharingServicesForItems:items];
 | 
				
			||||||
 | 
					  for (NSSharingService* service in services)
 | 
				
			||||||
 | 
					    [menu addItem:[self menuItemForService:service withItems:items]];
 | 
				
			||||||
 | 
					  return menu.autorelease();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Creates a menu item that calls |service| when invoked.
 | 
				
			||||||
 | 
					- (NSMenuItem*)menuItemForService:(NSSharingService*)service
 | 
				
			||||||
 | 
					                        withItems:(NSArray*)items {
 | 
				
			||||||
 | 
					  base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
 | 
				
			||||||
 | 
					      initWithTitle:service.menuItemTitle
 | 
				
			||||||
 | 
					             action:@selector(performShare:)
 | 
				
			||||||
 | 
					      keyEquivalent:@""]);
 | 
				
			||||||
 | 
					  [item setTarget:self];
 | 
				
			||||||
 | 
					  [item setImage:service.image];
 | 
				
			||||||
 | 
					  [item setRepresentedObject:@{@"service" : service, @"items" : items}];
 | 
				
			||||||
 | 
					  return item.autorelease();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Adds an item or a hierarchical menu to the item at the |index|,
 | 
					// Adds an item or a hierarchical menu to the item at the |index|,
 | 
				
			||||||
// associated with the entry in the model identified by |modelIndex|.
 | 
					// associated with the entry in the model identified by |modelIndex|.
 | 
				
			||||||
- (void)addItemToMenu:(NSMenu*)menu
 | 
					- (void)addItemToMenu:(NSMenu*)menu
 | 
				
			||||||
| 
						 | 
					@ -300,6 +348,12 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
 | 
				
			||||||
    NSMenu* submenu = [[[NSMenu alloc] initWithTitle:label] autorelease];
 | 
					    NSMenu* submenu = [[[NSMenu alloc] initWithTitle:label] autorelease];
 | 
				
			||||||
    [item setSubmenu:submenu];
 | 
					    [item setSubmenu:submenu];
 | 
				
			||||||
    [NSApp setServicesMenu:submenu];
 | 
					    [NSApp setServicesMenu:submenu];
 | 
				
			||||||
 | 
					  } else if (role == base::ASCIIToUTF16("sharemenu")) {
 | 
				
			||||||
 | 
					    SharingItem sharing_item;
 | 
				
			||||||
 | 
					    model->GetSharingItemAt(index, &sharing_item);
 | 
				
			||||||
 | 
					    [item setTarget:nil];
 | 
				
			||||||
 | 
					    [item setAction:nil];
 | 
				
			||||||
 | 
					    [item setSubmenu:[self createShareMenuForItem:sharing_item]];
 | 
				
			||||||
  } else if (type == electron::ElectronMenuModel::TYPE_SUBMENU &&
 | 
					  } else if (type == electron::ElectronMenuModel::TYPE_SUBMENU &&
 | 
				
			||||||
             model->IsVisibleAt(index)) {
 | 
					             model->IsVisibleAt(index)) {
 | 
				
			||||||
    // We need to specifically check that the submenu top-level item has been
 | 
					    // We need to specifically check that the submenu top-level item has been
 | 
				
			||||||
| 
						 | 
					@ -372,6 +426,8 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
 | 
				
			||||||
// radio, etc) of each item in the menu.
 | 
					// radio, etc) of each item in the menu.
 | 
				
			||||||
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
 | 
					- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
 | 
				
			||||||
  SEL action = [item action];
 | 
					  SEL action = [item action];
 | 
				
			||||||
 | 
					  if (action == @selector(performShare:))
 | 
				
			||||||
 | 
					    return YES;
 | 
				
			||||||
  if (action != @selector(itemSelected:))
 | 
					  if (action != @selector(itemSelected:))
 | 
				
			||||||
    return NO;
 | 
					    return NO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -405,14 +461,30 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Performs the share action using the sharing service represented by |sender|.
 | 
				
			||||||
 | 
					- (void)performShare:(NSMenuItem*)sender {
 | 
				
			||||||
 | 
					  NSDictionary* object =
 | 
				
			||||||
 | 
					      base::mac::ObjCCastStrict<NSDictionary>([sender representedObject]);
 | 
				
			||||||
 | 
					  NSSharingService* service =
 | 
				
			||||||
 | 
					      base::mac::ObjCCastStrict<NSSharingService>(object[@"service"]);
 | 
				
			||||||
 | 
					  NSArray* items = base::mac::ObjCCastStrict<NSArray>(object[@"items"]);
 | 
				
			||||||
 | 
					  [service setDelegate:self];
 | 
				
			||||||
 | 
					  [service performWithItems:items];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (NSMenu*)menu {
 | 
					- (NSMenu*)menu {
 | 
				
			||||||
  if (menu_)
 | 
					  if (menu_)
 | 
				
			||||||
    return menu_.get();
 | 
					    return menu_.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  menu_.reset([[NSMenu alloc] initWithTitle:@""]);
 | 
					  if (model_ && model_->GetSharingItem()) {
 | 
				
			||||||
 | 
					    NSMenu* menu = [self createShareMenuForItem:*model_->GetSharingItem()];
 | 
				
			||||||
 | 
					    menu_.reset([menu retain]);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    menu_.reset([[NSMenu alloc] initWithTitle:@""]);
 | 
				
			||||||
 | 
					    if (model_)
 | 
				
			||||||
 | 
					      [self populateWithModel:model_.get()];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  [menu_ setDelegate:self];
 | 
					  [menu_ setDelegate:self];
 | 
				
			||||||
  if (model_)
 | 
					 | 
				
			||||||
    [self populateWithModel:model_.get()];
 | 
					 | 
				
			||||||
  return menu_.get();
 | 
					  return menu_.get();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -439,4 +511,18 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NSSharingServiceDelegate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (NSWindow*)sharingService:(NSSharingService*)service
 | 
				
			||||||
 | 
					    sourceWindowForShareItems:(NSArray*)items
 | 
				
			||||||
 | 
					          sharingContentScope:(NSSharingContentScope*)scope {
 | 
				
			||||||
 | 
					  // Return the current active window.
 | 
				
			||||||
 | 
					  const auto& list = electron::WindowList::GetWindows();
 | 
				
			||||||
 | 
					  for (electron::NativeWindow* window : list) {
 | 
				
			||||||
 | 
					    if (window->IsFocused())
 | 
				
			||||||
 | 
					      return window->GetNativeWindow().GetNativeNSWindow();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return nil;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@end
 | 
					@end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,18 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "shell/browser/ui/electron_menu_model.h"
 | 
					#include "shell/browser/ui/electron_menu_model.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "base/stl_util.h"
 | 
					#include "base/stl_util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace electron {
 | 
					namespace electron {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					ElectronMenuModel::SharingItem::SharingItem() = default;
 | 
				
			||||||
 | 
					ElectronMenuModel::SharingItem::SharingItem(SharingItem&&) = default;
 | 
				
			||||||
 | 
					ElectronMenuModel::SharingItem::~SharingItem() = default;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ElectronMenuModel::Delegate::GetAcceleratorForCommandId(
 | 
					bool ElectronMenuModel::Delegate::GetAcceleratorForCommandId(
 | 
				
			||||||
    int command_id,
 | 
					    int command_id,
 | 
				
			||||||
    ui::Accelerator* accelerator) const {
 | 
					    ui::Accelerator* accelerator) const {
 | 
				
			||||||
| 
						 | 
					@ -79,6 +87,23 @@ bool ElectronMenuModel::WorksWhenHiddenAt(int index) const {
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					bool ElectronMenuModel::GetSharingItemAt(int index, SharingItem* item) const {
 | 
				
			||||||
 | 
					  if (delegate_)
 | 
				
			||||||
 | 
					    return delegate_->GetSharingItemForCommandId(GetCommandIdAt(index), item);
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ElectronMenuModel::SetSharingItem(SharingItem item) {
 | 
				
			||||||
 | 
					  sharing_item_.emplace(std::move(item));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base::Optional<ElectronMenuModel::SharingItem>&
 | 
				
			||||||
 | 
					ElectronMenuModel::GetSharingItem() const {
 | 
				
			||||||
 | 
					  return sharing_item_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ElectronMenuModel::MenuWillClose() {
 | 
					void ElectronMenuModel::MenuWillClose() {
 | 
				
			||||||
  ui::SimpleMenuModel::MenuWillClose();
 | 
					  ui::SimpleMenuModel::MenuWillClose();
 | 
				
			||||||
  for (Observer& observer : observers_) {
 | 
					  for (Observer& observer : observers_) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,16 +6,34 @@
 | 
				
			||||||
#define SHELL_BROWSER_UI_ELECTRON_MENU_MODEL_H_
 | 
					#define SHELL_BROWSER_UI_ELECTRON_MENU_MODEL_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "base/files/file_path.h"
 | 
				
			||||||
#include "base/memory/weak_ptr.h"
 | 
					#include "base/memory/weak_ptr.h"
 | 
				
			||||||
#include "base/observer_list.h"
 | 
					#include "base/observer_list.h"
 | 
				
			||||||
#include "base/observer_list_types.h"
 | 
					#include "base/observer_list_types.h"
 | 
				
			||||||
 | 
					#include "base/optional.h"
 | 
				
			||||||
#include "ui/base/models/simple_menu_model.h"
 | 
					#include "ui/base/models/simple_menu_model.h"
 | 
				
			||||||
 | 
					#include "url/gurl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace electron {
 | 
					namespace electron {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ElectronMenuModel : public ui::SimpleMenuModel {
 | 
					class ElectronMenuModel : public ui::SimpleMenuModel {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					  struct SharingItem {
 | 
				
			||||||
 | 
					    SharingItem();
 | 
				
			||||||
 | 
					    SharingItem(SharingItem&&);
 | 
				
			||||||
 | 
					    SharingItem(const SharingItem&) = delete;
 | 
				
			||||||
 | 
					    ~SharingItem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    base::Optional<std::vector<std::string>> texts;
 | 
				
			||||||
 | 
					    base::Optional<std::vector<GURL>> urls;
 | 
				
			||||||
 | 
					    base::Optional<std::vector<base::FilePath>> file_paths;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class Delegate : public ui::SimpleMenuModel::Delegate {
 | 
					  class Delegate : public ui::SimpleMenuModel::Delegate {
 | 
				
			||||||
   public:
 | 
					   public:
 | 
				
			||||||
    ~Delegate() override {}
 | 
					    ~Delegate() override {}
 | 
				
			||||||
| 
						 | 
					@ -30,6 +48,11 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual bool ShouldCommandIdWorkWhenHidden(int command_id) const = 0;
 | 
					    virtual bool ShouldCommandIdWorkWhenHidden(int command_id) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					    virtual bool GetSharingItemForCommandId(int command_id,
 | 
				
			||||||
 | 
					                                            SharingItem* item) const = 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   private:
 | 
					   private:
 | 
				
			||||||
    // ui::SimpleMenuModel::Delegate:
 | 
					    // ui::SimpleMenuModel::Delegate:
 | 
				
			||||||
    bool GetAcceleratorForCommandId(
 | 
					    bool GetAcceleratorForCommandId(
 | 
				
			||||||
| 
						 | 
					@ -65,6 +88,13 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
 | 
				
			||||||
                                  ui::Accelerator* accelerator) const;
 | 
					                                  ui::Accelerator* accelerator) const;
 | 
				
			||||||
  bool ShouldRegisterAcceleratorAt(int index) const;
 | 
					  bool ShouldRegisterAcceleratorAt(int index) const;
 | 
				
			||||||
  bool WorksWhenHiddenAt(int index) const;
 | 
					  bool WorksWhenHiddenAt(int index) const;
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					  // Return the SharingItem of menu item.
 | 
				
			||||||
 | 
					  bool GetSharingItemAt(int index, SharingItem* item) const;
 | 
				
			||||||
 | 
					  // Set/Get the SharingItem of this menu.
 | 
				
			||||||
 | 
					  void SetSharingItem(SharingItem item);
 | 
				
			||||||
 | 
					  const base::Optional<SharingItem>& GetSharingItem() const;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // ui::SimpleMenuModel:
 | 
					  // ui::SimpleMenuModel:
 | 
				
			||||||
  void MenuWillClose() override;
 | 
					  void MenuWillClose() override;
 | 
				
			||||||
| 
						 | 
					@ -80,6 +110,10 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  Delegate* delegate_;  // weak ref.
 | 
					  Delegate* delegate_;  // weak ref.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(OS_MAC)
 | 
				
			||||||
 | 
					  base::Optional<SharingItem> sharing_item_;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::map<int, base::string16> toolTips_;   // command id -> tooltip
 | 
					  std::map<int, base::string16> toolTips_;   // command id -> tooltip
 | 
				
			||||||
  std::map<int, base::string16> roles_;      // command id -> role
 | 
					  std::map<int, base::string16> roles_;      // command id -> role
 | 
				
			||||||
  std::map<int, base::string16> sublabels_;  // command id -> sublabel
 | 
					  std::map<int, base::string16> sublabels_;  // command id -> sublabel
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,9 @@
 | 
				
			||||||
#define SHELL_COMMON_GIN_HELPER_DICTIONARY_H_
 | 
					#define SHELL_COMMON_GIN_HELPER_DICTIONARY_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "base/optional.h"
 | 
				
			||||||
#include "gin/dictionary.h"
 | 
					#include "gin/dictionary.h"
 | 
				
			||||||
#include "shell/common/gin_converters/std_converter.h"
 | 
					#include "shell/common/gin_converters/std_converter.h"
 | 
				
			||||||
#include "shell/common/gin_helper/function_template.h"
 | 
					#include "shell/common/gin_helper/function_template.h"
 | 
				
			||||||
| 
						 | 
					@ -59,6 +61,18 @@ class Dictionary : public gin::Dictionary {
 | 
				
			||||||
    return !result.IsNothing() && result.FromJust();
 | 
					    return !result.IsNothing() && result.FromJust();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Like normal Get but put result in an base::Optional.
 | 
				
			||||||
 | 
					  template <typename T>
 | 
				
			||||||
 | 
					  bool GetOptional(base::StringPiece key, base::Optional<T>* out) const {
 | 
				
			||||||
 | 
					    T ret;
 | 
				
			||||||
 | 
					    if (Get(key, &ret)) {
 | 
				
			||||||
 | 
					      out->emplace(std::move(ret));
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename T>
 | 
					  template <typename T>
 | 
				
			||||||
  bool GetHidden(base::StringPiece key, T* out) const {
 | 
					  bool GetHidden(base::StringPiece key, T* out) const {
 | 
				
			||||||
    v8::Local<v8::Context> context = isolate()->GetCurrentContext();
 | 
					    v8::Local<v8::Context> context = isolate()->GetCurrentContext();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								typings/internal-electron.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								typings/internal-electron.d.ts
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -108,6 +108,7 @@ declare namespace Electron {
 | 
				
			||||||
    _isCommandIdVisible(id: string): boolean;
 | 
					    _isCommandIdVisible(id: string): boolean;
 | 
				
			||||||
    _getAcceleratorForCommandId(id: string, useDefaultAccelerator: boolean): Accelerator | undefined;
 | 
					    _getAcceleratorForCommandId(id: string, useDefaultAccelerator: boolean): Accelerator | undefined;
 | 
				
			||||||
    _shouldRegisterAcceleratorForCommandId(id: string): boolean;
 | 
					    _shouldRegisterAcceleratorForCommandId(id: string): boolean;
 | 
				
			||||||
 | 
					    _getSharingItemForCommandId(id: string): SharingItem | null;
 | 
				
			||||||
    _callMenuWillShow(): void;
 | 
					    _callMenuWillShow(): void;
 | 
				
			||||||
    _executeCommand(event: any, id: number): void;
 | 
					    _executeCommand(event: any, id: number): void;
 | 
				
			||||||
    _menuWillShow(): void;
 | 
					    _menuWillShow(): void;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue