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; } }