Commit 47b0afad authored by Artem Bochkarev's avatar Artem Bochkarev
Browse files

linux-menu: fixed mnemonics processing under KDE

process key-events (for mnemonic shortcuts) within ide
parent 0e5c3453
Branches unavailable Tags unavailable
No related merge requests found
Showing with 75 additions and 46 deletions
+75 -46
No preview for this file type
......@@ -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;
......
......@@ -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);
......
......@@ -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");
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment