linux-menubar: show swing-menu in full screen mode

fixed IDEA-201291 Linux Native menu bar: if 'windows-style' menu (i.e. located on the window title bar) is used, menu can't be used in the Full Screen mode
This commit is contained in:
Artem Bochkarev
2018-11-15 16:50:32 +07:00
parent 63e45a8cf2
commit 0eee89e393
6 changed files with 90 additions and 19 deletions
Binary file not shown.
+8 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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);
@@ -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<Long, GlobalMenuLinux> ourInstances = new ConcurrentHashMap<>();
@@ -119,8 +118,11 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
private final @NotNull JFrame myFrame;
private List<MenuItemInternal> 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<ActionMenu> 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) {
@@ -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;
}
@@ -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);