IDEA-277709: listen for presentation changes

remove copy/paste

GitOrigin-RevId: 778915a89e52846c132632ae12fc2fd3112db734
This commit is contained in:
Artem Bochkarev
2021-11-18 00:36:20 +07:00
committed by intellij-monorepo-bot
parent f62962b9f4
commit abebd64acd
7 changed files with 154 additions and 83 deletions

Binary file not shown.

View File

@@ -115,14 +115,23 @@ Java_com_intellij_ui_mac_screenmenu_Menu_nativeCreateMenu
/*
* Class: com_intellij_ui_mac_screenmenu_Menu
* Method: nativeSetTitle
* Signature: (JLjava/lang/String;)V
* Signature: (JLjava/lang/String;Z)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_Menu_nativeSetTitle
(JNIEnv *env, jobject peer, jlong menu, jstring label)
(JNIEnv *env, jobject peer, jlong menuObj, jstring label, jboolean onAppKit)
{
JNI_COCOA_ENTER();
[((Menu *)menu) setTitle:JavaStringToNSString(env, label)];
__strong NSString *theText = JavaStringToNSString(env, label);
__strong Menu * menu = (Menu *)menuObj;
dispatch_block_t block = ^{
[menu setTitle:theText];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}
@@ -202,7 +211,7 @@ Java_com_intellij_ui_mac_screenmenu_Menu_nativeRefill
}
};
if (onAppKit)
if (onAppKit && ![NSThread isMainThread])
dispatch_async(dispatch_get_main_queue(), block);
else
block();
@@ -279,7 +288,7 @@ Java_com_intellij_ui_mac_screenmenu_Menu_nativeRefillMainMenu
free(newItemsPtrs);
};
if (onAppKit)
if (onAppKit && ![NSThread isMainThread])
dispatch_async(dispatch_get_main_queue(), block);
else
block();

View File

@@ -306,7 +306,7 @@ JNIEXPORT jlong JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeDispose
(JNIEnv *env, jobject peer, jlong menuItemObj)
{
MenuItem *item = (MenuItem *)menuItemObj;
__strong MenuItem *item = (MenuItem *)menuItemObj;
(*env)->DeleteGlobalRef(env, item->javaPeer);
item->javaPeer = NULL;
dispatch_async(dispatch_get_main_queue(), ^{
@@ -401,11 +401,11 @@ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) {
/*
* Class: com_intellij_ui_mac_screenmenu_MenuItem
* Method: nativeSetLabel
* Signature: (JLjava/lang/String;CII)V
* Signature: (JLjava/lang/String;CIIZ)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetLabel
(JNIEnv *env, jobject peer, jlong menuItemObj, jstring label, jchar shortcutKey, jint shortcutKeyCode, jint mods)
(JNIEnv *env, jobject peer, jlong menuItemObj, jstring label, jchar shortcutKey, jint shortcutKeyCode, jint mods, jboolean onAppKit)
{
JNI_COCOA_ENTER();
NSString *theLabel = JavaStringToNSString(env, label);
@@ -423,33 +423,49 @@ Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetLabel
theKeyEquivalent = @"";
}
[((MenuItem *) menuItemObj) setLabel:theLabel shortcut:theKeyEquivalent modifierMask:mods];
__strong MenuItem * item = (MenuItem *)menuItemObj;
dispatch_block_t block = ^{
[item setLabel:theLabel shortcut:theKeyEquivalent modifierMask:mods];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}
/*
* Class: com_intellij_ui_mac_screenmenu_MenuItem
* Method: nativeSetAcceleratorText
* Signature: (JLjava/lang/String;)V
* Signature: (JLjava/lang/String;Z)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetAcceleratorText
(JNIEnv *env, jobject peer, jlong menuItemObj, jstring acceleratorText)
(JNIEnv *env, jobject peer, jlong menuItemObj, jstring acceleratorText, jboolean onAppKit)
{
JNI_COCOA_ENTER();
NSString *theText = JavaStringToNSString(env, acceleratorText);
[((MenuItem *)menuItemObj) setAcceleratorText:theText];
__strong NSString *theText = JavaStringToNSString(env, acceleratorText);
__strong MenuItem * item = (MenuItem *)menuItemObj;
dispatch_block_t block = ^{
[item setAcceleratorText:theText];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}
/*
* Class: com_intellij_ui_mac_screenmenu_MenuItem
* Method: nativeSetImage
* Signature: (J[III)V
* Signature: (J[IIIZ)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetImage
(JNIEnv *env, jobject peer, jlong menuItemObj, jintArray buffer, jint width, jint height)
(JNIEnv *env, jobject peer, jlong menuItemObj, jintArray buffer, jint width, jint height, jboolean onAppKit)
{
JNI_COCOA_ENTER();
NSImage *nsImage = nil;
@@ -490,52 +506,81 @@ Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetImage
}
// 2. set image for item
[((MenuItem *)menuItemObj) setImage:nsImage];
__strong MenuItem * item = (MenuItem *)menuItemObj;
dispatch_block_t block = ^{
[item setImage:nsImage];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}
/*
* Class: com_intellij_ui_mac_screenmenu_MenuItem
* Method: nativeSetEnabled
* Signature: (JZ)V
* Signature: (JZZ)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetEnabled
(JNIEnv *env, jobject peer, jlong menuItemObj, jboolean enable)
(JNIEnv *env, jobject peer, jlong menuItemObj, jboolean enable, jboolean onAppKit)
{
JNI_COCOA_ENTER();
MenuItem *item = (MenuItem *)menuItemObj;
[item->nsMenuItem setEnabled:(enable == JNI_TRUE)];
__strong MenuItem * item = (MenuItem *)menuItemObj;
dispatch_block_t block = ^{
[item->nsMenuItem setEnabled:(enable == JNI_TRUE)];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}
/*
* Class: com_intellij_ui_mac_screenmenu_MenuItem
* Method: nativeSetSubmenu
* Signature: (JJ)V
* Signature: (JJZ)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetSubmenu
(JNIEnv *env, jobject peer, jlong menuItemObj, jlong submenuObj)
(JNIEnv *env, jobject peer, jlong menuItemObj, jlong submenuObj, jboolean onAppKit)
{
JNI_COCOA_ENTER();
MenuItem *item = (MenuItem *)menuItemObj;
Menu * submenu = (Menu *)submenuObj;
[item->nsMenuItem setSubmenu:submenu->nsMenu];
__strong MenuItem * item = (MenuItem *)menuItemObj;
__strong Menu * submenu = (Menu *)submenuObj;
dispatch_block_t block = ^{
[item->nsMenuItem setSubmenu:submenu->nsMenu];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}
/*
* Class: com_intellij_ui_mac_screenmenu_MenuItem
* Method: nativeSetState
* Signature: (JZ)V
* Signature: (JZZ)V
*/
JNIEXPORT void JNICALL
Java_com_intellij_ui_mac_screenmenu_MenuItem_nativeSetState
(JNIEnv *env, jobject peer, jlong menuItemObj, jboolean isToggled)
(JNIEnv *env, jobject peer, jlong menuItemObj, jboolean isToggled, jboolean onAppKit)
{
JNI_COCOA_ENTER();
MenuItem *item = (MenuItem *)menuItemObj;
[item->nsMenuItem setState:(isToggled == JNI_TRUE ? NSOnState : NSOffState)];
__strong MenuItem * item = (MenuItem *)menuItemObj;
dispatch_block_t block = ^{
[item->nsMenuItem setState:(isToggled == JNI_TRUE ? NSOnState : NSOffState)];
};
if (!onAppKit || [NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
JNI_COCOA_EXIT();
}

View File

@@ -1,16 +1,19 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui.mac.screenmenu;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SimpleTimer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.ReflectionUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -40,18 +43,17 @@ public class Menu extends MenuItem {
this.myComponent = component;
}
public void setTitle(String label) {
ensureNativePeer();
nativeSetTitle(nativePeer,label);
@Override
public void propertyChange(PropertyChangeEvent e) {
@NonNls String propertyName = e.getPropertyName();
if (Presentation.PROP_TEXT.equals(propertyName) || Presentation.PROP_DESCRIPTION.equals(propertyName)) {
setTitle(presentation.getText());
}
}
// If item was created but wasn't added into any parent menu then can be invoked from any thread.
public void addItem(@NotNull MenuItem menuItem, boolean onAppKit) {
myItems.add(menuItem);
public void setTitle(String label) {
ensureNativePeer();
menuItem.ensureNativePeer();
nativeAddItem(nativePeer, menuItem.nativePeer, onAppKit);
nativeSetTitle(nativePeer, label, isInHierarchy);
}
@SuppressWarnings("SSBasedInspection")
@@ -75,10 +77,7 @@ public class Menu extends MenuItem {
synchronized
public void dispose() {
disposeChildren(0);
if (nativePeer != 0) {
nativeDispose(nativePeer);
nativePeer = 0;
}
super.dispose();
}
public void beginFill() {
@@ -104,6 +103,7 @@ public class Menu extends MenuItem {
newItemsPeers[c] = menuItem.nativePeer;
//System.err.printf("\t0x%X\n", newItemsPeers[c]);
myItems.add(menuItem);
menuItem.isInHierarchy = true;
} else {
newItemsPeers[c] = 0;
}
@@ -127,7 +127,14 @@ public class Menu extends MenuItem {
if (actionDelegate != null) {
if (USE_STUB) {
// NOTE: must add stub item when menu opens (otherwise AppKit considers it as empty and we can't fill it later)
addItem(new MenuItem(), false/*already on AppKit thread*/);
MenuItem stub = new MenuItem();
myItems.add(stub);
stub.isInHierarchy = true;
ensureNativePeer();
stub.ensureNativePeer();
nativeAddItem(nativePeer, stub.nativePeer, false/*already on AppKit thread*/);
ApplicationManager.getApplication().invokeLater(()->{
actionDelegate.run();
endFill(true);
@@ -158,7 +165,7 @@ public class Menu extends MenuItem {
private native long nativeCreateMenu();
// If menu was created but wasn't added into any parent menu then all setters can be invoked from any thread.
private native void nativeSetTitle(long menuPtr, String title);
private native void nativeSetTitle(long menuPtr, String title, boolean onAppKit);
private native void nativeAddItem(long menuPtr, long itemPtr/*MenuItem OR Menu*/, boolean onAppKit);
// Refill menu

View File

@@ -2,36 +2,54 @@
package com.intellij.ui.mac.screenmenu;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.Presentation;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@SuppressWarnings({"UndesirableClassUsage", "NonPrivateFieldAccessedInSynchronizedContext", "FieldAccessedSynchronizedAndUnsynchronized"})
public class MenuItem implements Disposable {
public class MenuItem implements Disposable, PropertyChangeListener {
long nativePeer;
Runnable actionDelegate;
boolean isInHierarchy = false;
Presentation presentation;
public void setActionDelegate(Runnable actionDelegate) {
this.actionDelegate = actionDelegate;
}
public void setSubmenu(Menu subMenu) {
@Override
public void propertyChange(PropertyChangeEvent e) {}
public void listenPresentationChanges(Presentation newPresentation) {
if (presentation != null) presentation.removePropertyChangeListener(this);
if (newPresentation != null) {
newPresentation.addPropertyChangeListener(this);
setEnabled(newPresentation.isEnabled());
}
presentation = newPresentation;
}
public void setSubmenu(@NotNull Menu subMenu, boolean onAppKit) {
ensureNativePeer();
subMenu.ensureNativePeer();
nativeSetSubmenu(nativePeer, subMenu.nativePeer);
nativeSetSubmenu(nativePeer, subMenu.nativePeer, isInHierarchy || subMenu.isInHierarchy);
}
public void setState(boolean isToggled) {
ensureNativePeer();
nativeSetState(nativePeer, isToggled);
nativeSetState(nativePeer, isToggled, isInHierarchy);
}
public void setEnabled(boolean isEnabled) {
ensureNativePeer();
nativeSetEnabled(nativePeer, isEnabled);
nativeSetEnabled(nativePeer, isEnabled, isInHierarchy);
}
public void setLabel(String label, KeyStroke ks) {
@@ -48,7 +66,7 @@ public class MenuItem implements Disposable {
keyChar = 0;
}
nativeSetLabel(nativePeer, label, keyChar, keyCode, modifiers);
nativeSetLabel(nativePeer, label, keyChar, keyCode, modifiers, isInHierarchy);
}
public void setIcon(final Icon icon) {
@@ -67,12 +85,12 @@ public class MenuItem implements Disposable {
}
ensureNativePeer();
nativeSetImage(nativePeer, bytes, w, h);
nativeSetImage(nativePeer, bytes, w, h, isInHierarchy);
}
public void setAcceleratorText(String acceleratorText) {
ensureNativePeer();
nativeSetAcceleratorText(nativePeer, acceleratorText);
nativeSetAcceleratorText(nativePeer, acceleratorText, isInHierarchy);
}
synchronized
@@ -94,6 +112,9 @@ public class MenuItem implements Disposable {
@Override
synchronized
public void dispose() {
if (presentation != null) presentation.removePropertyChangeListener(this);
presentation = null;
if (nativePeer != 0) {
nativeDispose(nativePeer);
nativePeer = 0;
@@ -113,10 +134,10 @@ public class MenuItem implements Disposable {
native void nativeDispose(long nativePeer);
// If item was created but wasn't added into any parent menu then all setters can be invoked from any thread.
private native void nativeSetLabel(long nativePeer, String label, char keyChar, int keyCode, int modifiers);
private native void nativeSetImage(long nativePeer, int[] buffer, int w, int h);
private native void nativeSetEnabled(long nativePeer, boolean isEnabled);
private native void nativeSetAcceleratorText(long nativePeer, String acceleratorText);
private native void nativeSetState(long nativePeer, boolean isToggled);
public native void nativeSetSubmenu(long nativePeer, long submenu);
private native void nativeSetLabel(long nativePeer, String label, char keyChar, int keyCode, int modifiers, boolean onAppKit);
private native void nativeSetImage(long nativePeer, int[] buffer, int w, int h, boolean onAppKit);
private native void nativeSetEnabled(long nativePeer, boolean isEnabled, boolean onAppKit);
private native void nativeSetAcceleratorText(long nativePeer, String acceleratorText, boolean onAppKit);
private native void nativeSetState(long nativePeer, boolean isToggled, boolean onAppKit);
private native void nativeSetSubmenu(long nativePeer, long submenu, boolean onAppKit);
}

View File

@@ -74,9 +74,7 @@ public final class ActionMenu extends JBMenu {
if (myScreenMenuPeer != null) {
myScreenMenuPeer.setOnOpen(() -> fillMenu(), this);
myScreenMenuPeer.setOnClose(() -> setSelected(false), this);
// update from presentation
myScreenMenuPeer.setEnabled(myPresentation.isEnabled());
myScreenMenuPeer.listenPresentationChanges(myPresentation);
}
updateUI();

View File

@@ -64,36 +64,24 @@ public class ActionMenuItem extends JBCheckBoxMenuItem {
myToggleable = action instanceof Toggleable;
myInsideCheckedGroup = insideCheckedGroup;
myUseDarkIcons = useDarkIcons;
final ActionTransmitter actionTransmitter = new ActionTransmitter();
addActionListener(actionTransmitter);
setBorderPainted(false);
myScreenMenuItemPeer = screenMenuItemPeer;
if (myScreenMenuItemPeer != null) {
myScreenMenuItemPeer.setActionDelegate(()-> {
// Called on AppKit when menu opening
// Called on AppKit when user activates menu item
if (isToggleable()) {
myToggled = !myToggled;
myScreenMenuItemPeer.setState(myToggled);
}
ApplicationManager.getApplication().invokeLater(()->{
IdeFocusManager focusManager = IdeFocusManager.findInstanceByContext(myContext);
focusManager.runOnOwnContext(myContext, () -> {
AWTEvent currentEvent = IdeEventQueue.getInstance().getTrueCurrentEvent();
final AnActionEvent event = new AnActionEvent(
currentEvent instanceof InputEvent ? (InputEvent)currentEvent : null,
myContext, myPlace, myPresentation, ActionManager.getInstance(), 0, true, false
);
AnAction menuItemAction = myAction.getAction();
if (ActionUtil.lastUpdateAndCheckDumb(menuItemAction, event, false)) {
ActionUtil.performActionDumbAwareWithCallbacks(menuItemAction, event);
}
});
actionTransmitter.performAction(0);
});//invokeLater
});//setActionDelegate
}
addActionListener(new ActionTransmitter());
setBorderPainted(false);
updateUI();
init();
}
@@ -279,9 +267,7 @@ public class ActionMenuItem extends JBCheckBoxMenuItem {
}
private final class ActionTransmitter implements ActionListener {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
void performAction(int modifiers) {
IdeFocusManager focusManager = IdeFocusManager.findInstanceByContext(myContext);
String id = ActionManager.getInstance().getId(myAction.getAction());
if (id != null) {
@@ -292,7 +278,7 @@ public class ActionMenuItem extends JBCheckBoxMenuItem {
AWTEvent currentEvent = IdeEventQueue.getInstance().getTrueCurrentEvent();
final AnActionEvent event = new AnActionEvent(
currentEvent instanceof InputEvent ? (InputEvent)currentEvent : null,
myContext, myPlace, myPresentation, ActionManager.getInstance(), e.getModifiers(), true, false
myContext, myPlace, myPresentation, ActionManager.getInstance(), modifiers, true, false
);
AnAction menuItemAction = myAction.getAction();
if (ActionUtil.lastUpdateAndCheckDumb(menuItemAction, event, false)) {
@@ -300,5 +286,10 @@ public class ActionMenuItem extends JBCheckBoxMenuItem {
}
});
}
@Override
public void actionPerformed(@NotNull ActionEvent e) {
performAction(e.getModifiers());
}
}
}