hello icon indicating copy to clipboard operation
hello copied to clipboard

Match windows to their .app bundles

Open probonopd opened this issue 4 years ago • 15 comments

Currently there is no easy way to find out which application bundle a given window belongs to. In fact, there seems not even to be a simple way to find out which executable a given window belongs to.

We need to change this, so that we can e.g., retrieve the matching icon or application name for agiven window from the application bundle.

cc @mszoek


LD_PRELOAD can be used to set custom WM_NAME properties on applications' windows.

Can we use that to match windows to their .app bundles?

https://github.com/dasJ/spotifywm/blob/master/spotifywm.cpp

probonopd avatar Jul 18 '21 10:07 probonopd

Even easier:

RESOURCE_NAME=xxxxxxxxxxxxxxxxxxx  /Applications/FeatherPad.app/FeatherPad

Results in xprop showing:

WM_CLASS(STRING) = "xxxxxxxxxxxxxxxxxxx", "FeatherPad"

And e.g., Menu picks the first one up:

probono: WM_CLASS "xxxxxxxxxxxxxxxxxxx"

probonopd avatar Jul 18 '21 10:07 probonopd

RESOURCE_NAME=/Applications/FeatherPad.app launch FeatherPad

works: We get /Applications/FeatherPad.app as the first WM_CLASS(STRING).

probonopd avatar Jul 18 '21 10:07 probonopd

Possibly we can use this mechanism to keep the launch animation for an application in the Dock running until the first window with the same WM_CLASS appears.

probonopd avatar Jul 18 '21 10:07 probonopd

Apparently this does not work for Gtk apps:

RESOURCE_NAME=xxxxxxxxxxxxx launch /usr/local/bin/system-config-printer

xprop still shows

WM_CLASS(STRING) = "system-config-printer", "System-config-printer.py"

Aaaargh!

probonopd avatar Jul 18 '21 10:07 probonopd

Somehow KDE managed to hack in its own properties:

_KDE_NET_WM_APPMENU_OBJECT_PATH(STRING) = "/MenuBar/2"
_KDE_NET_WM_APPMENU_SERVICE_NAME(STRING) = "org.kde.plasma.gmenu_dbusmenu_proxy"
_KDE_NET_WM_ACTIVITIES(STRING) = "00000000-0000-0000-0000-000000000000"

So (how) can we hack in something like _APPLICATION_BUNDLE or even _APPLICATION_EXECUTABLE?

Looks like the Inter-Client Communication Conventions Manual (ICCM) is the relevant spec.

But it reads very dated. For example, they are talking about "octets" instead of strings.

So the simple question is: How does one set additional Atoms when launching an application.

According to https://unix.stackexchange.com/a/495125 one can set it with

xprop -name "ma_window" -f WM_TRUC 8s -set WM_TRUC "The_Truc"

xprop -name "ma_window" WM_TRUC
WM_TRUC(STRING) = "The_Truc"

but for that, the window must already be there. Instead, we want to set it by exporting an environment variable or derive it from readlink -f /proc/self/exe or something like that.

probonopd avatar Jul 18 '21 10:07 probonopd

_NET_WM_PID as defined by EWMH seems to come close?

FreeBSD% xprop | grep PID
_NET_WM_PID(CARDINAL) = 71894
FreeBSD% ps ax | grep 71894
71894  -  S      0:07,56 /usr/local/bin/falkon

But in this case, we still don't get the application bundle that was used to launch the process, because in this (special) case, the process does not live inside the application bundle that launched it.

probonopd avatar Jul 18 '21 10:07 probonopd

This is the very same problem that caused me to drop development of my DockBarX (dock panel for Linux) many years ago, It took too many workarounds for everything to work properly. There is no way to find a creator of some window in terms of X11 protocol. There was a whole separate daemon for this task in Ubuntu - BAMF daemon. I'm not sure if it is still exists nowadays, or some another replacement has been made for this component. I think it is much better to solve this problem from the launch command, like set environment variable on the start. Probably for this you will need to introduce some restrictions, for example, no wrappers, only real applications inside their .app directories.

Can we move (or pkg install) all applications to their .app directories? Is it possible? If it is not possible due to changing paths, is it possible to use Jail (or something like that) to trick pkg install. I don't know if mount namespaces exist in FreeBSD.

ls0h avatar Jul 18 '21 17:07 ls0h

The way I envison it:

  • Every GUI application on helloSystem is supposed to go through the launch command
  • The launch command, before actually executing the GUI application, is responsible for setting the metadata on the process
  • The only question is how to do this. Looks like using LD_PRELOAD might work universally (but is an ugly overhead) so I am looking for an easier way

probonopd avatar Jul 18 '21 18:07 probonopd

Well, if you had some sort of manifest file in the app bundle, like info.plist, then you can add a window manager class property that launch reads and tells the dock about. You can also have localised app names.

kettle-7 avatar Jul 18 '21 20:07 kettle-7

The way I envison it:

You can simply set an environment variable (e.g. APP_PATH), and force all applications to be placed in their .app directories and forbid other behavior. Or use something like Jail for each application, so the application will be in its own directory inside /Applications, but at the same time will see itself in /usr/local. In the second case, it will be possible to use all applications without breaking compatibility. They will behave as installed with pkg install.

In addition, if I understand correctly how macOS works, the application may be running, but not have any windows, just an icon in the dock. Accordingly, if you want to implement such behavior, then you cannot rely on the X11 related protocols, like EWMH.

ls0h avatar Jul 18 '21 21:07 ls0h

You can simply set an environment variable (e.g. APP_PATH), and force all applications to be placed in their .app directories and forbid other behavior.

I don't want to have this restriction because it would render all "placeholder app bundles" unusable.

In addition, if I understand correctly how macOS works, the application may be running, but not have any windows, just an icon in the dock. Accordingly, if you want to implement such behavior, then you cannot rely on the X11 related protocols, like EWMH.

Ideally, we would attach our metadata to processes (PIDs). Windows can be resolved to PIDs easily. Thinking more about it, just exporting an environment variable is probably sufficient?

We can get it back by using procstat -e <pid>.

probonopd avatar Jul 19 '21 06:07 probonopd

Can't ps find the parent process?

kettle-7 avatar Jul 19 '21 21:07 kettle-7

launch is now setting LAUNCHED_EXECUTABLE and LAUNCHED_BUNDLE.

probonopd avatar Jul 21 '21 06:07 probonopd

Can't ps find the parent process?

How would that help?

probonopd avatar Jul 21 '21 06:07 probonopd

You keep going up the tree, to the parent of the parent and so on until you reach an AppRun.

Environment variables are probably cleaner.

kettle-7 avatar Jul 21 '21 07:07 kettle-7

Using environment variables set by launch now.

probonopd avatar Nov 12 '22 21:11 probonopd