Java in Linux - different look and feel classes for root and non-root
Asked Answered
C

2

6

I noticed that Java proposes different look and feel classes for root and non-root users. I am trying to understand how to make LAF consistent. Moreover, it's inconsistent even within a user/root: depends on how user/root logged in:

Sample code (compiled and packaged in laf.jar):

import javax.swing.UIManager;

public class laf {
    public static void main(java.lang.String[] args) {
        try {
            System.out.print(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
    }
}

Scenario 1 Logs in to machine (in GUI mode) as a regular user

Sample output (as user)

[xxx@yyy Downloads]$ java -classpath laf.jar laf
com.sun.java.swing.plaf.gtk.GTKLookAndFeel

Sample output (switch to root via su)

[root@yyy Downloads]# java -classpath ./laf.jar laf
javax.swing.plaf.metal.MetalLookAndFeel

Scenario 2 Logs in to machine (in GUI mode) as root

Sample output (as root)

[root@yyy Downloads]# java -classpath ./laf.jar laf
com.sun.java.swing.plaf.gtk.GTKLookAndFeel

Scenario 3 Logs in to machine via SSH as a regular user (similar as scenario #1 above, but in this case - same LAF)

Sample output (as user)

[xxx@yyy Downloads]$ java -classpath laf.jar laf
javax.swing.plaf.metal.MetalLookAndFeel

Sample output (switch to root)

[root@yyy Downloads]# java -classpath ./laf.jar laf
javax.swing.plaf.metal.MetalLookAndFeel

Software versions:

[root@yyy Downloads]# java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build pxa6470sr9fp10-20150708_01(SR9 FP10))
IBM J9 VM (build 2.6, JRE 1.7.0 Linux amd64-64 Compressed References     20150701_255667 (JIT enabled, AOT enabled)
J9VM - R26_Java726_SR9_20150701_0050_B255667
JIT  - tr.r11_20150626_95120.01
GC   - R26_Java726_SR9_20150701_0050_B255667_CMPRSS
J9CL - 20150701_255667)
JCL - 20150628_01 based on Oracle jdk7u85-b15

[root@yyy Downloads]# cat /etc/redhat-release 
Red Hat Enterprise Linux Workstation release 6.7 (Santiago)
Clemmer answered 16/11, 2015 at 12:58 Comment(5)
This may come from a difference in the user's environment; try and see the result of env for different scenarios, or in Java, use the result of System.getenv().Basketball
Can you check, in your various settings, whether you have the variable GNOME_DESKTOP_SESSION_ID in your environment?Oxendine
1) as user it said "this-is-depricated" 2) after "su -" as root it gave blank outputClemmer
If you want a consistent cross-platform look, you may want to stick with the Nimbus theme or UIManager.getCrossPlatformLookAndFeelClassName().Disc
Nimbus was created to a be nicer-looking cross-platform L&F, but for whatever reason, was never updated to be the default.Disc
F
0

The first line of getSystemLookAndFeelClassName is:

public static String getSystemLookAndFeelClassName() {
    String systemLAF = AccessController.doPrivileged(
                         new GetPropertyAction("swing.systemlaf"));

So you can use the JAVA_OPTS of the user to set

-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel

As default.

add this to the .rc-File of the user:

set JAVA_OPTS=-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel
export JAVA_OPTS

Regards

Factual answered 16/11, 2015 at 13:12 Comment(3)
Sure, I will try with properties, but I am surprised it's not working out of box.Clemmer
Modifying at user level (bashrc or profile) was not an option, as we don't control it and don't want our application affect system. So, my solution is to add in application's startup script a fragment "-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel"Clemmer
Make a note com.sun.javax.swing.plaf.metal.CrossPlatformLookAndFeel is not available in IBM JRE I am using. So it's not a cross-platform solution. I still recommend to use what I mentioned in the previous comment: javax.swing.plaf.metal.MetalLookAndFeelClemmer
O
4

This is less about root, and more about environment variables.

Basically, the UIManager.getSystemLookAndFeelClassName method works like this:

  • Check the swing.systemlaf system property. This allows the user to override whatever the system wants to choose. If it is not null, it's used.
  • Otherwise, if the operating system is Windows, it returns the WindowsLookAndFeel.
  • Otherwise, it checks the sun.desktop property. If sun.desktop is set to gnome, and GTK is available natively, it returs the GTKLookAndFeel
  • Otherwise, checks for Mac OS X and Solaris and returns appropriate values for these operating systems.
  • If all other checks failed, it returns the "cross platform" L&F, which is MetalLookAndFeel.

So, the part that is relevant to Linux/Unix is the part that checks sun.desktop. This property is set when the JVM starts up. It is set to gnome if the environment variable GNOME_DESKTOP_SESSION_ID exists, ignoring its contents, and it is set to null otherwise. I believe this is the pertinent native source code that does this.

So, on Linux, if that environment variable is set (and GTK is available), your L&F will be set to GTKLookAndFeel. If not, it will be set to MetalLookAndFeel.

When you log in to a Gnome-based Linux using the desktop manager, your environment will have that variable set. But the su command does not propagate environment variables by default. Thus, when you su to any user, not necessarily root, you lose the GNOME_DESKTOP_SESSION_ID environment variable, and Java will default to MetalLookAndFeel.

You can cause your environment to be passed through su by using su -p, or if you are using sudo, using sudo -E.

The ssh command, like su and sudo, does not propagate environment variables. This can also be worked around using ~/.ssh/environment.

However, as already stated - you can easily force a specific L&F by passing the -Dswing.systemlaf=... switch to the java command.

Oxendine answered 16/11, 2015 at 15:55 Comment(5)
Thanks for explanation, as I said above GNOME_DESKTOP_SESSION_ID did not contain anything meaningful. My option was to explicitly define LAF via -DClemmer
BTW, that problem was observed also on Ubuntu OS 12.04.02. Surprisingly, on Ubuntu I get exactly same results: as user it said echo echo $GNOME_DESKTOP_SESSION_ID => "this-is-depricated", and as root - blank output, and different LAFs as user and root.Clemmer
@BaratSahdzijeu It doesn't have to contain anything meaningful. It just has to exist to pick the GTK L&F. And yes, Ubuntu is Gnome-based Linux.Oxendine
This helps to explain the problem but does not offer a scalable solution which matches that of the desktop behavior. For example, if an installer wants to launch a Java process in user space afterward, how does one obtain the user's environmental variables without forcing the user to provide switches to the sudo command which invoked in the installer? In the case of one particular installer the sudo -u command is used for launching the process in user space, so the environmental variables are hidden by sudo twice. How can an installer accommodate this scenario?Vesuvian
How does anyone ever find anything in the OpenJDK source tree, mutter, mutter? The code's still there, in hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/java.base/unix/…, even though GNOME_DESKTOP_SESSION_ID has been deprecated since 2008 (bugzilla.gnome.org/show_bug.cgi?id=542880). Gnome still sets it, presumably thanks to the fix for that bug - to "this-is-deprecated" - so why was I getting the Metal LAF? Because I'd started Java from an xterm that I start before gnome-session, just in case. Makes perfect sense, thanks to @RealSkeptic.Alphanumeric
F
0

The first line of getSystemLookAndFeelClassName is:

public static String getSystemLookAndFeelClassName() {
    String systemLAF = AccessController.doPrivileged(
                         new GetPropertyAction("swing.systemlaf"));

So you can use the JAVA_OPTS of the user to set

-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel

As default.

add this to the .rc-File of the user:

set JAVA_OPTS=-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel
export JAVA_OPTS

Regards

Factual answered 16/11, 2015 at 13:12 Comment(3)
Sure, I will try with properties, but I am surprised it's not working out of box.Clemmer
Modifying at user level (bashrc or profile) was not an option, as we don't control it and don't want our application affect system. So, my solution is to add in application's startup script a fragment "-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel"Clemmer
Make a note com.sun.javax.swing.plaf.metal.CrossPlatformLookAndFeel is not available in IBM JRE I am using. So it's not a cross-platform solution. I still recommend to use what I mentioned in the previous comment: javax.swing.plaf.metal.MetalLookAndFeelClemmer

© 2022 - 2024 — McMap. All rights reserved.