linux-menubar: fixes

fixed IDEA-200379 linux Native menu bar on Ubuntu Linux: the View menu actions have incorrect state
fixed IDEA-151200 Unity menu bar is not available for detached editor tabs and floating tool windows
fixed IDEA-200724 IntelliJ IDEA does not fully start after update, ends with window with menubar and nothing else
fixed IDEA-200374 Throwable at com.intellij.openapi.wm.impl.GlobalMenuLinux.lambda$handleEvent$4
fixed IDEA-200768 Start Splash window doesn't hide
fixed IDEA-200822 Opening any Markdown file freezes recent IntelliJ Ultimate EAP 183.3795.13

fixed GLIB-WARN (child/parent mismatches)
add traces
return checking of registry key linux.native.menu
fix loading of class GlobalMenuLib
This commit is contained in:
Artem Bochkarev
2018-10-19 17:02:13 +07:00
parent 62847b08dd
commit efe12a1b3f
5 changed files with 201 additions and 110 deletions
Binary file not shown.
+14 -6
View File
@@ -317,21 +317,19 @@ void bindNewWindow(WndInfo * wi, long windowXid) {
return;
}
if (wi->linkedXids == NULL) {
wi->linkedXids = g_list_alloc();
wi->linkedXids->data = windowXid;
} else
g_list_append(wi->linkedXids, windowXid);
// _logmsg(LOG_LEVEL_INFO, "bind new window 0x%lx", windowXid);
wi->linkedXids = g_list_append(wi->linkedXids, windowXid);
}
void unbindWindow(WndInfo * wi, long windowXid) {
if (wi == NULL || wi->server == NULL || wi->menuPath == NULL)
return;
// _logmsg(LOG_LEVEL_INFO, "unbind window 0x%lx", windowXid);
_unregisterWindow(windowXid, wi->registrar);
if (wi->linkedXids != NULL)
g_list_remove(wi->linkedXids, windowXid);
wi->linkedXids = g_list_remove(wi->linkedXids, windowXid);
}
static gboolean _execReleaseWindow(gpointer user_data) {
@@ -536,6 +534,16 @@ void setItemShortcut(DbusmenuMenuitem *item, int jmodifiers, int jkeycode) {
dbusmenu_menuitem_property_set_variant(item, DBUSMENU_MENUITEM_PROP_SHORTCUT, outsideArr);
}
void toggleItemStateChecked(DbusmenuMenuitem *item, bool isChecked) {
const int nOn = DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED;
const int nOff = DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED;
const int ncheck = isChecked ? nOn : nOff;
if (dbusmenu_menuitem_property_get_int(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE) != ncheck) {
// _logmsg(LOG_LEVEL_INFO, "item %s changes checked-state: %d -> %d", _getItemLabel(item), dbusmenu_menuitem_property_get_int(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE), ncheck);
dbusmenu_menuitem_property_set_int(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, ncheck);
}
}
static gboolean _execJRunnable(gpointer user_data) {
(*((jrunnable) user_data))();
return FALSE;
+2
View File
@@ -62,6 +62,8 @@ void setItemEnabled(DbusmenuMenuitem* item, bool isEnabled);
void setItemIcon(DbusmenuMenuitem* item, const char * iconBytesPng, int iconBytesCount);
void setItemShortcut(DbusmenuMenuitem *item, int jmodifiers, int jkeycode);
void toggleItemStateChecked(DbusmenuMenuitem *item, bool isChecked);
#ifdef __cplusplus
}
#endif
@@ -2,6 +2,7 @@
package com.intellij.openapi.wm.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.impl.ActionMenu;
import com.intellij.openapi.actionSystem.impl.ActionMenuItem;
@@ -29,14 +30,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.*;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Date;
interface GlobalMenuLib extends Library {
void runDbusServer(JLogger jlogger, JRunnable onAppmenuServiceAppeared, JRunnable onAppmenuServiceVanished);
@@ -46,8 +43,8 @@ interface GlobalMenuLib extends Library {
Pointer registerWindow(long windowXid, EventHandler handler);
void releaseWindowOnMainLoop(Pointer wi);
void bindNewWindow(Pointer wi, long windowXid);
void unbindWindow(Pointer wi, long windowXid);
void bindNewWindow(Pointer wi, long windowXid); // can be called from EDT (invokes only g_dbus_proxy_call, stateless)
void unbindWindow(Pointer wi, long windowXid); // can be called from EDT (invokes only g_dbus_proxy_call, stateless)
void clearRootMenu(Pointer wi);
void clearMenu(Pointer dbmi);
@@ -63,6 +60,8 @@ interface GlobalMenuLib extends Library {
void setItemIcon(Pointer item, byte[] iconBytesPng, int iconBytesCount);
void setItemShortcut(Pointer item, int jmodifiers, int jkeycode);
void toggleItemStateChecked(Pointer item, boolean isChecked);
interface EventHandler extends Callback {
void handleEvent(int uid, int eventType);
}
@@ -98,16 +97,22 @@ interface GlobalMenuLib extends Library {
public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
private static final SimpleDateFormat ourDtf = new SimpleDateFormat("hhmmss.SSS"); // for debug only
private static final boolean TRACE_SYSOUT = Registry.is("linux.native.menu.debug.trace.sysout", false);
private static final boolean TRACE_DISABLED = Registry.is("linux.native.menu.debug.trace.disabled", true);
private static final boolean TRACE_SYNC_STATS = Registry.is("linux.native.menu.debug.trace.sync-stats", false);
private static final boolean TRACE_EVENTS = Registry.is("linux.native.menu.debug.trace.events", false);
private static final boolean TRACE_EVENT_FILTER = Registry.is("linux.native.menu.debug.trace.event-filter", false);
private static final boolean TRACE_SYSOUT = Registry.is("linux.native.menu.debug.trace.sysout", false);
private static final boolean TRACE_DISABLED = Registry.is("linux.native.menu.debug.trace.disabled", true);
private static final boolean TRACE_SYNC_STATS = Registry.is("linux.native.menu.debug.trace.sync-stats", false);
private static final boolean TRACE_EVENTS = Registry.is("linux.native.menu.debug.trace.events", false);
private static final boolean TRACE_EVENT_FILTER = Registry.is("linux.native.menu.debug.trace.event-filter", false);
private static final boolean TRACE_CLEARING = Registry.is("linux.native.menu.debug.trace.clearing", false);
private static final boolean TRACE_HIERARCHY_MISMATCHES = Registry.is("linux.native.menu.debug.trace.hierarchy.mismatches", false);
private static final boolean SHOW_SWING_MENU = Registry.is("linux.native.menu.debug.show.frame.menu", false);
private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class);
private static final GlobalMenuLib ourLib;
private static final GlobalMenuLib.JLogger ourGLogger;
private static final Thread ourGlibMainLoopThread;
private static final GlobalMenuLib.JRunnable ourProcessQueue;
private static final GlobalMenuLib.JRunnable ourOnAppmenuServiceAppeared;
private static final GlobalMenuLib.JRunnable ourOnAppmenuServiceVanished;
private static final Map<Long, GlobalMenuLinux> ourInstances = new ConcurrentHashMap<>();
private static boolean ourIsServiceAvailable = false;
@@ -124,18 +129,47 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
if (ourLib != null) {
ourGLogger = (level, msg) -> {
if (level == GlobalMenuLib.LOG_LEVEL_INFO) {
// System.out.println("INFO: " + msg);
LOG.info(msg);
if (TRACE_SYSOUT)
_trace(msg);
else
LOG.info(msg);
} else {
// System.out.println("ERROR: " + msg);
LOG.error(msg);
}
};
ourGlibMainLoopThread = new Thread(()->ourLib.runDbusServer(ourGLogger, GlobalMenuLinux::_onAppmenuServiceAppeared, GlobalMenuLinux::_onAppmenuServiceVanished), "Glib-main-loop");
ourProcessQueue = () -> {
// exec at glib-thread
if (!ourIsServiceAvailable)
return;
for (GlobalMenuLinux gml: ourInstances.values())
gml._processRoots();
};
ourOnAppmenuServiceAppeared = () -> {
// exec at glib-thread
_trace("Appeared dbus-service 'com.canonical.AppMenu.Registrar'");
ourIsServiceAvailable = true;
ourProcessQueue.run();
};
ourOnAppmenuServiceVanished = () -> {
// exec at glib-thread
_trace("Closed dbus-service 'com.canonical.AppMenu.Registrar'");
ourIsServiceAvailable = false;
for (GlobalMenuLinux gml: ourInstances.values()) {
gml.myWindowHandle = null;
ApplicationManager.getApplication().invokeLater(()->gml.myFrame.getJMenuBar().setVisible(true));
}
};
ourGlibMainLoopThread = new Thread(()->ourLib.runDbusServer(ourGLogger, ourOnAppmenuServiceAppeared, ourOnAppmenuServiceVanished), "Glib-main-loop");
ourGlibMainLoopThread.start();
} else {
ourGLogger = null;
ourGlibMainLoopThread = null;
ourProcessQueue = null;
ourOnAppmenuServiceAppeared = null;
ourOnAppmenuServiceVanished = null;
}
}
@@ -163,17 +197,34 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
}
public void bindNewWindow(@NotNull Window frame) {
// exec at EDT
final long xid = _getX11WindowXid(frame);
if (xid == 0)
if (xid == 0) {
LOG.warn("can't obtain XID of window: " + frame + ", skip global menu binding");
return;
ourLib.bindNewWindow(myWindowHandle, xid);
}
if (myWindowHandle != null) {
_trace("bind new window 0x%X", xid);
ourLib.bindNewWindow(myWindowHandle, xid);
if (frame instanceof JFrame) {
final JFrame jfr = (JFrame)frame;
if (jfr.getJMenuBar() != null)
jfr.getJMenuBar().setVisible(false);
}
}
}
public void unbindNewWindow(@NotNull Window frame) {
public void unbindWindow(@NotNull Window frame) {
// exec at EDT
final long xid = _getX11WindowXid(frame);
if (xid == 0)
if (xid == 0) {
LOG.warn("can't obtain XID of window: " + frame + ", skip global menu unbinding");
return;
ourLib.unbindWindow(myWindowHandle, xid);
}
if (myWindowHandle != null) {
_trace("unbind window 0x%X", xid);
ourLib.unbindWindow(myWindowHandle, xid);
}
}
public void setRoots(List<ActionMenu> roots) {
@@ -187,8 +238,9 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
if (roots != null) {
for (ActionMenu am: roots) {
final int uid = System.identityHashCode(am);
final MenuItemInternal mi = new MenuItemInternal(newRoots.size(), uid, GlobalMenuLib.ITEM_SUBMENU, _buildMnemonicLabel(am), am.getText(), null, true, am.getAnAction());
final MenuItemInternal mi = new MenuItemInternal(newRoots.size(), uid, GlobalMenuLib.ITEM_SUBMENU, am.getAnAction());
mi.jitem = am;
mi.setLabelFromSwingPeer(am);
newRoots.add(mi);
}
}
@@ -223,7 +275,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
for (MenuItemInternal mi: croots)
mi.nativePeer = ourLib.addRootMenu(myWindowHandle, mi.uid, mi.txt);
if (!Registry.is("linux.native.menu.debug.show.frame.menu", false))
if (!SHOW_SWING_MENU)
ApplicationManager.getApplication().invokeLater(()->myFrame.getJMenuBar().setVisible(false));
}
@@ -291,14 +343,14 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
MenuItemInternal result = null;
if (each instanceof ActionMenuItem) {
final ActionMenuItem ami = (ActionMenuItem)each;
result = new MenuItemInternal(-1, System.identityHashCode(ami), ami.isToggleable() ? GlobalMenuLib.ITEM_CHECK : GlobalMenuLib.ITEM_SIMPLE, ami.getText(), ami.getText(), _icon2png(ami.getIcon()), ami.isEnabled(), ami.getAnAction());
result = new MenuItemInternal(-1, System.identityHashCode(ami), ami.isToggleable() ? GlobalMenuLib.ITEM_CHECK : GlobalMenuLib.ITEM_SIMPLE, ami.getAnAction());
result.jitem = ami;
} else if (each instanceof ActionMenu) {
final ActionMenu am2 = (ActionMenu)each;
result = new MenuItemInternal(-1, System.identityHashCode(am2), GlobalMenuLib.ITEM_SUBMENU, am2.getText(), am2.getText(), null, am2.isEnabled(), am2.getAnAction());
result = new MenuItemInternal(-1, System.identityHashCode(am2), GlobalMenuLib.ITEM_SUBMENU, am2.getAnAction());
result.jitem = am2;
} else if (each instanceof JSeparator) {
result = new MenuItemInternal(-1, System.identityHashCode(each), GlobalMenuLib.ITEM_SIMPLE, null, null, null, true, null);
result = new MenuItemInternal(-1, System.identityHashCode(each), GlobalMenuLib.ITEM_SIMPLE, null);
} else if (each instanceof StubItem) {
// System.out.println("skip StubItem");
} else {
@@ -334,6 +386,8 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
if (cmi != null) {
mi.children.add(cmi);
if (stats != null) ++stats[STAT_CREATED];
if (each instanceof JMenuItem)
cmi.updateBySwingPeer((JMenuItem)each);
}
} else {
cmi.toDelete = false;
@@ -359,11 +413,9 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
if (child.nativePeer != null) {
if (child.toDelete) {
ourLib.removeMenuItem(mi.nativePeer, child.nativePeer);
child.nativePeer = null;
} else {
// update states and icons
// NOTE: probably it's better to use sync flags, to avoid frequent calls, to avoid applet destabilization)
ourLib.setItemEnabled(child.nativePeer, child.isEnabled);
ourLib.setItemIcon(child.nativePeer, child.iconPngBytes, child.iconPngBytes != null ? child.iconPngBytes.length : 0);
child.updateNative();
}
} else {
if (child.action == null) {
@@ -372,11 +424,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
}
child.nativePeer = ourLib.addMenuItem(mi.nativePeer, child.uid, child.txt, child.type);
if (!child.isEnabled)
ourLib.setItemEnabled(child.nativePeer, false);
if (child.iconPngBytes != null && child.iconPngBytes.length > 0)
ourLib.setItemIcon(child.nativePeer, child.iconPngBytes, child.iconPngBytes.length);
child.updateNative();
}
_processChildren(child);
@@ -416,7 +464,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
// ETD-start
final JMenuItem jmi = mi.jitem;
if (jmi == null) {
LOG.error("can't find corresponding (opening) ActionMenu, event source: " + mi + ", swing menu hierarchy:\n" + _dumpSwingHierarchy());
if (TRACE_HIERARCHY_MISMATCHES) _trace("corresponding (opening) swing item is null, event source: " + mi + ", swing menu hierarchy:\n" + _dumpSwingHierarchy());
return;
}
if (!(jmi instanceof ActionMenu)) {
@@ -437,26 +485,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
_processChildren(mi);
} else if (eventType == GlobalMenuLib.EVENT_CLOSED) {
// glib main-loop thread
final Timer timer = new Timer(100, (e) -> {
// ETD-start
final JMenuItem jmi = mi.jitem;
if (jmi == null) {
LOG.error("can't find corresponding (closing) ActionMenu, event source: " + mi + ", swing menu hierarchy:\n" + _dumpSwingHierarchy());
return;
}
if (!(jmi instanceof ActionMenu)) {
LOG.error("corresponding (closing) swing item isn't instance of ActionMenu, class=" + jmi.getClass().getName() + ", event source: " + mi);
return;
}
final ActionMenu am = (ActionMenu)jmi;
am.clearItems();
mi.clearChildrenSwingRefs();
});
timer.setRepeats(false);
timer.start();
_trace("\t scheduled (100 ms later) to clear menu '%s'", mi.txt);
mi.scheduleClearSwing();
}
return;
@@ -483,22 +512,22 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
public static boolean isAvailable() { return ourLib != null; }
private static GlobalMenuLib _loadLibrary() {
if (!SystemInfo.isLinux)
if (!SystemInfo.isLinux || !Registry.is("linux.native.menu"))
return null;
UrlClassLoader.loadPlatformLibrary("dbm");
// Set JNA to convert java.lang.String to char* using UTF-8, and match that with
// the way we tell CF to interpret our char*
// May be removed if we use toStringViaUTF16
System.setProperty("jna.encoding", "UTF8");
final Map<String, Object> options = new HashMap<>();
try {
UrlClassLoader.loadPlatformLibrary("dbm");
// Set JNA to convert java.lang.String to char* using UTF-8, and match that with
// the way we tell CF to interpret our char*
// May be removed if we use toStringViaUTF16
System.setProperty("jna.encoding", "UTF8");
final Map<String, Object> options = new HashMap<>();
return Native.loadLibrary("dbm", GlobalMenuLib.class, options);
} catch (UnsatisfiedLinkError ule) {
LOG.error(ule);
} catch (RuntimeException e) {
LOG.info("disable global-menu integration because some of shared libraries isn't installed: " + ule);
} catch (Throwable e) {
LOG.error(e);
}
return null;
@@ -514,28 +543,27 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
String txt;
String originTxt;
boolean isEnabled;
boolean isEnabled = true;
boolean isChecked = false;
byte[] iconPngBytes;
JMenuItem jitem;
Pointer nativePeer;
boolean toDelete = false;
long lastOpenedMs = 0;
long lastClosedMs = 0;
MenuItemInternal(int rootPos, int uid, int type, String txt, String originTxt, byte[] iconPngBytes, boolean isEnabled, AnAction action) {
Timer timerClearSwing;
MenuItemInternal(int rootPos, int uid, int type, AnAction action) {
this.rootPos = rootPos;
this.uid = uid;
this.type = type;
this.txt = txt;
this.originTxt = originTxt;
this.iconPngBytes = iconPngBytes;
this.isEnabled = isEnabled;
this.action = action;
}
boolean isRoot() { return rootPos >= 0; }
boolean isToggleable() { return type == GlobalMenuLib.ITEM_CHECK || type == GlobalMenuLib.ITEM_RADIO; }
void clearChildrenSwingRefs() {
for (MenuItemInternal cmi: children) {
@@ -545,16 +573,44 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
}
// returns true when changed
boolean updateBySwingPeer(JMenuItem peer) {
boolean updateBySwingPeer(@NotNull JMenuItem peer) {
// exec at EDT
jitem = peer;
// probably need to calc sync flags like: if (cmi.isEnabled != each.isEnabled()) cmi.needUpdate = true;
// NOTE: probably is's better to use sync flags like: if (cmi.isEnabled != each.isEnabled()) cmi.needUpdate = true;
boolean res = isEnabled != peer.isEnabled();
isEnabled = peer.isEnabled();
// TODO: update icons (text must be the same)
if (isToggleable()) {
if (isChecked != peer.isSelected()) res = true;
isChecked = peer.isSelected();
}
if (!Objects.equals(originTxt, peer.getText())) {
// _trace("label changes: '%s' -> '%s'", originTxt, peer.getText());
setLabelFromSwingPeer(peer);
res = true;
}
iconPngBytes = isToggleable() ? null : _icon2png(peer.getIcon());
return res;
}
void setLabelFromSwingPeer(@NotNull JMenuItem peer) {
// exec at EDT
originTxt = peer.getText();
txt = _buildMnemonicLabel(peer);
}
void updateNative() {
// exec at glib-loop thread
// NOTE: probably it's better to use sync flags, to avoid frequent calls, to avoid applet destabilization)
if (nativePeer == null)
return;
ourLib.setItemLabel(nativePeer, txt);
ourLib.setItemEnabled(nativePeer, isEnabled);
ourLib.setItemIcon(nativePeer, iconPngBytes, iconPngBytes != null ? iconPngBytes.length : 0);
if (isToggleable())
ourLib.toggleItemStateChecked(nativePeer, isChecked);
}
MenuItemInternal findCorrespondingChild(@NotNull Component target) {
if (target == null)
return null;
@@ -638,6 +694,55 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
res = res + " [toDelele]";
return res;
}
String toStringShort() {
String res = String.format("'%s'", txt);
if (toDelete)
res = res + " [D]";
if (isRoot())
res = "Root " + res;
else
res = "Submenu " + res;
return res;
}
synchronized void scheduleClearSwing() {
// exec at glib main-loop thread
if (timerClearSwing != null)
timerClearSwing.stop();
timerClearSwing = new Timer(300, (e) -> {
_clearSwing();
});
timerClearSwing.setRepeats(false);
timerClearSwing.start();
if (TRACE_CLEARING) _trace("\t scheduled (300 ms later) to clear '%s'", toStringShort());
}
synchronized void cancelClearSwing() {
// exec at glib main-loop thread
timerClearSwing = null;
}
private void _clearSwing() {
// exec at ETD
if (timerClearSwing == null)
return;
if (jitem == null) {
if (TRACE_CLEARING) _trace("corresponding (closing) swing item is null - nothing to clear, event source: ", this);
return;
}
if (!(jitem instanceof ActionMenu)) {
LOG.error("corresponding (closing) swing item isn't instance of ActionMenu, class=" + jitem.getClass().getName() + ", event source: " + toString());
return;
}
final ActionMenu am = (ActionMenu)jitem;
am.clearItems();
clearChildrenSwingRefs();
if (TRACE_CLEARING) _trace("\t cleared '%s'", toStringShort());
}
}
private class EventFilter {
@@ -666,6 +771,8 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
if (TRACE_EVENT_FILTER) _trace("EventFilter: start timer to process 'about-to-show' of first-root later");
return false;
}
myTimer = null;
} else if (mi.rootPos > 0) {
if ((timeMs - myLastFirstRootEventMs) < 50) {
if (TRACE_EVENT_FILTER) _trace("EventFilter: skip fake 'about-to-show' of root[%d]%s", mi.rootPos, myTimer != null ? " (reset timer)" : "");
@@ -685,8 +792,6 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
}
}
if (mi.rootPos == 0)
myTimer = null;
return true;
}
}
@@ -821,28 +926,4 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
else
LOG.info(msg);
}
private static final GlobalMenuLib.JRunnable ourProcessQueue = () -> {
// exec at glib-thread
if (!ourIsServiceAvailable)
return;
for (GlobalMenuLinux gml: ourInstances.values())
gml._processRoots();
};
private static void _onAppmenuServiceAppeared() {
// exec at glib-thread
ourIsServiceAvailable = true;
ourProcessQueue.run();
}
private static void _onAppmenuServiceVanished() {
// exec at glib-thread
ourIsServiceAvailable = false;
for (GlobalMenuLinux gml: ourInstances.values()) {
gml.myWindowHandle = null;
ApplicationManager.getApplication().invokeLater(()->gml.myFrame.getJMenuBar().setVisible(true));
}
}
}
@@ -16,7 +16,6 @@ import com.intellij.openapi.actionSystem.impl.WeakTimerListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.FrameWrapper;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
@@ -575,8 +574,9 @@ public class IdeMenuBar extends JMenuBar implements IdeEventQueue.EventDispatche
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
frameMenuBar.myGlobalMenuLinux.unbindNewWindow(frame);
frameMenuBar.myGlobalMenuLinux.unbindWindow(frame);
}
@Override
public void windowOpened(WindowEvent e) {
frameMenuBar.myGlobalMenuLinux.bindNewWindow(frame);
}