Commit fixes for bugs 345494 and 338221
Bug 345494 - Add support for missing MacOS UI commands from org.eclipse.ui.ide
Bug 338221 - Exit does not prompt
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/fragment-cocoa.properties b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/fragment-cocoa.properties
index 3349f7c..eb71764 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/fragment-cocoa.properties
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/fragment-cocoa.properties
@@ -14,4 +14,13 @@
 fragmentName=Eclipse UI MacOS X Enhancements
 
 command.closeDialog.name=Close Dialog
-command.closeDialog.desc=Closes the active Dialog
\ No newline at end of file
+command.closeDialog.desc=Closes the active Dialog
+
+command.minimize.name=Minimize
+command.minimize.desc=Minimizes the current window to the Dock
+
+command.zoom.name=Zoom
+command.zoom.desc=Toggles the window between standard state and user state 
+
+command.arrangeWindows.name=Bring All to Front
+command.arrangeWindows.desc=Arranges the application windows in front of all windows 
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/AbstractWindowHandler.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/AbstractWindowHandler.java
new file mode 100644
index 0000000..9fd6e0b
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/AbstractWindowHandler.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Brian de Alwis - port to Eclipse 4
+ ******************************************************************************/
+
+package org.eclipse.e4.ui.workbench.renderers.swt.cocoa;
+
+import javax.inject.Named;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.swt.internal.cocoa.NSWindow;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 4.1
+ */
+public abstract class AbstractWindowHandler {
+	@CanExecute
+	public boolean canExecute(
+			@Optional @Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
+		if (shell == null) {
+			return false;
+		}
+		NSWindow window = shell.view.window();
+		if (window == null) {
+			return false;
+		}
+		return !window.isMiniaturized();
+	}
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/ArrangeWindowHandler.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/ArrangeWindowHandler.java
new file mode 100644
index 0000000..288ac20
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/ArrangeWindowHandler.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Brian de Alwis - port to Eclipse 4
+ ******************************************************************************/
+
+package org.eclipse.e4.ui.workbench.renderers.swt.cocoa;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.swt.internal.cocoa.NSApplication;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 4.1
+ */
+public class ArrangeWindowHandler extends AbstractWindowHandler {
+	@CanExecute
+	public boolean canExecute(@Optional Display display) {
+		if (display == null) {
+			return false;
+		}
+
+		boolean isEnabled = false;
+		Shell[] shells = Display.getDefault().getShells();
+
+		// not all windows should be in minimized state
+		for (int i = 0; i < shells.length; i++) {
+			if (shells[i].view.window().isKeyWindow()) {
+				isEnabled = true;
+				break;
+			}
+		}
+		return isEnabled;
+	}
+
+	@Execute
+	public void execute() {
+		NSApplication app = NSApplication.sharedApplication();
+		app.arrangeInFront(app);
+	}
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIHandler.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIHandler.java
index 600a972..1e5896c 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIHandler.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIHandler.java
@@ -89,11 +89,6 @@
  * @since 1.0
  */
 public class CocoaUIHandler {
-	protected static final String FRAGMENT_ID = "org.eclipse.e4.ui.workbench.renderers.swt.cocoa"; //$NON-NLS-1$
-	protected static final String HOST_ID = "org.eclipse.e4.ui.workbench.renderers.swt"; //$NON-NLS-1$
-	protected static final String CLASS_URI = "platform:/plugin/" //$NON-NLS-1$  
-			+ HOST_ID + "/" + CocoaUIHandler.class.getName(); //$NON-NLS-1$
-
 	// these constants are defined in IWorkbenchCommandConstants
 	// but reproduced here to support pure-e4 apps
 	private static final String COMMAND_ID_ABOUT = "org.eclipse.ui.help.aboutAction"; //$NON-NLS-1$
@@ -344,7 +339,9 @@
 		}
 		closeDialogCommand = CommandsFactoryImpl.eINSTANCE.createCommand();
 		closeDialogCommand.setElementId(COMMAND_ID_CLOSE_DIALOG);
-		closeDialogCommand.setCommandName(COMMAND_ID_CLOSE_DIALOG);
+		closeDialogCommand.setCommandName("%command.closeDialog.name"); //$NON-NLS-1$
+		closeDialogCommand.setDescription("%command.closeDialog.desc"); //$NON-NLS-1$
+		closeDialogCommand.setContributorURI(CocoaUIProcessor.FRAGMENT_ID);
 		app.getCommands().add(closeDialogCommand);
 	}
 
@@ -355,8 +352,8 @@
 		}
 		handler = CommandsFactoryImpl.eINSTANCE.createHandler();
 		handler.setCommand(closeDialogCommand);
-		handler.setContributionURI("platform:/plugin/" + HOST_ID + "/" //$NON-NLS-1$ //$NON-NLS-2$
-				+ CloseDialogHandler.class.getName());
+		handler.setContributionURI(CocoaUIProcessor.HOST_URI
+				+ "/" + CloseDialogHandler.class.getName());//$NON-NLS-1$
 		app.getHandlers().add(handler);
 	}
 
@@ -375,7 +372,8 @@
 		// StatusUtil.handleStatus(e, StatusManager.LOG);
 		statusReporter
 				.get()
-				.report(new Status(IStatus.WARNING, FRAGMENT_ID,
+				.report(new Status(IStatus.WARNING,
+						CocoaUIProcessor.FRAGMENT_ID,
 						"Exception occurred during CocoaUI processing", e), StatusReporter.LOG); //$NON-NLS-1$
 	}
 
@@ -589,8 +587,8 @@
 			if (item != null) {
 				item.addSelectionListener(new SelectionAdapter() {
 					public void widgetSelected(SelectionEvent e) {
-						if (!runCommand(commandId)) {
-							runAction(commandId);
+						if (runCommand(commandId) || runAction(commandId)) {
+							e.doit = false;
 						}
 					}
 				});
@@ -650,55 +648,61 @@
 	/**
 	 * Locate an action (a menu item, actually) with the given id in the current
 	 * menu bar and run it.
+	 * 
+	 * @param actionId
+	 *            the action to find
+	 * @return true if an action was found, false otherwise
 	 */
-	private void runAction(String actionId) {
+	private boolean runAction(String actionId) {
 		MWindow window = app.getSelectedElement();
-		if (window != null) {
-			MMenu topMenu = window.getMainMenu();
-			MMenuItem item = findAction(actionId, topMenu);
-			if (item != null && item.isEnabled()) {
-				try {
-					// disable the about and prefs items -- they shouldn't be
-					// able to be run when another item is being triggered
-					final Display display = Display.getDefault();
-					Menu appMenuBar = display.getMenuBar();
-					if (appMenuBar == null) {
-						return;
-					}
-					MenuItem aboutItem = findMenuItemById(appMenuBar,
-							SWT.ID_ABOUT);
-					boolean aboutEnabled = true;
-					if (aboutItem != null) {
-						aboutEnabled = aboutItem.getEnabled();
-						aboutItem.setEnabled(false);
-					}
-					MenuItem prefsItem = findMenuItemById(appMenuBar,
-							SWT.ID_PREFERENCES);
-					boolean prefsEnabled = true;
-					if (prefsItem != null) {
-						prefsEnabled = prefsItem.getEnabled();
-						prefsItem.setEnabled(false);
-					}
+		if (window == null) {
+			return false;
+		}
+		MMenu topMenu = window.getMainMenu();
+		MMenuItem item = findAction(actionId, topMenu);
+		if (item == null || !item.isEnabled()) {
+			return false;
+		}
+		try {
+			// disable the about and prefs items -- they shouldn't be
+			// able to be run when another item is being triggered
+			final Display display = Display.getDefault();
+			MenuItem aboutItem = null;
+			boolean aboutEnabled = true;
+			MenuItem prefsItem = null;
+			boolean prefsEnabled = true;
 
-					try {
-						simulateMenuSelection(item);
-					} finally {
-						if (prefsItem != null) {
-							prefsItem.setEnabled(prefsEnabled);
-						}
-						if (aboutItem != null) {
-							aboutItem.setEnabled(aboutEnabled);
-						}
-					}
-				} catch (Exception e) {
-					// theoretically, one of
-					// SecurityException,Illegal*Exception,InvocationTargetException,NoSuch*Exception
-					// not expected to happen at all.
-					log(e);
+			Menu appMenuBar = display.getMenuBar();
+			if (appMenuBar != null) {
+				aboutItem = findMenuItemById(appMenuBar, SWT.ID_ABOUT);
+				if (aboutItem != null) {
+					aboutEnabled = aboutItem.getEnabled();
+					aboutItem.setEnabled(false);
+				}
+				prefsItem = findMenuItemById(appMenuBar, SWT.ID_PREFERENCES);
+				if (prefsItem != null) {
+					prefsEnabled = prefsItem.getEnabled();
+					prefsItem.setEnabled(false);
 				}
 			}
+			try {
+				simulateMenuSelection(item);
+			} finally {
+				if (prefsItem != null) {
+					prefsItem.setEnabled(prefsEnabled);
+				}
+				if (aboutItem != null) {
+					aboutItem.setEnabled(aboutEnabled);
+				}
+			}
+		} catch (Exception e) {
+			// theoretically, one of
+			// SecurityException,Illegal*Exception,InvocationTargetException,NoSuch*Exception
+			// not expected to happen at all.
+			log(e);
+			// return false?
 		}
-
+		return true;
 	}
 
 	private void simulateMenuSelection(MMenuItem item) {
@@ -733,7 +737,7 @@
 					.get()
 					.report(new Status(
 							IStatus.WARNING,
-							FRAGMENT_ID,
+							CocoaUIProcessor.FRAGMENT_ID,
 							"Unhandled menu type: " + item.getClass() + ": " + item), //$NON-NLS-1$ //$NON-NLS-2$ $NON-NLS-2$
 					StatusReporter.LOG);
 		}
@@ -753,15 +757,19 @@
 	 * @return true if the command was found, false otherwise
 	 */
 	private boolean runCommand(String commandId) {
-		if (handlerService != null) {
-			ParameterizedCommand cmd = commandService.createCommand(commandId,
-					Collections.emptyMap());
-			if (cmd != null) {
-				handlerService.executeHandler(cmd);
-				return true;
-			}
+		if (commandService == null || handlerService == null) {
+			return false;
 		}
-		return false;
+		ParameterizedCommand cmd = commandService.createCommand(commandId,
+				Collections.emptyMap());
+		if (cmd == null) {
+			return false;
+		}
+		// Unfortunately there's no way to check if a handler was available...
+		// EHandlerService#executeHandler() returns null if a handler cannot be
+		// found, but the handler itself could also return null too.
+		handlerService.executeHandler(cmd);
+		return true;
 	}
 
 	/**
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIProcessor.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIProcessor.java
index c03e96a..a141cde 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIProcessor.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/CocoaUIProcessor.java
@@ -15,22 +15,58 @@
 import org.eclipse.e4.ui.model.application.MAddon;
 import org.eclipse.e4.ui.model.application.MApplication;
 import org.eclipse.e4.ui.model.application.MApplicationFactory;
+import org.eclipse.e4.ui.model.application.commands.MCategory;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MCommandsFactory;
+import org.eclipse.e4.ui.model.application.commands.MHandler;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
 
 /**
- * A hack to create an IStartup-like equivalent using ModelProcessor. The actual
- * handling is done by {@link CocoaUIHandler}. But as the context provided to a
- * {@code ModelProcessor} is destroyed after the processor has executed, we
- * create a new context.
+ * A hack to create an IStartup-like equivalent using ModelProcessor. But as the
+ * context provided to a {@code ModelProcessor} is destroyed after this
+ * processor has executed (thus disconnecting any event listeners, etc.), we
+ * create a new context and defer processing to the actual handling is done by
+ * {@link CocoaUIHandler}.
  */
 public class CocoaUIProcessor {
+	/**
+	 * The schema identifier used for Eclipse platform references
+	 */
+	final private static String PLATFORM_SCHEMA = "platform"; //$NON-NLS-1$
+	final private static String PLUGIN_SEGMENT = "/plugin/"; //$NON-NLS-1$
+	final private static String FRAGMENT_SEGMENT = "/fragment/"; //$NON-NLS-1$
+
+	/**
+	 * Useful constants for referencing classes defined within this
+	 * host/fragment
+	 */
+	protected static final String FRAGMENT_ID = "org.eclipse.e4.ui.workbench.renderers.swt.cocoa"; //$NON-NLS-1$
+	protected static final String FRAGMENT_URI = PLATFORM_SCHEMA
+			+ ":" + FRAGMENT_SEGMENT + FRAGMENT_ID; //$NON-NLS-1$  
+	protected static final String HOST_ID = "org.eclipse.e4.ui.workbench.renderers.swt"; //$NON-NLS-1$
+	protected static final String HOST_URI = PLATFORM_SCHEMA
+			+ ":" + PLUGIN_SEGMENT + HOST_ID; //$NON-NLS-1$  
+
 	@Inject
 	protected MApplication app;
 
 	/**
-	 * Install the addon.
+	 * Execute!
 	 */
 	@Execute
 	public void execute() {
+		installAddon();
+
+		// these handlers are installed directly on the app and are thus
+		// independent of the context.
+		installHandlers();
+	}
+
+	/**
+	 * Install the addon.
+	 */
+	public void installAddon() {
 		String addonId = CocoaUIHandler.class.getName();
 		for (MAddon addon : app.getAddons()) {
 			if (addonId.equals(addon.getElementId())) {
@@ -39,9 +75,133 @@
 		}
 
 		MAddon addon = MApplicationFactory.INSTANCE.createAddon();
-		addon.setContributionURI(CocoaUIHandler.CLASS_URI);
+		addon.setContributionURI(getClassURI(CocoaUIHandler.class));
 		addon.setElementId(addonId);
 		app.getAddons().add(addon);
 	}
 
+	/**
+	 * Install the Cocoa window handlers. Sadly this has to be done here rather
+	 * than in a <tt>fragments.e4xmi</tt> as the project
+	 * <tt>Application.e4xmi</tt> may (and likely will) use different IDs.
+	 */
+	public void installHandlers() {
+		installHandler(
+				defineCommand(
+						"org.eclipse.ui.category.window", "org.eclipse.ui.cocoa.arrangeWindowsInFront", //$NON-NLS-1$ //$NON-NLS-2$
+						"%command.arrangeWindows.name", //$NON-NLS-1$
+						"%command.arrangeWindows.desc", FRAGMENT_URI), //$NON-NLS-1$
+				ArrangeWindowHandler.class, FRAGMENT_URI);
+		installHandler(
+				defineCommand(
+						"org.eclipse.ui.category.window", "org.eclipse.ui.cocoa.minimizeWindow", //$NON-NLS-1$ //$NON-NLS-2$
+						"%command.minimize.name", "%command.minimize.desc", FRAGMENT_URI), //$NON-NLS-1$ //$NON-NLS-2$
+				MinimizeWindowHandler.class, FRAGMENT_URI);
+		installHandler(
+				defineCommand(
+						"org.eclipse.ui.category.window", "org.eclipse.ui.cocoa.zoomWindow", //$NON-NLS-1$ //$NON-NLS-2$
+						"%command.zoom.name", "%command.zoom.desc", FRAGMENT_URI), //$NON-NLS-1$//$NON-NLS-2$
+				ZoomWindowHandler.class, FRAGMENT_URI);
+	}
+
+	/**
+	 * Configure and install a command handler for the provided command and
+	 * handler
+	 * 
+	 * @param handlerClass
+	 * @param command
+	 */
+	private void installHandler(MCommand command, Class<?> handlerClass,
+			String contributorURI) {
+		for (MHandler handler : app.getHandlers()) {
+			if (handlerClass.getName().equals(handler.getElementId())
+					&& handler.getCommand() == command) {
+				return;
+			}
+		}
+
+		MHandler handler = MCommandsFactory.INSTANCE.createHandler();
+		handler.setContributionURI(getClassURI(handlerClass));
+		handler.setContributorURI(contributorURI);
+		handler.setElementId(handlerClass.getName());
+		handler.setCommand(command);
+		app.getHandlers().add(handler);
+	}
+
+	/**
+	 * Find the corresponding command and define if not found.
+	 * 
+	 * @param commandId
+	 * @param name
+	 * @param description
+	 * @return the command
+	 */
+	private MCommand defineCommand(String categoryId, String commandId,
+			String name, String description, String contributorURI) {
+		for (MCommand command : app.getCommands()) {
+			if (commandId.equals(command.getElementId())) {
+				return command;
+			}
+		}
+		MCommand command = MCommandsFactory.INSTANCE.createCommand();
+		command.setCategory(defineCategory(categoryId));
+		command.setElementId(commandId);
+		command.setCommandName(name);
+		command.setDescription(description);
+		command.setContributorURI(contributorURI);
+		app.getCommands().add(command);
+		return command;
+	}
+
+	/**
+	 * Find the corresponding category and define if not found.
+	 * 
+	 * @param categoryId
+	 * @return the category
+	 */
+	private MCategory defineCategory(String categoryId) {
+		for (MCategory category : app.getCategories()) {
+			if (categoryId.equals(category.getElementId())) {
+				return category;
+			}
+		}
+		MCategory category = MCommandsFactory.INSTANCE.createCategory();
+		category.setElementId(categoryId);
+		category.setName(categoryId);
+		app.getCategories().add(category);
+		return category;
+	}
+
+	/**
+	 * Return a platform-style URI to reference the provided class
+	 * 
+	 * @param clazz
+	 *            a class
+	 * @return a URI referencing the class
+	 * @throws IllegalArgumentException
+	 *             if the class was not defined from a bundle
+	 */
+	private String getClassURI(Class<?> clazz) {
+		return getBundleURI(clazz) + "/" + clazz.getName(); //$NON-NLS-1$
+	}
+
+	/**
+	 * Return a platform-style URI to reference the bundle providing
+	 * {@code clazz}
+	 * 
+	 * @param clazz
+	 *            a class
+	 * @return a URI referencing the bundle
+	 * @throws IllegalArgumentException
+	 *             if the class was not defined from a bundle
+	 */
+	private String getBundleURI(Class<?> clazz) {
+		Bundle bundle = FrameworkUtil.getBundle(clazz);
+		if (bundle == null) {
+			throw new IllegalArgumentException(clazz.getName());
+		}
+		return PLATFORM_SCHEMA
+				+ ":" + PLUGIN_SEGMENT + bundle.getSymbolicName(); //$NON-NLS-1$
+	}
+
 }
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/MinimizeWindowHandler.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/MinimizeWindowHandler.java
new file mode 100644
index 0000000..7ad664a
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/MinimizeWindowHandler.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Brian de Alwis - port to Eclipse 4
+ ******************************************************************************/
+
+package org.eclipse.e4.ui.workbench.renderers.swt.cocoa;
+
+import javax.inject.Named;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.swt.internal.cocoa.NSWindow;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 4.1
+ */
+public class MinimizeWindowHandler extends AbstractWindowHandler {
+	@Execute
+	public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
+		if (shell == null) {
+			return;
+		}
+		NSWindow window = shell.view.window();
+		if (window == null) {
+			return;
+		}
+		window.miniaturize(window);
+	}
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/ZoomWindowHandler.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/ZoomWindowHandler.java
new file mode 100644
index 0000000..0851042
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt.cocoa/src/org/eclipse/e4/ui/workbench/renderers/swt/cocoa/ZoomWindowHandler.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Brian de Alwis - port to Eclipse 4
+ ******************************************************************************/
+
+package org.eclipse.e4.ui.workbench.renderers.swt.cocoa;
+
+import javax.inject.Named;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.swt.internal.cocoa.NSWindow;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 4.1
+ */
+public class ZoomWindowHandler extends AbstractWindowHandler {
+	@Execute
+	public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
+		if (shell == null) {
+			return;
+		}
+		NSWindow window = shell.view.window();
+		if (window == null) {
+			return;
+		}
+		window.zoom(window);
+	}
+
+}