0

Trying to port to Ubuntu my SWT application that works fine in Windows, I have encountered an issue with overlay scrollbars. When I run the application from under Eclipse, everything is OK, scrollbars look and behave normally. But when I pack the application into a JAR and execute this JAR, the scrollbars in the application will become "overlay scrollbars" and look like thin orange strips, and the scrollbar events, that I need to handle, are supposed to have some strange field values, so that my app totally ignore them. This is unacceptable for me, it's important for my app to handle the scrollbars in a special, non-standard way, so I need normal look of the scrollbars and normal events from them.

This issue can easily be mended by adding export LIBOVERLAY_SCROLLBAR=0 to the ~/.profile, but I don't want to force the end users to make custom system settings in order to run my application, I want them to be able to run it just by clicking on the JAR without any special efforts.

I'm new in programming for Linux, and I dont't know how to set up the environment programmatically. Placing

  System.setProperty("LIBOVERLAY_SCROLLBAR", "0"); 

in the beginning of my code has no effect, neither has

  new ProcessBuilder("export LIBOVERLAY_SCROLLBAR=0").start();

How do I disable this "overlay scrollbars" from my code?

P.S. Solutions for any other language perhaps may be a clue, too

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
m. vokhm
  • 669
  • 1
  • 6
  • 24

2 Answers2

1

Changing an environment variable of the current process (your java program) is difficult and may not always work. What you can do though, is distribute a shell script with your jar that people on Linux can use to start your application. Something like this should do the trick:

#!/bin/sh

export LIBOVERLAY_SCROLLBAR=0
java -jar yourjar.jar
Baz
  • 36,440
  • 11
  • 68
  • 94
  • Thanks! That's what I've done so far, yet I still hope to find a more graceful solution. – m. vokhm Feb 06 '17 at 11:13
  • @m.vokhm Well, if you do, please come back and post it as an answer here. – Baz Feb 06 '17 at 11:19
  • sorry, I can't mark this answer as accepted, since 1) its not an exact answer for my question (I asked about programmatical way), and 2) I still hope somebody may suggest another solution – m. vokhm Feb 06 '17 at 15:09
  • 1
    @m.vokhm Nobody asked you to accept my answer. All I said is you should come back and post an answer if you find a solution. – Baz Feb 06 '17 at 15:27
  • Yes, of course I will ! (English is not my native, so misunderstandings happen occasionally) – m. vokhm Feb 07 '17 at 07:30
  • I have found a solution and posted it below. – m. vokhm Feb 10 '17 at 14:04
0

There exist ways to set environment variables for the currently running VM, for example like this:

    private static void setEnv(Map<String, String> newEnv) throws Exception {
      Map<String, String> env = System.getenv();
      Class<?> cl = env.getClass();
      Field field = cl.getDeclaredField("m");
      field.setAccessible(true);
      @SuppressWarnings("unchecked")
      Map<String, String> envMap = (Map<String, String>) field.get(env);
      envMap.putAll(newEnv);
    }

(the idea is taken from the answers at How do I set environment variables from Java?)

Yet in my case I need the env vars to affect the libraries that are executed outside the VM, so this method does not solve my problem.

After thinking a little I have realized that I want to set environment for the parent process of the JVM, so I need first to set the required variables and then recursively run another JVM instance that would execute my app -- then the variables would affect the libraries even though their code is executed outside the VM.

So the logic should be as the following:

 if (required vars are absent) {
   start a process that {
     set required vars;
     run another instance of the JVM with the application inside; 
   }
   exit; 
 }
 // here the vars already set 
 do whatever we need in the proper environment

As it comes to Java, the code may look like this:

public class SecondVM {
  public static void main(String[] args)  {
    if (    System.getenv("SWT_GTK3") == null
         || System.getenv("LIBOVERLAY_SCROLLBAR") == null )  
    { 
      URL classResource = SecondVM.class.getResource("SecondVM.class");
      boolean fromJar = classResource.getProtocol().equals("rsrc");

      String exePath = ClassLoader.getSystemClassLoader().getResource(".").getPath();
      exePath =  new File(exePath).getAbsolutePath().replaceFirst("\\.$", "").replaceFirst("bin$", "");
      if (!exePath.endsWith(System.getProperty("file.separator")))
        exePath += System.getProperty("file.separator");

      String[] script = {
          "/bin/bash", "-c",
          "export SWT_GTK3=0; "
           + "export LIBOVERLAY_SCROLLBAR=0; "
           + (fromJar? // TODO: Put the proper paths, packages and class names here
              "java -jar " + exePath + "SecondVM.jar" :         // if runs from jar
              "java -cp ./bin/:../ExtLibs/swt_linux64/swt.jar " // if runs from under Eclipse or somewhat alike 
              + "com.m_v.test.SecondVM")
      };

      try {
        Process p = new ProcessBuilder(script).start();

        // When jar is run from a bash script, it kills the second VM when exits.
        // Let it has some time to take a breath
        p.waitFor(12, TimeUnit.HOURS);
      } catch (Exception e) { e.printStackTrace(); }
      System.exit(0);
    }

    // Now the env vars are OK. We can use SWT with normal scrollbars    
    Display display = Display.getDefault();
    // .... do watever we need 
  }
}

In case of running the jar from a shell script, we have to wait for the child process to finish, before exiting the original process, so this solution leads to an overhead of running two instances of JVM simultaneously. If there is no need to provide a possibility to run it from a script, the p.waitFor(12, TimeUnit.HOURS); may be replaced with p.waitFor(12, TimeUnit.MILLISECONDS); or, perhaps, removed at all (I have not tested without it), so we can have a single instance of JVM, like with a usual Java program.

A working snippet with a text widget and a scrollbar is at http://ideone.com/eRjePQ

Community
  • 1
  • 1
m. vokhm
  • 669
  • 1
  • 6
  • 24