mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
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:
Binary file not shown.
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user