1 /******************************************************************************* 2 * Copyright (c) 2010, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.e4.ui.internal.workbench.swt; 15 16 import org.eclipse.core.runtime.ISafeRunnable; 17 import org.eclipse.core.runtime.SafeRunner; 18 import org.eclipse.e4.core.contexts.IEclipseContext; 19 import org.eclipse.e4.ui.bindings.EBindingService; 20 import org.eclipse.e4.ui.internal.workbench.E4Workbench; 21 import org.eclipse.e4.ui.internal.workbench.Policy; 22 import org.eclipse.e4.ui.model.application.MApplication; 23 import org.eclipse.e4.ui.model.application.ui.basic.MWindow; 24 import org.eclipse.e4.ui.services.EContextService; 25 import org.eclipse.swt.SWT; 26 import org.eclipse.swt.widgets.Event; 27 import org.eclipse.swt.widgets.Listener; 28 import org.eclipse.swt.widgets.Shell; 29 30 /** 31 * An SWT listener for listening for activation events of shells that aren't 32 * associated with an MWindow. 33 */ 34 public class ShellActivationListener implements Listener { 35 36 /** 37 * A string key for use with a shell's keyed data to determine whether 38 * activation events of that shell should be ignored by this listener. The 39 * retrieved data of this string key must either be <code>null</code> or be 40 * of type <code>Boolean</code>. 41 */ 42 public static final String DIALOG_IGNORE_KEY = "org.eclipse.e4.ui.ignoreDialog"; //$NON-NLS-1$ 43 44 /** 45 * A string key for use with a shell's keyed data to retrieve the top level 46 * eclipse context that the shell is supposed to represent. 47 */ 48 private static final String ECLIPSE_CONTEXT_SHELL_CONTEXT = "org.eclipse.e4.ui.shellContext"; //$NON-NLS-1$ 49 50 private MApplication application; 51 ShellActivationListener(MApplication application)52 ShellActivationListener(MApplication application) { 53 this.application = application; 54 } 55 56 @Override handleEvent(Event event)57 public void handleEvent(Event event) { 58 if (!(event.widget instanceof Shell)) { 59 return; 60 } 61 62 Shell shell = (Shell) event.widget; 63 Object obj = shell.getData(AbstractPartRenderer.OWNING_ME); 64 if (obj instanceof MWindow) { 65 processWindow(event, shell, (MWindow) obj); 66 return; 67 } 68 69 obj = shell.getData(DIALOG_IGNORE_KEY); 70 if (obj instanceof Boolean && ((Boolean) obj).booleanValue()) { 71 return; 72 } 73 74 switch (event.type) { 75 case SWT.Activate: 76 activate(shell); 77 break; 78 case SWT.Deactivate: 79 deactivate(shell); 80 break; 81 } 82 } 83 processWindow(Event event, Shell shell, MWindow window)84 private void processWindow(Event event, Shell shell, MWindow window) { 85 switch (event.type) { 86 case SWT.Activate: 87 final IEclipseContext local = window.getContext(); 88 if (Policy.DEBUG_WORKBENCH) { 89 WorkbenchSWTActivator.trace(Policy.DEBUG_WORKBENCH_FLAG, 90 "setting mwindow context " + local, null); 91 } 92 // record this shell's context 93 shell.setData(ECLIPSE_CONTEXT_SHELL_CONTEXT, local); 94 95 SafeRunner.run(new ISafeRunnable() { 96 @Override 97 public void run() throws Exception { 98 // reconstruct the active chain for this mwindow 99 local.activateBranch(); 100 } 101 102 @Override 103 public void handleException(Throwable exception) { 104 WorkbenchSWTActivator.trace("/trace/workbench", 105 "failed correcting context chain", exception); 106 } 107 }); 108 break; 109 case SWT.Deactivate: 110 Object context = window.getContext(); 111 if(Policy.DEBUG_WORKBENCH) { 112 WorkbenchSWTActivator.trace(Policy.DEBUG_WORKBENCH_FLAG, 113 "setting mwindow context " + context, null); 114 } 115 // record this shell's context 116 shell.setData(ECLIPSE_CONTEXT_SHELL_CONTEXT, context); 117 break; 118 } 119 } 120 activate(Shell shell)121 private void activate(Shell shell) { 122 final IEclipseContext parentContext = application.getContext(); 123 final IEclipseContext shellContext = getShellContext(shell, 124 parentContext); 125 126 SafeRunner.run(new ISafeRunnable() { 127 @Override 128 public void run() throws Exception { 129 // activate this shell 130 shellContext.activate(); 131 } 132 133 @Override 134 public void handleException(Throwable exception) { 135 WorkbenchSWTActivator.trace("/trace/workbench", 136 "failed setting dialog child", exception); 137 } 138 }); 139 140 } 141 deactivate(Shell shell)142 private void deactivate(Shell shell) { 143 // bug 412001. Cannot assume anything about a non-modelled Shell's 144 // deactivation. It could be: 145 // * some other application got activated 146 // * some dialog we cannot see (IE's Find dialog in 412001) get's 147 // activated 148 // * another unmodelled shell is about to be activated 149 // * a modelled shell is about to be activated. 150 // No matter what, the time to do things is on activation 151 152 } 153 154 /** 155 * Retrieves the eclipse context for the specified shell. If one cannot be 156 * found, a child context will be created off of the provided parent 157 * context. 158 * 159 * @param shell 160 * the shell of interest, must not be <code>null</code> 161 * @param parentContext 162 * the parent context that the shell's context should be created 163 * off of if it doesn't have one, must not be <code>null</code> 164 * @return the shell's eclipse context 165 */ getShellContext(final Shell shell, IEclipseContext parentContext)166 private IEclipseContext getShellContext(final Shell shell, 167 IEclipseContext parentContext) { 168 IEclipseContext shellContext = (IEclipseContext) shell 169 .getData(ECLIPSE_CONTEXT_SHELL_CONTEXT); 170 if (shellContext != null) { 171 return shellContext; 172 } 173 final IEclipseContext context = parentContext 174 .createChild(EBindingService.DIALOG_CONTEXT_ID); 175 176 context.set(E4Workbench.LOCAL_ACTIVE_SHELL, shell); 177 178 // set the context into the widget for future retrieval 179 shell.setData(ECLIPSE_CONTEXT_SHELL_CONTEXT, context); 180 181 EContextService contextService = context.get(EContextService.class); 182 contextService.activateContext(EBindingService.DIALOG_CONTEXT_ID); 183 184 shell.addDisposeListener(e -> { 185 deactivate(shell); 186 context.dispose(); 187 }); 188 189 return context; 190 } 191 } 192