Icons for Python or Java

Icons for Python or Java

  • mdo  DigitalBox
  •   Dev
  •   January 17, 2025

In this article, let's review how to handle icons for Python or Java applications in Haiku.

Standard way

The standard way to have an icon to an application is to attach the BEOS:ICON attribute like described in the "Attach icon to app" article.

When the application is launched, its icon is visible in the Deskbar menu, like Genio below:

The icon can also be useful for LaunchBox :

Python way

Let's suppose you have created a new Python application under Haiku, like the PyHelloHaiku reviewed in Use Python and Haiku API article.

Now let's attach to this application an icon :

seticon ./sun.hvif ./PyHelloHaiku

Note : seticon() is my user defined function (in profile):

seticon()
{
  if [ $# -ne 2 ]; then
  echo "Usage: seticon "
  return 1
  fi
  addattr -f "$1" -t icon BEOS:ICON "$2"
}

Looking at the Tracker, the icon is correctly attached to the program :

However when you launch the python application, the Deskbar will display the generic icon :

And the application's name is overridden with "python3.10"

How to change that ?

You will need to launch the command :

addattr -t mime "BEOS:TYPE" application/x-vnd.be-elfexecutable /boot/home/Documents/Python/PyHelloHaiku/PyHelloHaiku

This command indicates that the program is an executable file. Now let's relaunch the program via the Tracker :

Nice it's working fine !

You can also add the application in LaunchBox, and it will work as expected :

Last point :

if you launch the application from the Terminal :

The "python3.10" with a generic icon will be displayed again :/

To avoid this, you can add the "open" command just before your application call :

In this case it's working as well :)

Java way

The java case was hard to resolve.

The solution proposed below is what I've found so far, as the best compromise.

Let's suppose, you're using the Squirrel SQL client - which is a java program.

The way to call the program is to have the launch script below :

As you might expect, the Tracker will display this application as "java" :

What about creating a C++ wrapper application, which will do the same than the bash script, ie calling the java program with the corresponding arguments needed to launch the Squirrel application ?

For that create the below C++ application with Pe editor :

lpe SquirrelSQL.cpp &

And paste the C++ code :

#include <Application.h>
#include <Alert.h>
#include <MessageRunner.h>

#include <unistd.h>
#include <iostream>
#include <csignal>
#include <sys/wait.h>
#include <filesystem>

#define APP_SIGNATURE "application/x-vnd.squirrel"
#define JAVA_JAR "/boot/home/config/non-packaged/apps/squirrelsql/squirrel-sql.jar"

class JavaLauncherApp : public BApplication {
public:
JavaLauncherApp()
: BApplication(APP_SIGNATURE), childPid(-1) {}

virtual void ReadyToRun() override {
  childPid = fork();
  if (childPid == 0) {
  std::string JAVA_BIN = FindJava();
  if (JAVA_BIN.empty()) {
  std::cerr << "Error: Unable to find Java executable. Please ensure Java is installed " << std::endl;
  exit(1);
}

// Execute child process corresponding to the JAR
if (execlp(JAVA_BIN.c_str(), JAVA_BIN.c_str(), "-jar", JAVA_JAR, nullptr) == -1) {
  std::cerr << "Error: unable to execute the JAR file." << std::endl;
  exit(1); // Terminate the child process if execlp fails
}
} else if (childPid < 0) {
  std::cerr << "Error: unable to create child process." << std::endl;
  exit(1);
} else {
  // Start a MessageRunner to check the child's status
  StartMessageRunner();
}
}

virtual void Quit() override {
  if (childPid > 0) {
  // Wait for child process to finish
  int status;
  pid_t result = waitpid(childPid, &status, WNOHANG); // Non-blocking wait
  if (result == childPid) {
  // Child process already exited
  } else if (result == -1) {
  // Error while waiting for child process
  } else {
  // Child is still running, send SIGTERM
  kill(childPid, SIGTERM);
waitpid(childPid, &status, 0); // Block here to ensure proper termination
  }
}

BApplication::Quit();
}

void StartMessageRunner() {
  // Post a periodic message every 1s to check if the child is still running
  BMessage* message = new BMessage('chdl'); 
messageRunner = new BMessageRunner(this, message, 1000000); // 1s interval
}

virtual void MessageReceived(BMessage* message) override {
  if (message->what == 'chdl') {
  int status;
  pid_t result = waitpid(childPid, &status, WNOHANG); // Non-blocking check for child status
  if (result == childPid) {
  PostMessage(B_QUIT_REQUESTED); // Notify parent to quit
  delete messageRunner; 
  }
} else {
  BApplication::MessageReceived(message);
}
}

private:
pid_t childPid;
BMessageRunner* messageRunner;

// Search JAVA from JAVA_HOME environment variable 
std::string FindJavaWithEnv() {
  const char* javaHome = std::getenv("JAVA_HOME");
  if (javaHome) {
  std::string javaPath = std::string(javaHome) + "/bin/java";
  if (std::filesystem::exists(javaPath)) {
  return javaPath;
  }
}

return ""; 
}

// Search JAVA in PATH
std::string FindJavaInPath() {
  const char* pathEnv = std::getenv("PATH");
  if (!pathEnv) {
  return "";
}

std::string pathStr(pathEnv);
std::istringstream pathStream(pathStr);
std::string dir;

// Scan for directories in PATH
while (std::getline(pathStream, dir, ':')) {
  std::filesystem::path javaPath = std::filesystem::path(dir) / "java";

  // Check if java command
  if (std::filesystem::exists(javaPath)) {
  return javaPath.string();
  }
  }

  return ""; 
}

// Search for JAVA 
std::string FindJava() {
// JAVA_HOME method
std::string javaPath = FindJavaWithEnv();
if (!javaPath.empty()) {
return javaPath;
}

// PATH folders 
javaPath = FindJavaInPath();
if (!javaPath.empty()) {
return javaPath;
}

return ""; 
}

};

int main() {
JavaLauncherApp app;
app.Run();
return 0;
}


This wrapper is doing the below :

  • The application's signature is defined by the APP_SIGNATURE value
  • Identify where the "java" binary is located (via JAVA_HOME or PATH)
  • Launch the "java" commands with the correct arguments ("-jar <JAVA_JAR>") as a child process
  • When quitting :
    • If child process quit, then the parent child will quit also
    • If parent process quit, then the child will quit too

I'm not sure the part to identify the java location is required, because when the "openjdkxxx_default" package is installed on Haiku, then the "/bin/java" symlink is created.

Now let's compile it and attach an icon :

g++ SquirrelSQL.cpp -o SquirrelSQL -lbe
seticon /boot/home/Documents/Java/squirrel.hvif /boot/home/Documents/Java/SquirrelSQL

Double click on the SquirrelSQL application :

As you can see, the SquirrelSQL application name and icon is visible in the Tracker !

The java part is still there also, but that's the current compromise to do.

When quitting the application, you can :

  • Quit the main SquirrelSQL application via the Tracker menu : it will also quit the "java" child process

  • Quit the java child via the Tracker menu (Close all) : it will also quit the main "SquirrelSQL" application

  • Quit the java child via the java application window : it will also quit the main "SquirrelSQL" application

With this C++ wrapper, it makes Java applications a little bit more clearer in the Deskbar and you can also have dedicated icon for you application in LaunchBox :

Now let's do the same for DB Visualizer :

  • Indicate the APP_SIGNATURE
  • Indicate the classname to be called (DbVisualizerGUI) via the JAVA_JAR define

In the case of DB Visualizer, the arguments used by the "java" program is containing more entries like below :

Let's compile it and attach a nice icon :

g++ ./DBVisualizer.cpp -o DBVisualizer -lbe
seticon ./DBVisualizer.hvif ./DBVisualizer

In the Tracker, double click on "DBVisualizer" but also on "SquirrelSQL":

It's working fine !

Each application has its dedicated icon. The "java" part is now including the child for DBVisualizer but also SquirrelSQL :

If you close each java application via the close icon, it will close the parent application as well :)

And now you can add your favorite icons into LaunchBox :

I hope you find this article useful, and that in case of Java or Python applications, you should be able to associate now some nice icons.


Powered by Bludit - Hosted by Planet Hoster
© 2025 Haiku Insider