linux-menubar: fixed IDEA-201286 Linux Native Menu bar: the order of actions in menu...
authorArtem Bochkarev <artem.bochkarev@jetbrains.com>
Sun, 11 Nov 2018 10:26:38 +0000 (17:26 +0700)
committerArtem Bochkarev <artem.bochkarev@jetbrains.com>
Mon, 12 Nov 2018 12:08:20 +0000 (19:08 +0700)
bin/linux/libdbm64.so
native/LinuxGlobalMenu/DbusMenuWrapper.c
native/LinuxGlobalMenu/DbusMenuWrapper.h
platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java

index 3216b4a25b433cd1c9fcdacef96122ca19392469..7fc851dcc1112708391218f5da7debb0d7cd4879 100755 (executable)
Binary files a/bin/linux/libdbm64.so and b/bin/linux/libdbm64.so differ
index ca6e964600c41c630b38ae2f9fc719d718d6d81a..2601e201381dbffce4d8b515ec2f8dc9e708dc41 100644 (file)
@@ -439,10 +439,10 @@ DbusmenuMenuitem *addRootMenu(WndInfo *wi, int uid, const char * label) {
   if (wi == NULL || wi->menuroot == NULL)
     return NULL;
   // _logmsg(LOG_LEVEL_INFO, "add root %d", uid);
-  return addMenuItem(wi->menuroot, uid, label, true);
+  return addMenuItem(wi->menuroot, uid, label, true, -1);
 }
 
-DbusmenuMenuitem *addMenuItem(DbusmenuMenuitem *parent, int uid, const char * label, int type) {
+DbusmenuMenuitem *addMenuItem(DbusmenuMenuitem *parent, int uid, const char * label, int type, int position) {
   // _logmsg(LOG_LEVEL_INFO, "add menu item %s (%d) [p %s]", label, uid, _getItemLabel(parent));
 
   DbusmenuMenuitem *item = dbusmenu_menuitem_new();
@@ -469,23 +469,32 @@ DbusmenuMenuitem *addMenuItem(DbusmenuMenuitem *parent, int uid, const char * la
     if (data == NULL)
       _logmsg(LOG_LEVEL_ERROR, "parent of item %d hasn't jhandler", uid);
     g_object_set_data(G_OBJECT(item), MENUITEM_JHANDLER_PROPERTY, data);
-    dbusmenu_menuitem_child_append(parent, item);
+    if (position < 0)
+      dbusmenu_menuitem_child_append(parent, item);
+    else
+      dbusmenu_menuitem_child_add_position(parent, item, position);
   }
 
   return item;
 }
 
-DbusmenuMenuitem* addSeparator(DbusmenuMenuitem * parent, int uid) {
+DbusmenuMenuitem* addSeparator(DbusmenuMenuitem * parent, int uid, int position) {
   DbusmenuMenuitem* item = dbusmenu_menuitem_new();
   dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TYPE, "separator");
   dbusmenu_menuitem_property_set_int(item, MENUITEM_UID_PROPERTY, uid);
   dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-  if (parent != NULL)
-    dbusmenu_menuitem_child_append(parent, item);
+  if (parent != NULL) {
+    if (position < 0)
+      dbusmenu_menuitem_child_append(parent, item);
+    else
+      dbusmenu_menuitem_child_add_position(parent, item, position);
+  }
 
   return item;
 }
 
+void reorderMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item, int position) { dbusmenu_menuitem_child_reorder(parent, item, position); }
+
 void removeMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item) { dbusmenu_menuitem_child_delete(parent, item); }
 
 void setItemLabel(DbusmenuMenuitem *item, const char *label) {
index 82bdda4267385a4c7057cf40bab86f1704c528f9..f1b459d23292274b073fddd92345d586da196795 100644 (file)
@@ -50,9 +50,10 @@ void clearRootMenu(WndInfo* wi);
 void clearMenu(DbusmenuMenuitem* menu);
 
 DbusmenuMenuitem* addRootMenu(WndInfo* wi, int uid, const char * label);
-DbusmenuMenuitem* addMenuItem(DbusmenuMenuitem * parent, int uid, const char * label, int type);
-DbusmenuMenuitem* addSeparator(DbusmenuMenuitem * parent, int uid);
+DbusmenuMenuitem* addMenuItem(DbusmenuMenuitem * parent, int uid, const char * label, int type, int position);
+DbusmenuMenuitem* addSeparator(DbusmenuMenuitem * parent, int uid, int position);
 
+void reorderMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item, int position);
 void removeMenuItem(DbusmenuMenuitem * parent, DbusmenuMenuitem* item);
 
 void setItemLabel(DbusmenuMenuitem* item, const char * label);
index b3e14b2898d26f0fdc990e5e0b04f60b1552a885..d02c815b7517a960752b6aa4ca97843817aaa107 100644 (file)
@@ -54,9 +54,10 @@ interface GlobalMenuLib extends Library {
   void clearMenu(Pointer dbmi);
 
   Pointer addRootMenu(Pointer wi, int uid, String label);
-  Pointer addMenuItem(Pointer parent, int uid, String label, int type);
-  Pointer addSeparator(Pointer wi, int uid);
+  Pointer addMenuItem(Pointer parent, int uid, String label, int type, int position);
+  Pointer addSeparator(Pointer wi, int uid, int position);
 
+  void reorderMenuItem(Pointer parent, Pointer item, int position);
   void removeMenuItem(Pointer parent, Pointer item);
 
   void setItemLabel(Pointer item, String label);
@@ -379,22 +380,24 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
     // 1. mark all kids to delete
     mi.clearChildrenSwingRefs();
     for (MenuItemInternal cmi: mi.children)
-      cmi.toDelete = true;
+      cmi.position = -1; // mark item to be deleted
     if (stats != null) stats[STAT_DELETED] += mi.children.size();
 
     // 2. check all children from ActionMenu
+    int itemPos = 0;
     for (Component each : am.getPopupMenu().getComponents()) {
       MenuItemInternal cmi = mi.findCorrespondingChild(each);
       if (cmi == null) {
         cmi = _createInternalFromSwing(each);
         if (cmi != null) {
+          cmi.position = itemPos++;
           mi.children.add(cmi);
           if (stats != null) ++stats[STAT_CREATED];
           if (each instanceof JMenuItem)
             cmi.updateBySwingPeer((JMenuItem)each);
         }
       } else {
-        cmi.toDelete = false;
+        cmi.position = itemPos++;
         if (stats != null) --stats[STAT_DELETED];
         if (each instanceof JMenuItem) {
           final boolean changed = cmi.updateBySwingPeer((JMenuItem)each);
@@ -413,24 +416,40 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
     if (mi.nativePeer == null)
       return;
 
-    for (MenuItemInternal child: mi.children) {
+    // sort
+    mi.children.sort((i0, i1) -> i0.position - i1.position);
+
+    // remove marked items
+    Iterator<MenuItemInternal> i = mi.children.iterator();
+    while (i.hasNext()) {
+      final MenuItemInternal child = i.next();
+      if (child.position != -1)
+        break;
+
       if (child.nativePeer != null) {
-        if (child.toDelete) {
-          ourLib.removeMenuItem(mi.nativePeer, child.nativePeer);
-          child.nativePeer = null;
-        } else {
-          child.updateNative();
-        }
-      } else {
+        ourLib.removeMenuItem(mi.nativePeer, child.nativePeer);
+        child.nativePeer = null;
+      }
+      i.remove();
+    }
+
+    // update/create and reorder
+    for (int pos = 0; pos < mi.children.size(); ++pos) {
+      final MenuItemInternal child = mi.children.get(pos);
+
+      if (child.nativePeer == null) {
         if (child.action == null) {
-          child.nativePeer = ourLib.addSeparator(mi.nativePeer, child.uid);
+          child.nativePeer = ourLib.addSeparator(mi.nativePeer, child.uid, pos);
           continue;
         }
 
-        child.nativePeer = ourLib.addMenuItem(mi.nativePeer, child.uid, child.txt, child.type);
-        child.updateNative();
+        child.nativePeer = ourLib.addMenuItem(mi.nativePeer, child.uid, child.txt, child.type, child.position);
+      } else if (child.position != pos) {
+        // System.out.printf("reorder: '%s' [%d] -> [%d]\n", child, child.position, pos);
+        ourLib.reorderMenuItem(mi.nativePeer, child.nativePeer, child.position);
       }
 
+      child.updateNative();
       _processChildren(child);
     }
   }
@@ -566,7 +585,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
 
     JMenuItem jitem;
     Pointer nativePeer;
-    boolean toDelete = false;
+    int position = -1;
 
     long lastClosedMs = 0;
 
@@ -649,7 +668,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
 
       if (target instanceof JSeparator) {
         for (MenuItemInternal child : children)
-          if (child.toDelete && child.action == null)
+          if (child.position == -1 && child.action == null)
             return child;
         return null;
       }
@@ -720,14 +739,14 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable {
     @Override
     public String toString() {
       String res = String.format("'%s' (uid=%d, act=%s)", txt, uid, String.valueOf(action));
-      if (toDelete)
+      if (position == -1)
         res = res + " [toDelele]";
       return res;
     }
 
     String toStringShort() {
       String res = String.format("'%s'", txt);
-      if (toDelete)
+      if (position == -1)
         res = res + " [D]";
       if (isRoot())
         res = "Root " + res;