helloSystem / Menu

Global menu bar written in Qt
43 stars 14 forks source link

Make global menu work for JetBrains (Java) applications #33

Open probonopd opened 3 years ago

probonopd commented 3 years ago

Make global menu work for JetBrains (Java) applications: bring the contents of (1) into (2). This will also make the commands searchable via the search field in the global menu and the system-wide ⌘+Space, which large IDEs like the ones from JetBrains would benefit from.

image

How?

image

probonopd commented 3 years ago

https://youtrack.jetbrains.com/issue/IDEA-169904

IntelliJ 2020.1.4 is last version global menu supported

rilian commented on 2020-11-15 10:23

Jetbrains apps does not need jayatana. They support appmenus natively.

Possibly helpful

alexandreliberato commented 3 years ago

Maybe it is a good idea to check that issue https://youtrack.jetbrains.com/issue/IDEA-169904

probonopd commented 3 years ago

Installing libdbusmenu pkg did not seem to make any difference.

LD_DEBUG=libs truss /usr/local/bin/pycharm-ce 2>&1 | grep menu

outputs nothing, indicating that no files/libraries with "menu" in their name are even attempted to be opened...

probonopd commented 3 years ago

Also see https://github.com/rilian-la-te/vala-panel-appmenu#experimental-features

JAyatana allows for displaying global menus in Java Swing applications. Because Vala-Panel-Appmenu uses the unity-gtk-module backend, this should theoretically work with JAyatana, although applications such as Netbeans and the JetBrains suite of IDEs require some configuration, which you can figure out with a cursory internet search.

probonopd commented 2 years ago

JetBrains IntelliJ code refers to Global Menu in this commit. So can it be enabled in JetBrains IDEs? How?

probonopd commented 2 years ago

Watching the output of dbus-monitor, I can't see jetBrains PyCharm to send any menu information via D-Bus. Maybe it is checking for some condition which helloSystem does not meet (yet) and hence doesn't even attempt to send menu information via D-Bus?

Yet somewhere deep inside there is AppMenu related code:

FreeBSD% grep -r AppMenu /usr/local/share/pycharm-ce/ 
Binary file /usr/local/share/pycharm-ce/lib/platform-impl.jar matches

FreeBSD% grep -r GlobalMenu /usr/local/share/pycharm-ce/                      
Binary file /usr/local/share/pycharm-ce/lib/platform-impl.jar matches
Binary file /usr/local/share/pycharm-ce/lib/resources.jar matches

FreeBSD% strings /usr/local/share/pycharm-ce/lib/platform-impl.jar | grep AppMenu
5Closed dbus-service 'com.canonical.AppMenu.Registrar'
7Appeared dbus-service 'com.canonical.AppMenu.Registrar'
$AppMenu-service can't register xid 
doBindAppMenuOfParent
installAppMenuIfNeeded
doInstallAppMenuIfNeeded
com/intellij/openapi/wm/impl/LinuxIdeMenuBar$Companion$doBindAppMenuOfParent$1.class
Ncom/intellij/openapi/wm/impl/LinuxIdeMenuBar$Companion$doBindAppMenuOfParent$1
doBindAppMenuOfParent
PLcom/intellij/openapi/wm/impl/LinuxIdeMenuBar$Companion$doBindAppMenuOfParent$1;
doBindAppMenuOfParent
Ncom/intellij/openapi/wm/impl/LinuxIdeMenuBar$Companion$doBindAppMenuOfParent$1
doInstallAppMenuIfNeeded
doBindAppMenuOfParent
installAppMenuIfNeeded
installAppMenuIfNeeded
installAppMenuIfNeeded
com/intellij/openapi/wm/impl/LinuxIdeMenuBar$Companion$doBindAppMenuOfParent$1.classPK

This code seems to be related: https://github.com/JetBrains/intellij-community/search?q=GlobalMenuLinux

And especially: https://github.com/JetBrains/intellij-community/blob/584913b212d4e92347d9b925f2f417fcc0dee439/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java#L790

    if (!SystemInfo.isLinux ||

Can it really be that they hardcoded the global menu not to show if the platform is not Linux, effectively disabling the global menu on BSD, even though all prerequisites are met?

Is this something that could be changed by e.g., using LD_PRELOAD?

probonopd commented 2 years ago

This should be fixed upstream. Can we do something in the meantime?

Assuming we could get com/intellij/openapi/wm/impl/GlobalMenuLinux.class inside /usr/local/share/pycharm-ce/lib/platform-impl.jar patched so that it doesn't check for Linux by the virtues of something like https://jdec.app/, is there a way to get it loaded instead of the one in the jar?

https://www.py4u.net/discuss/632477 says:

Write your own class in the same package as the original one, make sure your classes are before the 3-rd party jar on the java classpath. This way you will override the original version, class loader will load your class.

mkdir -p /tmp/com/intellij/openapi/wm/impl/patch/
cp GlobalMenuLinux.class /tmp/patch/com/intellij/openapi/wm/impl/patch/
FreeBSD% /usr/local/openjdk12//bin/java -classpath /tmp/:/usr/local/share/pycharm-ce/lib/bootstrap.jar:/usr/local/share/pycharm-ce/lib/util.jar:/usr/local/share/pycharm-ce/lib/jdom.jar:/usr/local/share/pycharm-ce/lib/log4j.jar:/usr/local/share/pycharm-ce/lib/jna.jar -Xms128m -Xmx1258m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -XX:CICompilerCount=2 -Dsun.io.useCanonPrefixCache=false -Djdk.http.auth.tunneling.disabledSchemes="" -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Djdk.attach.allowAttachSelf=true -Dkotlinx.coroutines.debug=off -Djdk.module.illegalAccess.silent=true -Dawt.useSystemAAFontSettings=lcd -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine -Dsun.tools.attach.tmp.only=true -XX:ErrorFile=/home/user/java_error_in_pycharm_%p.log -XX:HeapDumpPath=/home/user/java_error_in_pycharm_.hprof -Didea.vendor.name=JetBrains -Didea.paths.selector=PyCharmCE2021.1 -Djb.vmOptionsFile=/home/user/.config/JetBrains/PyCharmCE2021.1/pycharm64.vmoptions -Didea.platform.prefix=PyCharmCore com.intellij.idea.Main

We are up to something? @jsm222 what do you think?

probonopd commented 2 years ago

Upstream ticket opened: https://youtrack.jetbrains.com/issue/PY-51727

probonopd commented 1 year ago

Upstream doesn't want to make this change "without any testing". Even though I am sure FreeBSD users would be happy to test.

If we knew what syscall is used by SystemInfo.isLinux, we could possibly overwrite it using LD_PRELOAD...

probonopd commented 1 year ago

They are definitely running uname, but the following does not do the trick - there may be more to it. I was hoping that by changing the output of uname we could trick SystemInfo.isLinux, but it is not entirely clear whether this succeeded. We need to see whether we can get global menus to work with any Java application that uses the same GUI toolkit as Jetbrains.

sudo mv /usr/bin/uname /usr/bin/uname.original

Then create and make executable the following script as /usr/bin/uname:

#!/bin/bash

echo ""
echo "Script name: $0" >> /tmp/info
echo "Number of arguments: $#" >> /tmp/info
echo "Arguments: $@" >> /tmp/info

/usr/bin/uname.disabled "$@" | sed  -e 's|FreeBSD|Linux|g'

By looking at /tmp/info after running a JetBrains IDE we see the accesses.

osbre commented 1 year ago

I remember using Xubuntu with xfce4-appmenu-plugin a couple of years ago and the JetBrains IDE (PHPStorm) was working with a global menu.

probonopd commented 1 year ago

They hardcoded the global menu not to show if the platform is not Linux, effectively disabling the global menu on BSD, even though all prerequisites are met.

osbre commented 1 year ago

Trying to understand their reasoning for doing that. Would it mean that once removed it could break their macOS and Windows versions?

Perhaps in this case they have to invert it from : !SystemInfo.isLinux to: (pseudocode) !(SystemInfo.isWindows || SystemInfo.isDarwin)

And also, they have the word "Linux" all over the place in that implementation. Out of curiosity, what the proper name would be? (for example, GlobalMenuDbus instead of GlobalMenuLinux?)

probonopd commented 1 year ago

Out of curiosity, what the proper name would be?

Great question.

This stuff is under-documented and under-specified. https://github.com/unity8-team/libdbusmenu-qt calls it the "DBusMenu protocol".

The specification used to be at https://people.canonical.com/~agateau/dbusmenu/spec/index.html but the link is dead as of 2020. On https://agateau.com/2009/statusnotifieritem-and-dbusmenu/ it is described as: "The goal of DBusMenu is to make it possible for applications using the StatusNotifierItem spec to send their menus over DBus, so that the workspace can display them in a consistent way, regardless of whether the application is written using Qt, GTK or another toolkit."

Here is a collection of what information I could gather so far: https://hellosystem.github.io/docs/developer/menu

jsm222 commented 1 year ago

Trying to understand their reasoning for doing that. Would it mean that once removed it could break their macOS and Windows versions?

I also think we will be missing this linux blob https://github.com/JetBrains/intellij-community/blob/584913b212d4e92347d9b925f2f417fcc0dee439/bin/linux/libdbm64.so UPDATE perhaps not Update Update they do not ship a FreeBSD version of that lib.. But It might be portable from intellij-community-202.7660/native/LinuxGlobalMenu

jsm222 commented 1 year ago

IntelliJ 2020.1.4 is last version global menu supported

I tested on Linux with helloSystem's Menu, and 2023.2 intellij-ce gets global menus.. Now I only have left to hack and build the source..

jsm222 commented 1 year ago

Okay after a lot of stack tracing and building jna and intelij froms source and sqlite and libdb.so and jetbrains fork of libdbusmenu... ideangmenu

I will share the details later...

probonopd commented 1 year ago

WOW, this is awesome!

jsm222 commented 1 year ago

I will share the details later...

Some of them are here https://youtrack.jetbrains.com/issue/IDEA-283161

osbre commented 1 year ago

@jsm222 Very cool. Is it possible to submit that git-diff as a PR and they would accept it?

jsm222 commented 1 year ago

@jsm222 Very cool. Is it possible to submit that git-diff as a PR and they would accept it?

https://github.com/JetBrains/intellij-community/pull/2571

I will share the details later...

Here are the rest of the details https://github.com/jsm222/LinuxGlobalMenu