diff --git a/bin/linux/libdbm64.so b/bin/linux/libdbm64.so index 8d0864502783..d8fa66c6b661 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 42e0b70773fc..2d35071a0ae0 100644 --- a/native/LinuxGlobalMenu/DbusMenuWrapper.c +++ b/native/LinuxGlobalMenu/DbusMenuWrapper.c @@ -65,7 +65,7 @@ static void _printWndInfo(const WndInfo *wi, char *out, int outLen) { return; } - snprintf(out, outLen, "xid=0x%X menuPath='%s' registrar=0x%p server=0x%p menuroot=0x%p", wi->xid, wi->menuPath, + snprintf(out, (size_t)outLen, "xid=0x%X menuPath='%s' registrar=0x%p server=0x%p menuroot=0x%p", wi->xid, wi->menuPath, wi->registrar, wi->server, wi->menuroot); } @@ -163,7 +163,7 @@ static void _releaseMenuItem(gpointer data) { } } -static void _unregisterWindow(long xid, GDBusProxy * registrar) { +static void _unregisterWindow(guint32 xid, GDBusProxy * registrar) { // NOTE: sync call g_dbus_proxy_call_sync(wi->registrar, "UnregisterWindow", g_variant_new("(u)", wi->xid), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error) // under ubuntu18 (with GlobalMenu plugin) executes several minutes. // We make async call and don't care about results and errors (i.e. NULL callbacks) @@ -200,7 +200,7 @@ static void _releaseWindow(WndInfo *wi) { _unregisterWindow(wi->xid, wi->registrar); if (wi->linkedXids != NULL) { for (GList* l = wi->linkedXids; l != NULL; l = l->next) - _unregisterWindow(l->data, wi->registrar); + _unregisterWindow((guint32)l->data, wi->registrar); } g_object_unref(wi->registrar); @@ -240,7 +240,7 @@ void createMenuRootForWnd(WndInfo *wi) { dbusmenu_server_set_root(wi->server, wi->menuroot); } -WndInfo *registerWindow(long windowXid, jeventcallback handler) { +WndInfo *registerWindow(guint32 windowXid, jeventcallback handler) { // _info("register new window"); WndInfo *wi = (WndInfo *) malloc(sizeof(WndInfo)); @@ -248,7 +248,7 @@ WndInfo *registerWindow(long windowXid, jeventcallback handler) { wi->xid = (guint32) windowXid; wi->menuPath = malloc(64); - sprintf(wi->menuPath, "/com/canonical/menu/0x%lx", windowXid); + sprintf(wi->menuPath, "/com/canonical/menu/0x%x", windowXid); wi->menuroot = dbusmenu_menuitem_new(); if (wi->menuroot == NULL) { @@ -305,7 +305,7 @@ WndInfo *registerWindow(long windowXid, jeventcallback handler) { return wi; } -void bindNewWindow(WndInfo * wi, long windowXid) { +void bindNewWindow(WndInfo * wi, guint32 windowXid) { if (wi == NULL || wi->server == NULL || wi->menuPath == NULL) return; @@ -326,10 +326,10 @@ void bindNewWindow(WndInfo * wi, long windowXid) { } // _logmsg(LOG_LEVEL_INFO, "bind new window 0x%lx", windowXid); - wi->linkedXids = g_list_append(wi->linkedXids, windowXid); + wi->linkedXids = g_list_append(wi->linkedXids, (gpointer)windowXid); } -void unbindWindow(WndInfo * wi, long windowXid) { +void unbindWindow(WndInfo * wi, guint32 windowXid) { if (wi == NULL || wi->server == NULL || wi->menuPath == NULL) return; @@ -337,7 +337,7 @@ void unbindWindow(WndInfo * wi, long windowXid) { _unregisterWindow(windowXid, wi->registrar); if (wi->linkedXids != NULL) - wi->linkedXids = g_list_remove(wi->linkedXids, windowXid); + wi->linkedXids = g_list_remove(wi->linkedXids, (gpointer)windowXid); } static gboolean _execReleaseWindow(gpointer user_data) { @@ -390,8 +390,9 @@ static const char *_type2str(int type) { return "sig-shown"; case SIGNAL_CHILD_ADDED: return "sig-child-added"; + default: + return "unknown event type"; } - return "unknown event type"; } static void _handleItemSignal(DbusmenuMenuitem *item, int type) { @@ -479,7 +480,7 @@ DbusmenuMenuitem *addMenuItem(DbusmenuMenuitem *parent, int uid, const char * la if (position < 0) dbusmenu_menuitem_child_append(parent, item); else - dbusmenu_menuitem_child_add_position(parent, item, position); + dbusmenu_menuitem_child_add_position(parent, item, (guint)position); } return item; @@ -494,16 +495,23 @@ DbusmenuMenuitem* addSeparator(DbusmenuMenuitem * parent, int uid, int position) if (position < 0) dbusmenu_menuitem_child_append(parent, item); else - dbusmenu_menuitem_child_add_position(parent, item, position); + dbusmenu_menuitem_child_add_position(parent, item, (guint)position); } return item; } -void reorderMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item, int position) { dbusmenu_menuitem_child_reorder(parent, item, position); } +void reorderMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item, int position) { dbusmenu_menuitem_child_reorder(parent, item, (guint)position); } void removeMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item) { dbusmenu_menuitem_child_delete(parent, item); } +static gboolean _showMenuItem(gpointer item) { + dbusmenu_menuitem_show_to_user(item, 0); + return FALSE; +} + +void showMenuItem(DbusmenuMenuitem* item) { g_idle_add(_showMenuItem, item); } + void setItemLabel(DbusmenuMenuitem *item, const char *label) { dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, label); } @@ -513,14 +521,8 @@ void setItemEnabled(DbusmenuMenuitem *item, bool isEnabled) { } void setItemIcon(DbusmenuMenuitem *item, const char *iconBytesPng, int iconBytesCount) { - const gboolean propreturn = dbusmenu_menuitem_property_set_byte_array(item, DBUSMENU_MENUITEM_PROP_ICON_DATA, - (guchar *) iconBytesPng, iconBytesCount); + dbusmenu_menuitem_property_set_byte_array(item, DBUSMENU_MENUITEM_PROP_ICON_DATA, (guchar*)iconBytesPng, (gsize)iconBytesCount); // NOTE: memory copied (try to call memset(iconBytesPng, 0, iconBytesCount) after) - -// if (propreturn) -// _logmsg(LOG_LEVEL_INFO, "\tset %d icon bytes for item %s", iconBytesCount, _getItemLabel(item)); -// else -// _logmsg(LOG_LEVEL_ERROR, "\tcan't set %d icon bytes for item %s", iconBytesCount, _getItemLabel(item)); } // java modifiers @@ -530,7 +532,7 @@ static const int META_MASK = 1 << 2; static const int ALT_MASK = 1 << 3; void setItemShortcut(DbusmenuMenuitem *item, int jmodifiers, int x11keycode) { - char* xname = XKeysymToString(x11keycode); + char* xname = XKeysymToString((KeySym)x11keycode); if (xname == NULL) { // _logmsg(LOG_LEVEL_ERROR, "XKeysymToString returns null for x11keycode=%d", x11keycode); return; diff --git a/native/LinuxGlobalMenu/DbusMenuWrapper.h b/native/LinuxGlobalMenu/DbusMenuWrapper.h index 42264b053749..e10dc7add3cb 100644 --- a/native/LinuxGlobalMenu/DbusMenuWrapper.h +++ b/native/LinuxGlobalMenu/DbusMenuWrapper.h @@ -39,11 +39,11 @@ void runMainLoop(jlogger jlogger, jrunnable onAppmenuServiceAppeared, jrunnable void execOnMainLoop(jrunnable run); -WndInfo* registerWindow(long windowXid, jeventcallback handler); // creates menu-server and binds to xid +WndInfo* registerWindow(guint32 windowXid, jeventcallback handler); // creates menu-server and binds to xid void releaseWindowOnMainLoop(WndInfo* wi, jrunnable onReleased); -void bindNewWindow(WndInfo * wi, long windowXid); -void unbindWindow(WndInfo * wi, long windowXid); +void bindNewWindow(WndInfo * wi, guint32 windowXid); +void unbindWindow(WndInfo * wi, guint32 windowXid); void createMenuRootForWnd(WndInfo *wi); void clearRootMenu(WndInfo* wi); @@ -55,6 +55,7 @@ DbusmenuMenuitem* addSeparator(DbusmenuMenuitem * parent, int uid, int position) void reorderMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item, int position); void removeMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item); +void showMenuItem(DbusmenuMenuitem* item); void setItemLabel(DbusmenuMenuitem* item, const char * label); void setItemEnabled(DbusmenuMenuitem* item, bool isEnabled); 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 0b85dd9d5ce0..f5ebb5b28d6d 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 @@ -5,6 +5,7 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.ProcessOutput; import com.intellij.execution.util.ExecUtil; +import com.intellij.ide.IdeEventQueue; import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; @@ -30,6 +31,7 @@ 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; @@ -63,6 +65,7 @@ interface GlobalMenuLib extends Library { void reorderMenuItem(Pointer parent, Pointer item, int position); void removeMenuItem(Pointer parent, Pointer item); + void showMenuItem(Pointer item); void setItemLabel(Pointer item, String label); void setItemEnabled(Pointer item, boolean isEnabled); @@ -208,6 +211,37 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (myIsDisposed) ourInstances.remove(myXid); }; + + if (SystemInfo.isKDE) { + // root menu items doesn't catch mnemonic shortcuts (in KDE), so process them inside IDE + IdeEventQueue.getInstance().addDispatcher(e -> { + if (!(e instanceof KeyEvent)) + return false; + + final KeyEvent event = (KeyEvent)e; + if (!event.isAltDown()) + return false; + + final Component src = event.getComponent(); + final Window wndParent = src instanceof Window ? (Window)src : SwingUtilities.windowForComponent(src); + final char eventChar = Character.toUpperCase(event.getKeyChar()); + + for (GlobalMenuLinux gml: ourInstances.values()) { + if (gml.myFrame == wndParent) { + for (MenuItemInternal root : gml.myRoots) { + if (eventChar == root.mnemonic) { + ourLib.showMenuItem(root.nativePeer); + return false; + } + } + return false; + } + } + + return false; + }, this); + } + ourInstances.put(myXid, this); } @@ -652,6 +686,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { String txt; String originTxt; + char mnemonic; boolean isEnabled = true; boolean isChecked = false; byte[] iconPngBytes; @@ -714,7 +749,19 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { void setLabelFromSwingPeer(@NotNull JMenuItem peer) { // exec at EDT originTxt = peer.getText(); - txt = _buildMnemonicLabel(peer); + txt = originTxt != null ? originTxt : ""; + mnemonic = 0; + + if (originTxt != null && !originTxt.isEmpty()) { + final int mnemonicCode = peer.getMnemonic(); + final int mnemonicIndex = peer.getDisplayedMnemonicIndex(); + if (mnemonicIndex >= 0 && mnemonicIndex < originTxt.length() && Character.toUpperCase(originTxt.charAt(mnemonicIndex)) == mnemonicCode) { + final StringBuilder res = new StringBuilder(originTxt); + res.insert(mnemonicIndex, '_'); + txt = res.toString(); + mnemonic = (char)mnemonicCode; + } + } } void updateNative() { @@ -900,27 +947,6 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } - private static String _buildMnemonicLabel(JMenuItem jmenuitem) { - String text = jmenuitem.getText(); - final int mnemonicCode = jmenuitem.getMnemonic(); - final int mnemonicIndex = jmenuitem.getDisplayedMnemonicIndex(); - if (text == null) - text = ""; - final int index; - if (mnemonicIndex >= 0 && mnemonicIndex < text.length() && Character.toUpperCase(text.charAt(mnemonicIndex)) == mnemonicCode) { - index = mnemonicIndex; - } else { - // Mnemonic mismatch index - index = -1; - // LOG.error("Mnemonic code " + mnemonicCode + " mismatch index " + mnemonicIndex + " with txt: " + text); - } - - final StringBuilder res = new StringBuilder(text); - if(index != -1) - res.insert(index, '_'); - return res.toString(); - } - private static Object _getPeerField(@NotNull Component object) { try { Field field = Component.class.getDeclaredField("peer");