From d096aecf6660502d9397e7a4e7a56c2ed064b403 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Fri, 4 Oct 2013 16:31:09 +0400 Subject: [PATCH] Better topmost window evaluation, ModalityHelper is extracted in a separate class. Some warnings have been eliminated. --- .../openapi/wm/impl/ModalityHelper.java | 86 +++++++++++++++++++ .../com/intellij/ui/mac/MacMessagesImpl.java | 79 ++++++----------- 2 files changed, 114 insertions(+), 51 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/wm/impl/ModalityHelper.java diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ModalityHelper.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ModalityHelper.java new file mode 100644 index 000000000000..fb37f84ec753 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ModalityHelper.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.wm.impl; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.wm.IdeFrame; + +import javax.swing.*; +import java.awt.*; +import java.lang.reflect.Method; + +/** + * @author Denis Fokin + */ +public class ModalityHelper { + + private static final Logger LOG = Logger.getInstance(ModalityHelper.class); + + private static Method isModalBlockedMethod = null; + private static Method getModalBlockerMethod = null; + + static { + Class [] noParams = new Class [] {}; + + try { + isModalBlockedMethod = Window.class.getDeclaredMethod("isModalBlocked", noParams); + getModalBlockerMethod = Window.class.getDeclaredMethod("getModalBlocker", noParams); + isModalBlockedMethod.setAccessible(true); + getModalBlockerMethod.setAccessible(true); + } + catch (NoSuchMethodException e) { + LOG.error(e); + } + + } + + public static boolean isModalBlocked (final Window window) { + boolean result = false; + try { + result = (Boolean)isModalBlockedMethod.invoke(window); + } + catch (Exception e) { + LOG.error(e); + } + return result; + } + + public static JDialog getModalBlockerFor (final Window window) { + JDialog result = null; + try { + result = (JDialog)getModalBlockerMethod.invoke(window); + } + catch (Exception e) { + LOG.error(e); + } + return result; + } + + public static JDialog getBlockerForFrame(final IdeFrame ideFrame) { + if (ideFrame == null) return null; + Component c = ideFrame.getComponent(); + if (c == null) return null; + Window window = SwingUtilities.getWindowAncestor(c); + if (window == null) return null; + if (!isModalBlocked(window)) return null; + return getModalBlockerFor(window); + } + + public static JDialog getBlockerForFocusedFrame() { + return getBlockerForFrame(IdeFocusManagerImpl.getGlobalInstance().getLastFocusedFrame()); + } + +} diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java index b0ad72c12d44..01fd7dfbcd4f 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java @@ -22,7 +22,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.WindowManager; -import com.intellij.ui.mac.foundation.Foundation; +import com.intellij.openapi.wm.impl.ModalityHelper; import com.intellij.ui.mac.foundation.ID; import com.intellij.ui.mac.foundation.MacUtil; import com.intellij.util.ui.UIUtil; @@ -34,7 +34,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; @@ -67,7 +66,7 @@ public class MacMessagesImpl extends MacMessages { processResult(documentRoot); ID suppressState = invoke(invoke(alert, "suppressionButton"), "state"); resultsFromDocumentRoot.put(documentRoot, new MessageResult(returnCode.intValue(), - suppressState.intValue() == 1 ? true : false)); + suppressState.intValue() == 1)); queuesFromDocumentRoot.get(windowFromId.get(contextInfo.longValue())).runFromQueue(); } cfRelease(self); @@ -198,34 +197,20 @@ public class MacMessagesImpl extends MacMessages { private MacMessagesImpl() {} - private static Method isModalBlockedMethod = null; - private static Method getModalBlockerMethod = null; - static { if (SystemInfo.isMac) { - final ID delegateClass = Foundation.allocateObjcClassPair(Foundation.getObjcClass("NSObject"), "NSAlertDelegate_"); - if (!Foundation.addMethod(delegateClass, Foundation.createSelector("alertDidEnd:returnCode:contextInfo:"), SHEET_DID_END, "v*")) { + final ID delegateClass = allocateObjcClassPair(getObjcClass("NSObject"), "NSAlertDelegate_"); + if (!addMethod(delegateClass, createSelector("alertDidEnd:returnCode:contextInfo:"), SHEET_DID_END, "v*")) { throw new RuntimeException("Unable to add method to objective-c delegate class!"); } - if (!Foundation.addMethod(delegateClass, Foundation.createSelector("showSheet:"), SIMPLE_SHEET_PANEL, "v*")) { + if (!addMethod(delegateClass, createSelector("showSheet:"), SIMPLE_SHEET_PANEL, "v*")) { throw new RuntimeException("Unable to add method to objective-c delegate class!"); } - if (!Foundation.addMethod(delegateClass, Foundation.createSelector("showVariableButtonsSheet:"), VARIABLE_BUTTONS_SHEET_PANEL, "v*")) { + if (!addMethod(delegateClass, createSelector("showVariableButtonsSheet:"), VARIABLE_BUTTONS_SHEET_PANEL, "v*")) { throw new RuntimeException("Unable to add method to objective-c delegate class!"); } - Foundation.registerObjcClassPair(delegateClass); + registerObjcClassPair(delegateClass); } - - Class [] noParams = new Class [] {}; - - try { - isModalBlockedMethod = Window.class.getDeclaredMethod("isModalBlocked", noParams); - getModalBlockerMethod = Window.class.getDeclaredMethod("getModalBlocker", noParams); - } - catch (NoSuchMethodException e) { - LOG.error(e); - } - } @Override @@ -266,9 +251,6 @@ public class MacMessagesImpl extends MacMessages { return showAlertDialog(title, defaultButton, alternateButton, otherButton, message, window, false, doNotAskOption); } - - - final private static Object lock = new Object(); final private static HashMap blockedDocumentRoots = new HashMap(); @@ -669,24 +651,19 @@ public class MacMessagesImpl extends MacMessages { } } - @NotNull private static Window getForemostWindow(final Window window) { Window _window = null; + IdeFocusManager ideFocusManager = IdeFocusManager.getGlobalInstance(); Component focusOwner = IdeFocusManager.findInstance().getFocusOwner(); + // Let's ask for a focused component first if (focusOwner != null) { _window = SwingUtilities.getWindowAncestor(focusOwner); } - if (_window == null && window != null) { - focusOwner = window.getMostRecentFocusOwner(); - if (focusOwner != null) { - _window = SwingUtilities.getWindowAncestor(focusOwner); - } - } - if (_window == null) { - focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + // Looks like ide lost focus, let's ask about the last focused component + focusOwner = ideFocusManager.getLastFocusedFor(ideFocusManager.getLastFocusedFrame()); if (focusOwner != null) { _window = SwingUtilities.getWindowAncestor(focusOwner); } @@ -696,26 +673,26 @@ public class MacMessagesImpl extends MacMessages { _window = WindowManager.getInstance().findVisibleFrame(); } - if (_window != null) { - synchronized (_window.getTreeLock()) { - try { - isModalBlockedMethod.setAccessible(true); - if ((Boolean)isModalBlockedMethod.invoke(_window, null)) { - - getModalBlockerMethod.setAccessible(true); - _window = (Dialog)getModalBlockerMethod.invoke(_window, null); - } - } - catch (InvocationTargetException e) { - LOG.error(e); - } - catch (IllegalAccessException e) { - LOG.error(e); - } + if (_window == null && window != null) { + // It might be we just has not opened a frame yet. + // So let's ask AWT + focusOwner = window.getMostRecentFocusOwner(); + if (focusOwner != null) { + _window = SwingUtilities.getWindowAncestor(focusOwner); } } - while (getWindowTitle(_window) == null) { + if (_window != null) { + // We have successfully found the window + // Let's check that we have not missed a blocker + if (ModalityHelper.isModalBlocked(_window)) { + _window = ModalityHelper.getModalBlockerFor(_window); + } + } + + //Actually can, but not in this implementation. If you know a reasonable scenario, please ask Denis Fokin for the improvement. + LOG.assertTrue(getWindowTitle(_window) != null, "A window without a title should not be used for showing MacMessages"); + while (_window != null && getWindowTitle(_window) == null) { _window = _window.getOwner(); //At least our frame should have a title }