diff --git a/bin/linux/libdbm64.so b/bin/linux/libdbm64.so index 7fc851dcc111..8d0864502783 100755 Binary files a/bin/linux/libdbm64.so and b/bin/linux/libdbm64.so differ diff --git a/native/LinuxGlobalMenu/DbusMenuWrapper.c b/native/LinuxGlobalMenu/DbusMenuWrapper.c index 2601e201381d..42e0b70773fc 100644 --- a/native/LinuxGlobalMenu/DbusMenuWrapper.c +++ b/native/LinuxGlobalMenu/DbusMenuWrapper.c @@ -30,6 +30,7 @@ typedef struct _WndInfo { DbusmenuServer *server; DbusmenuMenuitem *menuroot; jeventcallback jhandler; + jrunnable onReleaseCallback; GList* linkedXids; } WndInfo; @@ -211,6 +212,10 @@ static void _releaseWindow(WndInfo *wi) { wi->linkedXids = NULL; } + if (wi->onReleaseCallback != NULL) { + (*wi->onReleaseCallback)(); + wi->onReleaseCallback = NULL; + } free(wi); } @@ -340,8 +345,10 @@ static gboolean _execReleaseWindow(gpointer user_data) { return FALSE; } -void releaseWindowOnMainLoop(WndInfo *wi) { +void releaseWindowOnMainLoop(WndInfo *wi, jrunnable onReleased) { // _info("scheduled releaseWindowOnMainLoop"); + if (wi != NULL) + wi->onReleaseCallback = onReleased; g_idle_add(_execReleaseWindow, wi); } diff --git a/native/LinuxGlobalMenu/DbusMenuWrapper.h b/native/LinuxGlobalMenu/DbusMenuWrapper.h index f1b459d23292..42264b053749 100644 --- a/native/LinuxGlobalMenu/DbusMenuWrapper.h +++ b/native/LinuxGlobalMenu/DbusMenuWrapper.h @@ -40,7 +40,7 @@ void runMainLoop(jlogger jlogger, jrunnable onAppmenuServiceAppeared, jrunnable void execOnMainLoop(jrunnable run); WndInfo* registerWindow(long windowXid, jeventcallback handler); // creates menu-server and binds to xid -void releaseWindowOnMainLoop(WndInfo* wi); +void releaseWindowOnMainLoop(WndInfo* wi, jrunnable onReleased); void bindNewWindow(WndInfo * wi, long windowXid); void unbindWindow(WndInfo * wi, long windowXid); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java index d02c815b7517..f5d49caa2e85 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java @@ -24,7 +24,6 @@ import javax.imageio.ImageIO; import javax.swing.Timer; import javax.swing.*; import java.awt.*; -import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.awt.peer.ComponentPeer; import java.io.ByteArrayOutputStream; @@ -45,7 +44,7 @@ interface GlobalMenuLib extends Library { void execOnMainLoop(JRunnable run); Pointer registerWindow(long windowXid, EventHandler handler); - void releaseWindowOnMainLoop(Pointer wi); + void releaseWindowOnMainLoop(Pointer wi, JRunnable onReleased); 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) @@ -109,7 +108,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class); private static final GlobalMenuLib ourLib; private static final GlobalMenuLib.JLogger ourGLogger; - private static final GlobalMenuLib.JRunnable ourProcessQueue; + private static final GlobalMenuLib.JRunnable ourUpdateAllRoots; private static final GlobalMenuLib.JRunnable ourOnAppmenuServiceAppeared; private static final GlobalMenuLib.JRunnable ourOnAppmenuServiceVanished; private static final Map ourInstances = new ConcurrentHashMap<>(); @@ -119,8 +118,11 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private final @NotNull JFrame myFrame; private List myRoots; private Pointer myWindowHandle; - private boolean myIsProcessed = false; + private boolean myIsRootsUpdated = false; + private boolean myIsEnabled = true; + private boolean myIsDisposed = false; + private final GlobalMenuLib.JRunnable myOnWindowReleased; private final EventFilter myEventFilter = new EventFilter(); static { @@ -137,19 +139,19 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { LOG.error(msg); } }; - ourProcessQueue = () -> { + ourUpdateAllRoots = () -> { // exec at glib-thread if (!ourIsServiceAvailable) return; for (GlobalMenuLinux gml: ourInstances.values()) - gml._processRoots(); + gml._updateRoots(); }; ourOnAppmenuServiceAppeared = () -> { // exec at glib-thread LOG.info("Appeared dbus-service 'com.canonical.AppMenu.Registrar'"); ourIsServiceAvailable = true; - ourProcessQueue.run(); + ourUpdateAllRoots.run(); }; ourOnAppmenuServiceVanished = () -> { // exec at glib-thread @@ -177,7 +179,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } else { ourGLogger = null; - ourProcessQueue = null; + ourUpdateAllRoots = null; ourOnAppmenuServiceAppeared = null; ourOnAppmenuServiceVanished = null; } @@ -192,22 +194,40 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { LOG.info("created instance of GlobalMenuLinux for xid=0x" + Long.toHexString(xid)); myXid = xid; myFrame = frame; + myOnWindowReleased = () -> { + // exec at glib-thread + myWindowHandle = null; + if (myRoots != null) { + for (MenuItemInternal root : myRoots) { + root.nativePeer = null; + root.children.clear(); + } + } + if (myIsDisposed) + ourInstances.remove(myXid); + }; ourInstances.put(myXid, this); } @Override public void dispose() { - if (ourLib == null) + // exec at EDT + if (ourLib == null || myIsDisposed) return; + myIsDisposed = true; + if (myWindowHandle != null) { - LOG.info("scheduled destroying of GlobalMenuLinux for xid=0x" + Long.toHexString(myXid)); - ourLib.releaseWindowOnMainLoop(myWindowHandle); + _trace("dispose frame, scheduled destroying of GlobalMenuLinux for xid=0x%X", myXid); + ourLib.releaseWindowOnMainLoop(myWindowHandle, myOnWindowReleased); } } public void bindNewWindow(@NotNull Window frame) { // exec at EDT + if (ourLib == null) + return; + final long xid = _getX11WindowXid(frame); if (xid == 0) { LOG.warn("can't obtain XID of window: " + frame + ", skip global menu binding"); @@ -221,6 +241,9 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { public void unbindWindow(@NotNull Window frame) { // exec at EDT + if (ourLib == null) + return; + final long xid = _getX11WindowXid(frame); if (xid == 0) { LOG.warn("can't obtain XID of window: " + frame + ", skip global menu unbinding"); @@ -233,6 +256,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } public void setRoots(List roots) { + // exec at EDT if (ourLib == null) return; @@ -252,16 +276,16 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { myRoots = newRoots; _trace("set new menu roots, count=%d", size); - myIsProcessed = false; - ourLib.execOnMainLoop(ourProcessQueue); + myIsRootsUpdated = false; + ourLib.execOnMainLoop(ourUpdateAllRoots); } - private void _processRoots() { + private void _updateRoots() { // exec at glib-thread - if (myIsProcessed) + if (myIsRootsUpdated || !myIsEnabled || myIsDisposed) return; - myIsProcessed = true; + myIsRootsUpdated = true; if (myWindowHandle == null) { myWindowHandle = ourLib.registerWindow(myXid, this); @@ -281,7 +305,35 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { mi.nativePeer = ourLib.addRootMenu(myWindowHandle, mi.uid, mi.txt); if (!SHOW_SWING_MENU) - ApplicationManager.getApplication().invokeLater(()->myFrame.getJMenuBar().setVisible(false)); + ApplicationManager.getApplication().invokeLater(()->{ + if (myIsEnabled) + myFrame.getJMenuBar().setVisible(false); + }); + } + + public void toggle(boolean enabled) { + if (ourLib == null || myIsDisposed) + return; + + if (myIsEnabled == enabled) + return; + + myIsEnabled = enabled; + + if (enabled) { + _trace("enable global-menu"); + myIsRootsUpdated = false; + ourLib.execOnMainLoop(ourUpdateAllRoots); + } else { + if (myWindowHandle != null) { + _trace("disable global menu, scheduled destroying of GlobalMenuLinux for xid=0x%X", myXid); + ourLib.releaseWindowOnMainLoop(myWindowHandle, myOnWindowReleased); + } + + final JMenuBar frameMenu = myFrame.getJMenuBar(); + if (frameMenu != null) + frameMenu.setVisible(true); + } } private MenuItemInternal _findMenuItem(int uid) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java index 411bc316c0ed..f82072fcf6aa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameDecorator.java @@ -152,6 +152,11 @@ public abstract class IdeFrameDecorator implements Disposable { if (myFrame != null) { myRequestedState = state; X11UiUtil.toggleFullScreenMode(myFrame); + + if (myFrame.getJMenuBar() instanceof IdeMenuBar) { + final IdeMenuBar frameMenuBar = (IdeMenuBar)myFrame.getJMenuBar(); + frameMenuBar.onToggleFullScreen(state); + } } return ActionCallback.DONE; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java index 4e74be871173..42f66e1e6235 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java @@ -600,6 +600,13 @@ public class IdeMenuBar extends JMenuBar implements IdeEventQueue.EventDispatche } } + public void onToggleFullScreen(boolean isFullScreen) { + if (myGlobalMenuLinux == null) + return; + + myGlobalMenuLinux.toggle(!isFullScreen); + } + private static class MyExitFullScreenButton extends JButton { private MyExitFullScreenButton() { setFocusable(false);