package jfconfig;
/**
* Created : Apr 7, 2012
*
* @author pquiring
*/
// TODO : create dialog box to undo changes if things go bad
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javaforce.*;
import javaforce.linux.Linux;
import static javaforce.linux.Linux.*;
public class DisplayPanel extends javax.swing.JPanel implements MouseMotionListener, MouseListener {
/**
* Creates new form DisplayPanel
*/
public DisplayPanel() {
initComponents();
loadConfig();
rescan();
// restore = monitors;
if (!new File("/usr/bin/nvidia-settings").exists()) {
nvidia.setEnabled(false);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jToolBar1 = new javax.swing.JToolBar();
back = new javax.swing.JButton();
apply = new javax.swing.JButton();
nvidia = new javax.swing.JButton();
jLabel4 = new javax.swing.JLabel();
resolution = new javax.swing.JComboBox();
jPanel1 = new javax.swing.JPanel();
view = new javax.swing.JScrollPane();
layout = new javax.swing.JPanel();
mirror = new javax.swing.JCheckBox();
jLabel7 = new javax.swing.JLabel();
rotation = new javax.swing.JComboBox();
jLabel1 = new javax.swing.JLabel();
displays = new javax.swing.JComboBox();
jToolBar1.setFloatable(false);
jToolBar1.setRollover(true);
back.setText("< Back");
back.setFocusable(false);
back.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
back.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
back.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
backActionPerformed(evt);
}
});
jToolBar1.add(back);
apply.setText("Apply");
apply.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
applyActionPerformed(evt);
}
});
jToolBar1.add(apply);
nvidia.setText("nVidia Settings");
nvidia.setFocusable(false);
nvidia.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
nvidia.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
nvidia.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
nvidiaActionPerformed(evt);
}
});
jToolBar1.add(nvidia);
jLabel4.setText("Resolution");
resolution.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
resolutionItemStateChanged(evt);
}
});
jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Position"));
layout.setLayout(null);
view.setViewportView(layout);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(view)
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(view, javax.swing.GroupLayout.DEFAULT_SIZE, 341, Short.MAX_VALUE)
.addContainerGap())
);
mirror.setText("Mirror Display");
mirror.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
mirrorItemStateChanged(evt);
}
});
jLabel7.setText("Rotation");
rotation.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Normal", "ClockWise", "CounterClockWise", "Inverted" }));
rotation.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
rotationItemStateChanged(evt);
}
});
jLabel1.setText("Display");
displays.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
displaysItemStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 521, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel4)
.addComponent(jLabel7)
.addComponent(jLabel1))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(displays, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(mirror))
.addComponent(resolution, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(rotation, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(displays, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(mirror))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel4)
.addComponent(resolution, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(rotation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel7))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void backActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backActionPerformed
ConfigApp.setPanel(new MainPanel());
}//GEN-LAST:event_backActionPerformed
private void applyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_applyActionPerformed
apply();
}//GEN-LAST:event_applyActionPerformed
private void nvidiaActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nvidiaActionPerformed
try {
Runtime.getRuntime().exec("nvidia-settings");
} catch (Exception e) {
}
}//GEN-LAST:event_nvidiaActionPerformed
private void resolutionItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_resolutionItemStateChanged
}//GEN-LAST:event_resolutionItemStateChanged
private void mirrorItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_mirrorItemStateChanged
if (selectedMonitor == monitors[0]) return; //can not mirror primary monitor
boolean state = mirror.isSelected();
boolean oldState = selectedMonitor.mirror;
selectedMonitor.mirror = state;
if (state) {
selectedMonitor.relpos = P_SAME;
selectedMonitor.relName = monitors[0].name;
} else {
//set an invalid position (x11_rr_arrangeMonitors() will place it somewhere)
selectedMonitor.relpos = P_NONE;
selectedMonitor.relName = "";
Linux.x11_rr_arrangeMonitors(monitors);
}
if (state != oldState) addJMonitors(); //removing or adding a monitor
}//GEN-LAST:event_mirrorItemStateChanged
private void rotationItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rotationItemStateChanged
}//GEN-LAST:event_rotationItemStateChanged
private void displaysItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_displaysItemStateChanged
int idx = displays.getSelectedIndex();
if (idx == -1) return;
if (selectedMonitor != monitors[idx]) selectMonitor(monitors[idx]);
}//GEN-LAST:event_displaysItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton apply;
private javax.swing.JButton back;
private javax.swing.JComboBox displays;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel7;
private javax.swing.JPanel jPanel1;
private javax.swing.JToolBar jToolBar1;
private javax.swing.JPanel layout;
private javax.swing.JCheckBox mirror;
private javax.swing.JButton nvidia;
private javax.swing.JComboBox resolution;
private javax.swing.JComboBox rotation;
private javax.swing.JScrollPane view;
// End of variables declaration//GEN-END:variables
/*
private final int P_NONE = 0;
private final int P_LEFT = 1;
private final int P_ABOVE = 2;
private final int P_RIGHT = 3;
private final int P_BELOW = 4;
private final int P_SAME = 5;
private final int R_NORMAL = 0;
private final int R_RIGHT = 1; //CW
private final int R_LEFT = 2; //CCW
private final int R_INVERTED = 3;
*/
private Monitor monitors[]; //, restore[];
private static Monitor selectedMonitor = null;
private static class JMonitor extends JLabel {
public Monitor monitor;
public int x,y; //position on screen
public boolean layout;
public JMonitor(String label) {
super(label);
}
public void paintComponent(Graphics g) {
if (selectedMonitor == monitor) {
setBackground(Color.blue);
} else {
setBackground(Color.gray);
}
super.paintComponent(g);
}
}
private void loadConfig() {
monitors = Linux.x11_rr_load_user();
}
private void saveConfig() {
Linux.x11_rr_save_user(monitors);
}
private void layoutMonitors() {
int x = BOXSIZE, y = BOXSIZE;
int nx = 0, ny = 0; //max negative x,y
JMonitor list[] = getJMonitors();
for(int j=0;j<list.length;j++) {
list[j].layout = false;
}
boolean redo;
int cnt = 0;
do {
redo = false;
cnt++;
if (cnt == 100) break;
for(int m=0;m<monitors.length;m++) {
Monitor monitor = monitors[m];
if (monitor.mirror) continue;
JMonitor jmonitor = null, adjacent = null;
for(int j=0;j<list.length;j++) {
JMonitor test = list[j];
if (test.monitor.name.equals(monitor.name)) jmonitor = test;
if (test.monitor.name.equals(monitor.relName)) adjacent = test;
}
if (jmonitor == null) continue;
if (jmonitor.layout) continue;
if (m == 0) {
monitor.relName = "";
monitor.relpos = P_NONE;
}
if (monitor.relpos != P_NONE && adjacent != null && !adjacent.layout) {redo = true; continue;}
switch (monitor.relpos) {
case P_NONE:
case P_SAME:
jmonitor.x = x;
jmonitor.y = y;
break;
case P_LEFT:
jmonitor.x = adjacent.x - BOXSIZE;
jmonitor.y = adjacent.y;
break;
case P_RIGHT:
jmonitor.x = adjacent.x + BOXSIZE;
jmonitor.y = adjacent.y;
break;
case P_ABOVE:
jmonitor.x = adjacent.x;
jmonitor.y = adjacent.y - BOXSIZE;
break;
case P_BELOW:
jmonitor.x = adjacent.x;
jmonitor.y = adjacent.y + BOXSIZE;
break;
}
jmonitor.setBounds(jmonitor.x,jmonitor.y,BOXSIZE,BOXSIZE);
if (jmonitor.x < nx) nx = jmonitor.x;
if (jmonitor.y < ny) ny = jmonitor.y;
jmonitor.layout = true;
}
} while (redo);
if (nx < 0 || ny < 0) {
//need to shift everything
for(int j=0;j<list.length;j++) {
JMonitor jmonitor = list[j];
jmonitor.x -= nx;
jmonitor.y -= ny;
jmonitor.setBounds(jmonitor.x,jmonitor.y,BOXSIZE,BOXSIZE);
}
}
}
private void moveMonitor(JMonitor jmonitor) {
if (jmonitor.monitor == monitors[0]) return;
int x = jmonitor.getX();
int y = jmonitor.getY();
int bestlen = 0x7fffffff;
JMonitor adjacent = null;
int pos = 0;
int dx,dy,len;
Monitor monitor = jmonitor.monitor;
JMonitor list[] = getJMonitors();
for(int j=0;j<list.length;j++) {
JMonitor test = list[j];
if (test == jmonitor) continue;
dx = (test.x - BOXSIZE) - x;
dy = test.y - y;
len = (int)Math.sqrt(dx * dx + dy * dy);
if (len < bestlen) {
adjacent = test;
pos = P_LEFT;
bestlen = len;
}
dx = (test.x + BOXSIZE) - x;
dy = test.y - y;
len = (int)Math.sqrt(dx * dx + dy * dy);
if (len < bestlen) {
adjacent = test;
pos = P_RIGHT;
bestlen = len;
}
dx = test.x - x;
dy = (test.y + BOXSIZE) - y;
len = (int)Math.sqrt(dx * dx + dy * dy);
if (len < bestlen) {
adjacent = test;
pos = P_BELOW;
bestlen = len;
}
dx = test.x - x;
dy = (test.y - BOXSIZE) - y;
len = (int)Math.sqrt(dx * dx + dy * dy);
if (len < bestlen) {
adjacent = test;
pos = P_ABOVE;
bestlen = len;
}
}
if (adjacent == null) return;
if (adjacent.monitor.name.equals(jmonitor.monitor.name) && adjacent.monitor.relName.equals(jmonitor.monitor.name)) {
adjacent.monitor.relpos = monitor.relpos;
adjacent.monitor.relName = monitor.relName;
}
jmonitor.monitor.relpos = pos;
jmonitor.monitor.relName = adjacent.monitor.name;
}
private void removeMonitors() {
layout.removeAll();
}
private JMonitor makeJMonitor(Monitor monitor) {
JMonitor jmonitor = new JMonitor(monitor.name);
jmonitor.monitor = monitor;
jmonitor.addMouseListener(this);
jmonitor.addMouseMotionListener(this);
jmonitor.setBorder(javax.swing.BorderFactory.createEtchedBorder());
jmonitor.setHorizontalAlignment(SwingConstants.CENTER);
return jmonitor;
}
private final int BOXSIZE = 100; //monitor width/height
private void addJMonitors() {
removeMonitors();
for(int m=0;m<monitors.length;m++) {
Monitor monitor = monitors[m];
// if (monitor.mirror) continue;
JMonitor jmonitor = makeJMonitor(monitor);
layout.add(jmonitor);
}
layoutMonitors();
layout.repaint();
}
private boolean apply_rr() {
Linux.x11_rr_set(monitors);
return true;
}
private static String quote(String str) {
return "\"" + str + "\"";
}
private void apply() {
saveMonitor();
saveConfig();
if (!apply_rr()) {
JF.showError("Error", "Failed to apply configuration");
return;
}
ConfigApp.jbusClient.call("org.jflinux.jfsystemmgr", "broadcastVideoChanged", quote("jconfig"));
}
private void saveMonitor() {
if (selectedMonitor == null) return;
//update values
selectedMonitor.res = (String)resolution.getSelectedItem();
selectedMonitor.rotate = rotation.getSelectedIndex();
// selectedMonitor.mirror = mirror.isSelected(); //done in mirror itemStateChanged()
}
private void selectMonitor(Monitor monitor) {
if (selectedMonitor != null) {
saveMonitor();
}
Screen screen;
Port port;
resolution.removeAllItems();
int idx = -1;
boolean done = false;
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 (monitor.name.equals(port.name)) {
//update resolution options
for(int d=0;d<port.sizes.size();d++) {
Size size = port.sizes.get(d);
resolution.addItem(size.size);
if (monitor.res.equals(size.size)) {
idx = d;
}
}
done = true;
break;
}
if (done) break;
}
if (done) break;
}
if (idx != -1) resolution.setSelectedIndex(idx);
rotation.setSelectedIndex(monitor.rotate);
idx = -1;
for(int a=0;a<monitors.length;a++) {
if (monitors[a] == monitor) {
idx = a;
break;
}
}
JMonitor list[] = getJMonitors();
for(int a=0;a<list.length;a++) {
if (list[a].monitor == monitor) {
selectedMonitor = monitor;
break;
}
}
mirror.setSelected(monitor.mirror);
mirror.setEnabled(idx != 0);
displays.setSelectedIndex(idx);
layout.repaint();
}
private boolean drag;
private int ix, iy; //init pos
private int sx, sy; //start x,y
public void mouseClicked(MouseEvent me) {
}
public void mousePressed(MouseEvent me) {
if (layout.getComponentCount() == 1) return; //nothing to move to
JMonitor jmonitor = (JMonitor)me.getSource();
ix = jmonitor.getX();
iy = jmonitor.getY();
sx = me.getXOnScreen();
sy = me.getYOnScreen();
drag = true;
// System.out.println("pressed:" + sx + "," + sy);
selectMonitor(jmonitor.monitor);
}
public void mouseReleased(MouseEvent me) {
if (drag) {
JMonitor jmonitor = (JMonitor)me.getSource();
moveMonitor(jmonitor);
layoutMonitors();
layout.repaint();
drag = false;
}
}
public void mouseEntered(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mouseDragged(MouseEvent me) {
if (!drag) return;
JMonitor jmonitor = (JMonitor)me.getSource();
int x = me.getXOnScreen();
int y = me.getYOnScreen();
// System.out.println("dragged:" + x + "," + y);
jmonitor.setLocation(ix + (x - sx), iy + (y - sy));
}
public void mouseMoved(MouseEvent me) {
}
public void rescan() {
monitors = Linux.x11_rr_get_setup(monitors);
monitors[0].relName = "";
monitors[0].relpos = P_NONE;
displays.removeAllItems();
for(int a=0;a<monitors.length;a++) {
displays.addItem(monitors[a].name);
}
addJMonitors();
selectMonitor(monitors[0]);
}
private JMonitor[] getJMonitors() {
Component list[] = layout.getComponents();
JMonitor mlist[] = new JMonitor[list.length];
for(int a=0;a<list.length;a++) {
mlist[a] = (JMonitor)list[a];
}
return mlist;
}
}