package javaforce.linux;
/**
* Created : Mar 12, 2012
*
* @author pquiring
*/
import java.util.*;
import java.io.*;
import javaforce.*;
import javaforce.jni.*;
/**
* Common functions for Linux administration.
*/
public class Linux {
/** Returns jfLinux ISO version. */
public static String getVersion() {
return "15";
}
public static enum DistroTypes {
Unknown, Ubuntu, Fedora
};
public static DistroTypes distro = DistroTypes.Unknown;
public static String ubuntuRelease, ubuntuCodename;
/**
* Detects Linux distribution type. (Support Ubuntu, Fedora currently)
*/
public static boolean detectDistro() {
if (distro != DistroTypes.Unknown) {
return true;
}
try {
//Ubuntu : /etc/lsb-release
File lsb = new File("/etc/lsb-release");
if (lsb.exists()) {
FileInputStream fis = new FileInputStream(lsb);
Properties props = new Properties();
props.load(fis);
fis.close();
String id = props.getProperty("DISTRIB_ID");
if (id.equals("Ubuntu")) {
distro = DistroTypes.Ubuntu;
ubuntuRelease = props.getProperty("DISTRIB_RELEASE");
ubuntuCodename = props.getProperty("DISTRIB_CODENAME");
return true;
}
}
//Fedora : /etc/fedora-release
File fedora = new File("/etc/fedora-release");
if (fedora.exists()) {
FileInputStream fis = new FileInputStream(fedora);
byte data[] = JF.readAll(fis);
fis.close();
String str = new String(data);
if (str.indexOf("Fedora") != -1) {
distro = DistroTypes.Fedora;
return true;
}
}
} catch (Exception e) {
JFLog.log(e);
}
return false;
}
public static boolean ubuntuAddRepo(String ppa) {
ShellProcess sp = new ShellProcess();
sp.removeEnvironmentVariable("TERM");
sp.addEnvironmentVariable("DEBIAN_FRONTEND", "noninteractive");
String output = sp.run(new String[] {"sudo", "-E", "add-apt-repository", ppa}, true);
if (output == null) {
return false;
} else {
return true;
}
}
/**
* Creates folder as root
*/
public static boolean mkdir(String folder) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("mkdir");
cmd.add("-p");
cmd.add(folder);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec mkdir");
return false;
}
if (output.length() > 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
/**
* Copies src to dst as root
*/
public static boolean copyFile(String src, String dst) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("cp");
cmd.add(src);
cmd.add(dst);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec cp");
return false;
}
if (output.length() > 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
/**
* Creates Link to Target as root
*/
public static boolean createLink(String target, String link) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("ln");
cmd.add("-s");
cmd.add(target);
cmd.add(link);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec ln");
return false;
}
if (output.length() > 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
/**
* Deletes file as root
*/
public static boolean deleteFile(String file) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("rm");
cmd.add("-f");
cmd.add(file);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec ln");
return false;
}
if (output.length() > 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
/**
* Restarts a service
*/
public static boolean restartService(String name) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("service");
cmd.add(name);
cmd.add("restart");
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec service");
return false;
}
if (sp.getErrorLevel() != 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
/**
* Restarts a JF service
*/
public static boolean restartJFService(String name) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("jservice");
cmd.add(name);
cmd.add("restart");
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec jservice");
return false;
}
if (sp.getErrorLevel() != 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
public static boolean ubuntuUpdate() {
ShellProcess sp = new ShellProcess();
sp.removeEnvironmentVariable("TERM");
sp.addEnvironmentVariable("DEBIAN_FRONTEND", "noninteractive");
String output = sp.run(new String[] {"sudo", "-E", "apt-get", "--yes", "update"}, true);
if (output == null) {
return false;
} else {
return true;
}
}
/**
* Work with Ubuntu packages.
*/
private static boolean apt(String action, String pkg, String desc) {
JFTask task = new JFTask() {
public boolean work() {
this.setProgress(-1);
String action = (String)this.getProperty("action");
String pkg = (String)this.getProperty("pkg");
String desc = (String)this.getProperty("desc");
setLabel((action.equals("install") ? "Installing " : "Removing ") + desc);
ShellProcess sp = new ShellProcess();
sp.removeEnvironmentVariable("TERM");
sp.addEnvironmentVariable("DEBIAN_FRONTEND", "noninteractive");
String output = sp.run(new String[]{"sudo", "-E", "apt-get", "--yes", action, pkg}, true);
if (output == null) {
setLabel("Failed to exec apt-get");
JFLog.log("Failed to exec apt-get");
return false;
}
if (output.indexOf("Unable to locate package") != -1) {
setLabel("Package not found");
JFLog.log("Package not found");
return false;
}
setLabel("Complete");
setProgress(100);
return true;
}
};
task.setProperty("action", action);
task.setProperty("pkg", pkg);
task.setProperty("desc", desc);
new ProgressDialog(null, true, task).setVisible(true);
return task.getStatus();
}
/**
* Work with Fedora packages.
*/
private static boolean yum(String action, String pkg, String desc) {
JFTask task = new JFTask() {
public boolean work() {
this.setProgress(-1);
String action = (String)this.getProperty("action");
String pkg = (String)this.getProperty("pkg");
String desc = (String)this.getProperty("desc");
setLabel((action.equals("install") ? "Installing " : "Removing ") + desc);
ShellProcess sp = new ShellProcess();
sp.removeEnvironmentVariable("TERM"); //prevent config dialogs
String output = sp.run(new String[]{"sudo", "-E", "yum", "-y", action, pkg}, false);
if (output == null) {
setLabel("Failed to exec yum");
JFLog.log("Failed to exec yum");
return false;
}
setLabel("Complete");
setProgress(100);
return true;
}
};
task.setProperty("action", action);
task.setProperty("pkg", pkg);
task.setProperty("desc", desc);
new ProgressDialog(null, true, task).setVisible(true);
return task.getStatus();
}
public static boolean installPackage(String pkg, String desc) {
detectDistro();
switch (distro) {
case Ubuntu:
return apt("install", pkg, desc);
case Fedora:
return yum("install", pkg, desc);
}
return false;
}
public static boolean removePackage(String pkg, String desc) {
detectDistro();
switch (distro) {
case Ubuntu:
return apt("autoremove", pkg, desc);
case Fedora:
return yum("remove", pkg, desc);
}
return false;
}
/**
* Sets file as executable as root
*/
public static boolean setExec(String file) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("sudo");
cmd.add("chmod");
cmd.add("+x");
cmd.add(file);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Failed to exec chmod");
return false;
}
if (output.length() > 0) {
JFLog.log("Error:" + output);
return false;
}
return true;
}
private static String pkgList[][];
/* public static String[][] getPackages() {
if (dpkg == null) updateInstalled();
return dpkg;
}*/
private static String[][] ubuntu_searchPackages(String regex) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("apt-cache");
cmd.add("search");
cmd.add(regex);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Error:unable to execute apt-cache");
return null;
}
String lns[] = output.split("\n");
String ret[][] = new String[lns.length][2];
String f[];
for (int a = 0; a < lns.length; a++) {
f = lns[a].split(" - ");
if (f.length != 2) {
continue;
}
ret[a][0] = f[0]; //package name
ret[a][1] = f[1]; //package desc
}
return ret;
}
private static String[][] fedora_searchPackages(String regex) {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("yum");
cmd.add("search");
cmd.add(regex);
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Error:unable to execute yum");
return null;
}
String lns[] = output.split("\n");
String ret[][] = new String[lns.length][2];
String f[];
for (int a = 0; a < lns.length; a++) {
f = lns[a].split(" : ");
if (f.length != 2) {
continue;
}
ret[a][0] = f[0]; //package name
ret[a][1] = f[1]; //package desc
}
return ret;
}
/**
* Searches for available packages (NOTE:There may be nulls in the output)
*/
public static String[][] searchPackages(String regex) {
detectDistro();
switch (distro) {
case Ubuntu:
return ubuntu_searchPackages(regex);
case Fedora:
return fedora_searchPackages(regex);
}
return null;
}
public static void ubuntu_updateInstalled() {
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("dpkg");
cmd.add("-l");
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Error:unable to execute dpkg");
return;
}
String lns[] = output.split("\n");
pkgList = new String[lns.length - 5][3];
String f[];
for (int a = 5; a < lns.length; a++) {
f = lns[a].split(" +", 4); //greedy spaces
pkgList[a - 5][0] = f[1]; //package name
pkgList[a - 5][1] = f[3]; //package desc
pkgList[a - 5][2] = (f[0].charAt(0) == 'i' ? "true" : "false"); //package installed?
}
}
public static void fedora_updateInstalled() {
//NOTE:can't use "rpm -qa" because the version # is mangled in the name
ShellProcess sp = new ShellProcess();
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("yum");
cmd.add("list");
cmd.add("installed");
String output = sp.run(cmd, false);
if (output == null) {
JFLog.log("Error:unable to execute yum");
return;
}
String lns[] = output.split("\n");
pkgList = new String[lns.length - 2][3];
for (int a = 2; a < lns.length; a++) {
String f[] = lns[a].split(" +"); //greedy spaces
if (f.length != 3) {
pkgList[a-2][0] = "";
pkgList[a-2][1] = "";
pkgList[a-2][2] = "";
continue;
}
int idx = f[0].lastIndexOf("."); //strip arch
if (idx == -1) {
pkgList[a-2][0] = f[0]; //package name
} else {
pkgList[a-2][0] = f[0].substring(0, idx); //package name
}
pkgList[a-2][1] = f[1]; //package desc
pkgList[a-2][2] = "true"; //package installed?
}
}
public static void updateInstalled() {
detectDistro();
switch (distro) {
case Ubuntu:
ubuntu_updateInstalled();
break;
case Fedora:
fedora_updateInstalled();
break;
}
}
public static boolean isInstalled(String pkg) {
if (pkg == null) {
return true;
}
if (pkgList == null) {
updateInstalled();
}
for (int a = 0; a < pkgList.length; a++) {
if (pkgList[a][0].equals(pkg)) {
return pkgList[a][2].equals("true");
}
}
return false;
}
public static String getPackageDesc(String pkg) {
if (pkg == null) {
return "";
}
if (pkgList == null) {
updateInstalled();
if (pkgList == null) {
return "";
}
}
for (int a = 0; a < pkgList.length; a++) {
if (pkgList[a][0].equals(pkg)) {
return pkgList[a][1];
}
}
return "";
}
public static boolean isMemberOf(String user, String group) {
try {
ShellProcess sp = new ShellProcess();
String output = sp.run(new String[]{"groups", user}, false).replaceAll("\n", "");
//output = "user : group1 group2 ..."
String groups[] = output.split(" ");
for (int a = 2; a < groups.length; a++) {
if (groups[a].equals(group)) {
return true;
}
}
return false;
} catch (Exception e) {
JFLog.log(e);
return false;
}
}
private static String expandQuotes(String inString) {
while (true) {
int i1 = inString.indexOf('\"');
if (i1 == -1) {
return inString;
}
int i2 = inString.indexOf('\"', i1 + 1);
if (i2 == -1) {
return inString;
}
inString = inString.substring(0, i1) + inString.substring(i1 + 1, i2).replace(' ', '\u1234') + inString.substring(i2 + 1);
}
}
private static String[] expandBackslash(String inString) {
StringBuilder out = new StringBuilder();
char inCA[] = inString.toCharArray();
for (int a = 0; a < inCA.length; a++) {
if (inCA[a] == '\\') {
if (inCA[a + 1] == '\\') {
if (inCA[a + 2] == '\\') {
if (inCA[a + 3] == '\\') {
out.append('\\');
out.append('\\');
a += 3;
continue;
}
} else if (inCA[a + 2] == ' ') {
out.append('\u1234');
a += 2;
continue;
} else {
out.append('\\');
a++;
continue;
}
}
}
out.append(inCA[a]);
}
String cmd[] = out.toString().split(" ");
for (int a = 0; a < cmd.length; a++) {
if (cmd[a].indexOf('\u1234') != -1) {
cmd[a] = cmd[a].replace('\u1234', ' ');
}
}
return cmd;
}
/**
* Currently only supports %f,%F,%u,%U
*/
public static String[] expandDesktopExec(String exec, String file) {
if (file == null) {
file = "";
}
file = '\"' + file + '\"';
exec = exec.replaceAll("%f", file);
exec = exec.replaceAll("%F", file);
exec = exec.replaceAll("%u", file);
exec = exec.replaceAll("%U", file);
exec = expandQuotes(exec);
return expandBackslash(exec);
}
/**
* Currently only supports %f,%F,%u,%U
*/
public static String[] expandDesktopExec(String exec, String file[]) {
String files = "";
if (file != null) {
for (int a = 0; a < file.length; a++) {
if (a > 0) {
files += " ";
}
files += '\"' + file[a] + '\"';
}
} else {
file = new String[1];
file[0] = "";
}
exec = exec.replaceAll("%f", '\"' + file[0] + '\"');
exec = exec.replaceAll("%F", files);
exec = exec.replaceAll("%u", '\"' + file[0] + '\"');
exec = exec.replaceAll("%U", files);
exec = expandQuotes(exec);
return expandBackslash(exec);
}
public static boolean executeDesktop(String desktop, String file[]) {
try {
Properties props = new Properties();
FileInputStream fis = new FileInputStream(desktop);
props.load(fis);
fis.close();
String exec = props.getProperty("Exec");
String path = props.getProperty("Path");
if (path == null || path.length() == 0) {
path = System.getenv("HOME");
if (path == null || path.length() == 0) {
path = "/";
}
}
ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File(path));
String expand[] = expandDesktopExec(exec, file);
pb.command(expand);
pb.start();
return true;
} catch (Exception e) {
JFLog.log(e);
return false;
}
}
public static int detectBits() {
if (new File("/usr/lib64").exists()) {
return 64;
}
return 32;
}
/**
* Runs a bash script as root
*/
public static boolean runScript(String lns[]) {
try {
File tmpFile = File.createTempFile("script", ".sh", new File("/tmp"));
FileOutputStream fos = new FileOutputStream(tmpFile);
fos.write("#!/bin/bash\n".getBytes());
for (int a = 0; a < lns.length; a++) {
fos.write((lns[a] + "\n").getBytes());
}
fos.close();
tmpFile.setExecutable(true);
ShellProcess sp = new ShellProcess();
String output = sp.run(new String[]{"sudo", tmpFile.getAbsolutePath()}, true);
tmpFile.delete();
return sp.getErrorLevel() == 0;
} catch (Exception e) {
JFLog.log(e);
return false;
}
}
private static final int None = 0;
private static final int CurrentTime = 0;
private static final int ShiftMask = 1;
private static final int True = 1;
private static final int False = 0;
private static final int KeyPress = 2;
private static final int KeyRelease = 3;
private static final int CreateNotify = 16;
private static final int DestroyNotify = 17;
private static final int UnmapNotify = 18;
private static final int MapNotify = 19;
private static final int ReparentNotify = 21;
private static final int ConfigureNotify = 22;
private static final int PropertyNotify = 28;
private static final int ClientMessage = 33;
private static final int KeyPressMask = 1;
private static final int KeyReleaseMask = (1 << 1);
private static final int StructureNotifyMask = (1 << 17);
private static final int SubstructureNotifyMask = (1 << 19);
private static final int PropertyChangeMask = (1 << 22);
public static boolean init() {
return true;
}
public static long x11_get_id(java.awt.Window w) {
return LnxNative.x11_get_id(w);
}
public static void x11_set_desktop(long xid) {
LnxNative.x11_set_desktop(xid);
}
public static void x11_set_dock(long xid) {
LnxNative.x11_set_dock(xid);
}
public static void x11_set_strut(long xid, int panelHeight, int x, int y, int width, int height) {
LnxNative.x11_set_strut(xid, panelHeight,x,y,width,height);
}
//tray functions
public static void x11_set_listener(X11Listener cb) {
LnxNative.x11_set_listener(cb);
}
/** Polls and dispatches tray events. Does not return until x11_tray_stop() is called. */
public static void x11_tray_main(long pid, int screenWidth, int trayPos, int trayHeight) {
LnxNative.x11_tray_main(pid, screenWidth, trayPos, trayHeight);
}
/** Repositions tray icons and the tray window itself.
*
* @param screenWidth = new screen width (-1 = has not changed)
*/
public static void x11_tray_reposition(int screenWidth, int trayPos, int trayHeight) {
LnxNative.x11_tray_reposition(screenWidth, trayPos, trayHeight);
}
/** Stops x11_tray_main() */
public static void x11_tray_stop() {
LnxNative.x11_tray_stop();
}
public static int x11_tray_width() {
return LnxNative.x11_tray_width();
}
//top-level x11 windows monitor
/** Polls and dispatches top-level windows events. Does not return until x11_window_list_stop() is called. */
public static void x11_window_list_main() {
LnxNative.x11_window_list_main();
}
public static void x11_window_list_stop() {
LnxNative.x11_window_list_stop();
//TODO : send a message to ??? to cause main() loop to abort
}
public static class Window {
public long xid;
public int pid;
public String title; //_NET_WM_NAME
public String name; //XFetchName
public String res_name, res_class;
public String file; //user defined
public long org_event_mask;
public Window(long xid, int pid, String title, String name, String res_name, String res_class) {
this.xid = xid;
this.pid = pid;
this.title = title;
this.name = name;
this.res_name = res_name;
this.res_class = res_class;
}
}
private static ArrayList<Window> currentList = new ArrayList<Window>();
private static Object currentListLock = new Object();
/** Returns list of all top-level windows.
* NOTE : x11_window_list_main() must be running.
*/
public static Window[] x11_get_window_list() {
//create a "copy" of currentList
synchronized(currentListLock) {
return currentList.toArray(new Window[0]);
}
}
//called from native code to add/update a window
private static void x11_window_add(long xid, int pid, String title, String name, String res_name, String res_class) {
Window window = new Window(xid, pid, title, name, res_name, res_class);
synchronized(currentListLock) {
int cnt = currentList.size();
for(int a=0;a<cnt;a++) {
if (currentList.get(a).xid == xid) {
currentList.set(a, window);
return;
}
}
currentList.add(window);
}
}
//called from native code to delete a window
private static void x11_window_del(long xid) {
synchronized(currentListLock) {
int cnt = currentList.size();
for(int a=0;a<cnt;a++) {
if (currentList.get(a).xid == xid) {
currentList.remove(a);
return;
}
}
}
}
public static void x11_minimize_all() {
LnxNative.x11_minimize_all();
}
public static void x11_raise_window(long xid) {
LnxNative.x11_raise_window(xid);
}
public static void x11_map_window(long xid) {
LnxNative.x11_map_window(xid);
}
public static void x11_unmap_window(long xid) {
LnxNative.x11_unmap_window(xid);
}
//x11 send event functions
public static int x11_keysym_to_keycode(char keysym) {
return LnxNative.x11_keysym_to_keycode(keysym);
}
/** Send keyboard event to window with focus. */
public static boolean x11_send_event(int keycode, boolean down) {
return LnxNative.x11_send_event(keycode, down);
}
/** Send keyboard event to specific window. */
public static boolean x11_send_event(long id, int keycode, boolean down) {
return LnxNative.x11_send_event(id, keycode, down);
}
//X11 : RandR support
public static class Size {
public String size;
public boolean active;
public boolean preferred;
}
public static class Port {
public String name;
public boolean connected;
public boolean hasActiveSize;
public boolean used; //mapped to Monitor
public ArrayList<Size> sizes = new ArrayList<Size>();
}
public static class Screen {
public int idx;
public ArrayList<Port> ports = new ArrayList<Port>();
}
public static class Monitor {
public String name;
public String res = ""; //resolution
public int rotate; //NORMAL, RIGHT, LEFT, INVERTED
public boolean mirror; //relpos ignored
public int relpos; //NONE, LEFT, RIGHT, BELOW, ABOVE, SAME
public String relName = ""; //relative to this monitor
}
public static final int P_NONE = 0; //only primary uses P_NONE
public static final int P_LEFT = 1;
public static final int P_ABOVE = 2;
public static final int P_RIGHT = 3;
public static final int P_BELOW = 4;
public static final int P_SAME = 5;
public static final int R_NORMAL = 0;
public static final int R_RIGHT = 1; //CW
public static final int R_LEFT = 2; //CCW
public static final int R_INVERTED = 3;
public static ArrayList<Screen> screens = new ArrayList<Screen>();
/** X11 : RandR : Detects current state.
* @param config = current settings (optional)
* @return new settings
*/
public static Monitor[] x11_rr_get_setup(Monitor config[]) {
//xrandr output:
//--------------
//Screen 0: minimum 1 x 1, current X x Y, maximum 8192 x 8192
//MonitorName [dis]connected XxY+0+0 [rotation] (normal left inverted right x axis y axis) 0mm x 0mm
// XxY freq*+ [freq2] (where *=current +=preferred)
//--------------
//(where rotation = right, left, inverted)
screens.clear();
Screen screen = null;
Port port = null;
Size size = null;
ArrayList<Monitor> newConfig = new ArrayList<Monitor>();
ShellProcess sp = new ShellProcess();
String output = sp.run(new String[] {"xrandr"}, false);
String lns[] = output.split("\n");
for(int a=0;a<lns.length;a++) {
if (lns[a].length() == 0) continue;
if (lns[a].startsWith("Screen ")) {
screen = new Screen();
int i1 = lns[a].indexOf(" ");
int i2 = lns[a].indexOf(":");
screen.idx = JF.atoi(lns[a].substring(i1+1, i2));
screens.add(screen);
continue;
}
if (lns[a].startsWith(" ")) {
//size / rate*+ (*=in use +=preferred)
if (port == null) {
JFLog.log("Error:XRandR size line without monitor");
continue;
}
if (!port.connected) continue; //junk info
size = new Size();
String f[] = lns[a].trim().split(" +"); //greedy spaces
size.size = f[0];
size.active = f[1].indexOf("*") != -1;
if (size.active) {
port.hasActiveSize = true;
}
size.preferred = f[1].indexOf("+") != -1 || (f.length > 2 && f[2].equals("+"));
port.sizes.add(size);
} else {
//port
port = new Port();
int i1 = lns[a].indexOf(" ");
port.name = lns[a].substring(0, i1);
port.connected = lns[a].substring(i1+1).startsWith("connected");
screen.ports.add(port);
}
}
if (config == null) config = new Monitor[0];
for(int b=0;b<screens.size();b++) {
screen = screens.get(b);
for(int c=0;c<screen.ports.size();c++) {
port = screen.ports.get(c);
if (!port.connected) continue; //ignore disconnected monitors
Monitor monitor = new Monitor();
monitor.name = port.name;
for(int a=0;a<config.length;a++) {
Monitor other = config[a];
if (other.name.equals(port.name)) {
monitor.res = other.res;
monitor.mirror = other.mirror;
monitor.relpos = other.relpos;
monitor.relName = other.relName;
monitor.rotate = other.rotate;
break;
}
}
if (monitor.res.length() == 0) {
if (port.hasActiveSize) {
//use active size
for(int s=0;s<port.sizes.size();s++) {
size = port.sizes.get(s);
if (size.active) {
monitor.res = size.size;
break;
}
}
} else {
//use prefered size
for(int s=0;s<port.sizes.size();s++) {
size = port.sizes.get(s);
if (size.preferred) {
monitor.res = size.size;
break;
}
}
}
if (monitor.res.length() == 0) {
//no active or preferred size
//use first size listed
if (port.sizes.size() > 0) {
monitor.res = port.sizes.get(0).size;
} else {
//no sizes???
JFLog.log("Warning:Monitor " + monitor.name + " has no sizes, trying 800x600");
monitor.res = "800x600"; //must use something or xrandr options will be corrupt
}
}
}
newConfig.add(monitor);
}
}
return x11_rr_arrangeMonitors(newConfig.toArray(new Monitor[0]));
}
/** Arranges monitors ensuring they all have valid positions.
* @return : the same list of monitors
*/
public static Monitor[] x11_rr_arrangeMonitors(Monitor monitors[]) {
for(int m=1;m<monitors.length;m++) {
Monitor monitor = monitors[m];
if (monitor.mirror) {
monitor.relpos = P_SAME;
//ensure mirrored monitor exists and is not a mirror itself
String mirrorName = monitor.relName;
boolean ok = false;
for(int c=0;c<monitors.length;c++) {
if (monitors[c].name.equals(mirrorName) && !monitors[c].mirror) {
ok = true;
break;
}
}
if (ok) continue;
//mirror is not valid
monitor.relpos = P_NONE;
monitor.relName = "";
}
if (monitor.relpos != P_NONE && monitor.relpos != P_SAME) {
//make sure path exists and is not circular
Monitor path = monitor;
boolean ok = true;
while (ok && path != monitors[0]) {
String parent = path.relName;
Monitor thisMonitor = path;
for(int c=0;c<monitors.length;c++) {
if (monitors[c].name.equals(parent)) {
path = monitors[c];
break;
}
}
if (thisMonitor == path) {
//parent not found
ok = false;
}
if (path == monitor) {
//circular
ok = false;
}
}
if (ok) continue;
}
Monitor rightMonitor = null;
String relName = monitors[0].name;
boolean left = false, right = false, above = false, below = false;
for(int c=1;c<monitors.length;c++) {
if (!monitors[c].name.equals(relName)) continue;
if (monitors[c].relpos == P_LEFT) left = true;
else if (monitors[c].relpos == P_RIGHT) {right = true; rightMonitor = monitors[c];}
else if (monitors[c].relpos == P_ABOVE) above = true;
else if (monitors[c].relpos == P_BELOW) below = true;
}
monitor.relName = monitors[0].name;
if (!right) monitor.relpos = P_RIGHT;
else if (!below) monitor.relpos = P_BELOW;
else if (!left) monitor.relpos = P_LEFT;
else if (!above) monitor.relpos = P_ABOVE;
else {
//need to make adj to another monitor (just keep moving right)
relName = rightMonitor.name;
boolean cont = false;
do {
cont = false;
for(int c=1;c<monitors.length;c++) {
if (!monitors[c].relName.equals(relName)) continue;
if (monitors[c].relpos == P_RIGHT) {
cont = true;
rightMonitor = monitors[c];
relName = rightMonitor.name;
break;
}
}
} while (cont);
monitor.relName = rightMonitor.name;
monitor.relpos = P_RIGHT;
}
}
return monitors;
}
/** X11 : RandR : Reconnects disconnected monitors. */
public static void x11_rr_auto() {
try {
Process p = Runtime.getRuntime().exec(new String[] {"xrandr", "--auto"});
p.waitFor();
} catch (Exception e) {
JFLog.log(e);
}
}
/** X11 : RandR : Applies config. */
public static void x11_rr_set(Monitor config[]) {
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("xrandr");
for(int a=0;a<config.length;a++) {
cmd.add("--output");
cmd.add(config[a].name);
cmd.add("--mode");
cmd.add(config[a].res);
cmd.add("--rotate");
switch (config[a].rotate) {
case R_NORMAL: cmd.add("normal"); break;
case R_LEFT: cmd.add("left"); break;
case R_RIGHT: cmd.add("right"); break;
case R_INVERTED: cmd.add("inverted"); break;
}
if (config[a].relpos != P_NONE) {
switch (config[a].relpos) {
case P_LEFT: cmd.add("--left-of"); break;
case P_RIGHT: cmd.add("--right-of"); break;
case P_ABOVE: cmd.add("--above"); break;
case P_BELOW: cmd.add("--below"); break;
case P_SAME: cmd.add("--same-as"); break;
}
cmd.add(config[a].relName);
}
}
/*
for(int a=0;a<cmd.size();a++) {
JFLog.log("cmd[]=" + cmd.get(a));
}
*/
try {
Process p = Runtime.getRuntime().exec(cmd.toArray(new String[0]));
p.waitFor();
} catch (Exception e) {
JFLog.log(e);
}
}
/** X11 : RandR : Sets only primary display to res and disable all other (for Logon Screen)
* @param res = resolution (ie: 800x600)
*/
public static void x11_rr_reset(String res) {
Monitor config[] = x11_rr_get_setup(null);
if (config == null || config.length == 0) return;
ArrayList<String> cmd = new ArrayList<String>();
cmd.add("xrandr");
cmd.add("--output");
cmd.add(config[0].name);
cmd.add("--mode");
cmd.add(res);
cmd.add("--rotate");
cmd.add("normal");
for(int a=1;a<config.length;a++) {
cmd.add("--output");
cmd.add(config[a].name);
cmd.add("--off");
}
try {
Process p = Runtime.getRuntime().exec(cmd.toArray(new String[0]));
p.waitFor();
} catch (Exception e) {
JFLog.log(e);
}
}
public static class Config {
public Monitor monitor[];
}
public static Monitor[] x11_rr_load_user() {
Config config = new Config();
try {
XML xml = new XML();
FileInputStream fis = new FileInputStream(JF.getUserPath() + "/.xrandr.xml");
xml.read(fis);
xml.writeClass(config);
fis.close();
return config.monitor;
} catch (FileNotFoundException e1) {
return new Monitor[0];
} catch (Exception e2) {
JFLog.log(e2);
return new Monitor[0];
}
}
public static void x11_rr_save_user(Monitor monitor[]) {
Config config = new Config();
config.monitor = monitor;
try {
XML xml = new XML();
FileOutputStream fos = new FileOutputStream(JF.getUserPath() + "/.xrandr.xml");
xml.readClass("display", config);
xml.write(fos);
fos.close();
} catch (Exception e) {
JFLog.log(e);
}
}
//PAM functions
private static final int PAM_SILENT = 0x8000;
private static final int PAM_PROMPT_ECHO_ON = 2;
private static final int PAM_PROMPT_ECHO_OFF = 1;
private static String pam_user, pam_pass;
private static long pam_responses;
public static synchronized boolean authUser(String user, String pass) {
return LnxNative.authUser(user, pass);
}
public static final int SIGKILL = 9;
public static final int SIGTERM = 15;
public static void kill(int pid, int signal) {
try {
Runtime.getRuntime().exec(new String[] {"kill", "-" + signal, "" + pid});
} catch (Exception e) {
JFLog.log(e);
}
}
public static void setenv(String name, String value) {
LnxNative.setenv(name, value);
}
/* Test */
public static void main(String args[]) {
x11_set_listener(new X11Listener() {
public void trayIconAdded(int count) {
System.out.println("tragIconAdded:" + count);
}
public void trayIconRemoved(int count) {
System.out.println("tragIconRemoved:" + count);
}
public void windowsChanged() {
System.out.println("windowsChanged");
}
});
x11_window_list_main();
}
}