From 5138c1069efcbe207186d7ac64d5ca074c0fafca Mon Sep 17 00:00:00 2001 From: rm5248 Date: Fri, 18 Jul 2014 19:15:41 -0400 Subject: [PATCH 01/13] Added the ability to see all subwindows. Added a dialog so users can see the recursive X windows --- contrib/x11/src/jnacontrib/x11/api/X.java | 79 +- .../jnacontrib/x11/demos/XDesktopDemo.java | 687 ++++++++++-------- 2 files changed, 440 insertions(+), 326 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index e8a76b95e9..28ffbfe5ed 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -27,6 +27,7 @@ import com.sun.jna.platform.unix.X11; import com.sun.jna.platform.unix.X11.Atom; +import com.sun.jna.platform.unix.X11.WindowByReference; /** * Object oriented X window system. @@ -586,7 +587,7 @@ public String getWindowClass() throws X11Exception { * @return PID of the window * @throws X11Exception thrown if X11 window errors occurred */ - public int getPID() throws X11Exception { + public Integer getPID() throws X11Exception { return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); } @@ -731,11 +732,15 @@ public int close() throws X11Exception { * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as integer + * @return property value as integer or null if not found * @throws X11Exception thrown if X11 window errors occurred */ - public int getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return bytesToInt(getProperty(xa_prop_type, xa_prop_name)); + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); } /** @@ -746,7 +751,7 @@ public int getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X * @return property value as integer * @throws X11Exception thrown if X11 window errors occurred */ - public int getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); } @@ -755,11 +760,14 @@ public int getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11 * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as window + * @return property value as window, or null if not found * @throws X11Exception thrown if X11 window errors occurred */ public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - int windowId = getIntProperty(xa_prop_type, xa_prop_name); + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } X11.Window x11Window = new X11.Window(windowId); return new Window(display, x11Window); } @@ -781,12 +789,16 @@ public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) thro * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as a null terminated byte array + * @return property value as a null terminated byte array, or null if not found * @throws X11Exception thrown if X11 window errors occurred */ public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); byte[] bytesDest; + + if( bytesOrig == null ){ + return null; + } // search for '\0' int i; @@ -821,12 +833,16 @@ public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_na * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found * @throws X11Exception thrown if X11 window errors occurred */ public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + if( bytes == null ){ + return null; + } + // search for '\0' int i; for (i = 0; i < bytes.length; i++) { @@ -891,11 +907,15 @@ public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_na * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as string list + * @return property value as string list, or null if the property value does not exist * @throws X11Exception thrown if X11 window errors occurred */ public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); } /** @@ -908,7 +928,11 @@ public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name */ public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { try { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name), "UTF8"); + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); } catch (UnsupportedEncodingException e) { throw new X11Exception(e); } @@ -986,6 +1010,11 @@ public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } if (xa_ret_type == null || xa_prop_type == null || !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { @@ -1067,6 +1096,32 @@ public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong throw new X11Exception("Cannot send " + msg + " event."); } } + + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + + x11.XFree( children.getValue() ); + + return retVal; + } public String toString() { return x11Window.toString(); diff --git a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java index f20002f832..785c8d618c 100644 --- a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java +++ b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java @@ -13,10 +13,12 @@ package jnacontrib.x11.demos; import jnacontrib.x11.api.X; +import jnacontrib.x11.api.X.X11Exception; import javax.swing.*; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; + import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -29,339 +31,396 @@ */ public class XDesktopDemo extends JFrame { private static final long serialVersionUID = 1L; - public static void main(String[] args) throws X.X11Exception { - new XDesktopDemo(); - } + public static void main(String[] args) throws X.X11Exception { + new XDesktopDemo(); + } + + private X.Display display = new X.Display(); + private JList desktopList; + private JTable windowTable; + private JButton refreshButton; + private JButton moveWindowToDesktopButton; + private JButton goToDesktopButton; + private JButton moveWindowAndGoToDesktopButton; + private JButton closeWindowButton; + private JButton goToWindowButton; + private JButton showDesktop; + private JButton showSubwindows; + + public XDesktopDemo() throws X.X11Exception { + super("XDesktopDemo"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + initGui(); + + refreshDesktopsAndWindows(); - private X.Display display = new X.Display(); - private JList desktopList; - private JTable windowTable; - private JButton refreshButton; - private JButton moveWindowToDesktopButton; - private JButton goToDesktopButton; - private JButton moveWindowAndGoToDesktopButton; - private JButton closeWindowButton; - private JButton goToWindowButton; - private JButton showDesktop; - - public XDesktopDemo() throws X.X11Exception { - super("XDesktopDemo"); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - initGui(); + pack(); + addListeners(); + setVisible(true); - refreshDesktopsAndWindows(); + printWmInfo(); + } - pack(); - addListeners(); - setVisible(true); + private void printWmInfo() throws X.X11Exception { + X.Window wm = display.getWindowManagerInfo(); + System.out.println("wm.getTitle() = " + wm.getTitle()); + System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); + System.out.println("wm.getPID() = " + wm.getPID()); + } - printWmInfo(); - } + private void addListeners() { + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + refreshDesktopsAndWindows(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + goToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + int desktopNr = desktopList.getSelectedIndex(); + if (desktopNr >= 0) { + try { + display.switchDesktop(desktopNr); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + } + }); + goToWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showDesktop.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + display.showingDesktop(true); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + closeWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.close(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showSubwindows.addActionListener(new ActionListener() { + + private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ + X.Window[] subWindows = win.getSubwindows(); + String title = win.getTitle(); + if( title != null ){ + area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); + }else{ + area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); + } + area.append( System.getProperty( "line.separator" ) ); + + if( subWindows == null ){ + return; + } + for( int x = 0; x < subWindows.length; x++ ){ + addWindowsToArea( area, depth + 4, subWindows[ x ] ); + } + } - private void printWmInfo() throws X.X11Exception { - X.Window wm = display.getWindowManagerInfo(); - System.out.println("wm.getTitle() = " + wm.getTitle()); - System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); - System.out.println("wm.getPID() = " + wm.getPID()); - } + @Override + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); - private void addListeners() { - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - refreshDesktopsAndWindows(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - goToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - int desktopNr = desktopList.getSelectedIndex(); - if (desktopNr >= 0) { - try { - display.switchDesktop(desktopNr); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - } - }); - goToWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - showDesktop.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - display.showingDesktop(true); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - closeWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.close(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - } + try{ + final JDialog jd = new JDialog(); + JPanel dialogPanel = new JPanel( new BorderLayout() ); + jd.setSize( 320, 240 ); + jd.setTitle( "Subwindows" ); + jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); + JTextArea area = new JTextArea(); + addWindowsToArea( area, 1, window ); + dialogPanel.add( area, BorderLayout.CENTER ); + JButton closeButton = new JButton( "Close" ); + closeButton.addActionListener( new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + jd.dispose(); + } + }); + dialogPanel.add( closeButton, BorderLayout.SOUTH ); + jd.add( dialogPanel ); + jd.setVisible( true ); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + } - private X.Window getSelectedWindow() { - WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); - return tableModel.getWindow(windowTable.getSelectedRow()); - } + private X.Window getSelectedWindow() { + WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); + return tableModel.getWindow(windowTable.getSelectedRow()); + } - private void refreshDesktopsAndWindows() throws X.X11Exception { - // update desktop list - X.Desktop[] desktops = display.getDesktops(); - ArrayList list = new ArrayList(desktops.length); - for (int i = 0; i < desktops.length; i++) { - list.add(desktops[i].name); - } - desktopList.clearSelection(); - desktopList.setModel(new SimpleListModel(list)); + private void refreshDesktopsAndWindows() throws X.X11Exception { + // update desktop list + X.Desktop[] desktops = display.getDesktops(); + ArrayList list = new ArrayList(desktops.length); + for (int i = 0; i < desktops.length; i++) { + list.add(desktops[i].name); + } + desktopList.clearSelection(); + desktopList.setModel(new SimpleListModel(list)); - // select active desktop - int activeDesktop = display.getActiveDesktopNumber(); - desktopList.setSelectedIndex(activeDesktop); + // select active desktop + int activeDesktop = display.getActiveDesktopNumber(); + desktopList.setSelectedIndex(activeDesktop); - // update window list - int activeWindowId = display.getActiveWindow().getID(); - int activeWindowNumber = -1; - X.Window[] windows = display.getWindows(); - String[] head = new String[]{ - "ID", "Desktop", "Title", - "X", "Y", "Width", "Height" - }; - String[][] data = new String[windows.length][head.length]; - for (int i = 0; i < windows.length; i++) { - X.Window window = windows[i]; - X.Window.Geometry geo = window.getGeometry(); - int windowId = window.getID(); - data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); - data[i][1] = "" + window.getDesktop(); - data[i][2] = window.getTitle(); - data[i][3] = "" + geo.x; - data[i][4] = "" + geo.y; - data[i][5] = "" + geo.width; - data[i][6] = "" + geo.height; - if (windowId == activeWindowId) { - activeWindowNumber = i; - } - } - windowTable.setModel(new WindowTableModel(head, data, windows)); - if (activeWindowNumber >= 0) { - windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); - } - } + // update window list + int activeWindowId = display.getActiveWindow().getID(); + int activeWindowNumber = -1; + X.Window[] windows = display.getWindows(); + String[] head = new String[]{ + "ID", "Desktop", "Title", + "X", "Y", "Width", "Height" + }; + String[][] data = new String[windows.length][head.length]; + for (int i = 0; i < windows.length; i++) { + X.Window window = windows[i]; + X.Window.Geometry geo = window.getGeometry(); + int windowId = window.getID(); + data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); + data[i][1] = "" + window.getDesktop(); + data[i][2] = window.getTitle(); + data[i][3] = "" + geo.x; + data[i][4] = "" + geo.y; + data[i][5] = "" + geo.width; + data[i][6] = "" + geo.height; + if (windowId == activeWindowId) { + activeWindowNumber = i; + } + } + windowTable.setModel(new WindowTableModel(head, data, windows)); + if (activeWindowNumber >= 0) { + windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); + } + } - private void initGui() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new GridBagLayout()); - final JPanel panel1 = new JPanel(); - panel1.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 0.8; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel1, gbc); - panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); - desktopList = new JList(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel1.add(desktopList, gbc); - final JPanel panel2 = new JPanel(); - panel2.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel2, gbc); - panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); - final JScrollPane scrollPane1 = new JScrollPane(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel2.add(scrollPane1, gbc); - windowTable = new JTable(); - windowTable.setEnabled(true); - scrollPane1.setViewportView(windowTable); - final JPanel panel3 = new JPanel(); - panel3.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 2; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel3, gbc); - panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); - goToDesktopButton = new JButton(); - goToDesktopButton.setText("go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToDesktopButton, gbc); - refreshButton = new JButton(); - refreshButton.setText("refresh"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(refreshButton, gbc); - goToWindowButton = new JButton(); - goToWindowButton.setText("go to window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToWindowButton, gbc); - moveWindowAndGoToDesktopButton = new JButton(); - moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowAndGoToDesktopButton, gbc); - closeWindowButton = new JButton(); - closeWindowButton.setText("close window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 3; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(closeWindowButton, gbc); - moveWindowToDesktopButton = new JButton(); - moveWindowToDesktopButton.setText("move window to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowToDesktopButton, gbc); - showDesktop = new JButton(); - showDesktop.setText("show desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(showDesktop, gbc); + private void initGui() { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new GridBagLayout()); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridBagLayout()); + GridBagConstraints gbc; + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 0.8; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel1, gbc); + panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); + desktopList = new JList(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel1.add(desktopList, gbc); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel2, gbc); + panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); + final JScrollPane scrollPane1 = new JScrollPane(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel2.add(scrollPane1, gbc); + windowTable = new JTable(); + windowTable.setEnabled(true); + scrollPane1.setViewportView(windowTable); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 2; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel3, gbc); + panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); + goToDesktopButton = new JButton(); + goToDesktopButton.setText("go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToDesktopButton, gbc); + refreshButton = new JButton(); + refreshButton.setText("refresh"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(refreshButton, gbc); + goToWindowButton = new JButton(); + goToWindowButton.setText("go to window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToWindowButton, gbc); + moveWindowAndGoToDesktopButton = new JButton(); + moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowAndGoToDesktopButton, gbc); + closeWindowButton = new JButton(); + closeWindowButton.setText("close window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(closeWindowButton, gbc); + moveWindowToDesktopButton = new JButton(); + moveWindowToDesktopButton.setText("move window to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowToDesktopButton, gbc); + showDesktop = new JButton(); + showDesktop.setText("show desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showDesktop, gbc); + showSubwindows = new JButton(); + showSubwindows.setText("show subwindows"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showSubwindows, gbc); - // more attributes - desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + // more attributes + desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - setContentPane(mainPanel); - } + setContentPane(mainPanel); + } - /** - * A simple ListModel managing a list of objects. - */ - public static class SimpleListModel extends AbstractListModel { + /** + * A simple ListModel managing a list of objects. + */ + public static class SimpleListModel extends AbstractListModel { private static final long serialVersionUID = 1L; - private ArrayList list; + private ArrayList list; - public SimpleListModel(ArrayList list) { - this.list = list; - } + public SimpleListModel(ArrayList list) { + this.list = list; + } - public int getSize() { return list.size(); } - public Object getElementAt(int i) { return list.get(i); } - } + public int getSize() { return list.size(); } + public Object getElementAt(int i) { return list.get(i); } + } - /** - * A simple TableModel managing an array of Strings. - */ - public static class WindowTableModel implements TableModel { - private String[] head; - private String[][] data; - private X.Window[] windows; + /** + * A simple TableModel managing an array of Strings. + */ + public static class WindowTableModel implements TableModel { + private String[] head; + private String[][] data; + private X.Window[] windows; - public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { - this.head = head; - this.data = data; - this.windows = windows; - } + public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { + this.head = head; + this.data = data; + this.windows = windows; + } - public int getRowCount() { - return data.length; - } - public int getColumnCount() { - return head.length; - } - public String getColumnName(int columnIndex) { - return head[columnIndex]; - } - public Class getColumnClass(int columnIndex) { - return String.class; - } - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - public Object getValueAt(int rowIndex, int columnIndex) { - return data[rowIndex][columnIndex]; - } - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - } - public void addTableModelListener(TableModelListener l) { - } - public void removeTableModelListener(TableModelListener l) { - } + public int getRowCount() { + return data.length; + } + public int getColumnCount() { + return head.length; + } + public String getColumnName(int columnIndex) { + return head[columnIndex]; + } + public Class getColumnClass(int columnIndex) { + return String.class; + } + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + } + public void addTableModelListener(TableModelListener l) { + } + public void removeTableModelListener(TableModelListener l) { + } - public X.Window getWindow(int rowIndex) { - return windows[rowIndex]; - } - } + public X.Window getWindow(int rowIndex) { + return windows[rowIndex]; + } + } } From 94b408875a3927c0c70667e0b27d9b33a4936a4a Mon Sep 17 00:00:00 2001 From: rm5248 Date: Fri, 18 Jul 2014 17:36:55 -0700 Subject: [PATCH 02/13] Ensured that getting all windows from the X server works properly on 32-bit --- contrib/x11/src/jnacontrib/x11/api/X.java | 2255 +++++++++++---------- 1 file changed, 1133 insertions(+), 1122 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index 28ffbfe5ed..239e373599 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -39,1126 +39,1137 @@ * @author Stefan Endrullis */ public class X { - /** Remove/unset property. */ - public static final int _NET_WM_STATE_REMOVE = 0; - /** Add/set property. */ - public static final int _NET_WM_STATE_ADD = 1; - /** Toggle property. */ - public static final int _NET_WM_STATE_TOGGLE = 2; - /** Maximal property value length. */ - public static final int MAX_PROPERTY_VALUE_LEN = 4096; - - private static final X11 x11 = X11.INSTANCE; - - private static int bytesToInt(byte[] prop) { - return ((prop[3] & 0xff) << 24) - | ((prop[2] & 0xff) << 16) - | ((prop[1] & 0xff) << 8) - | ((prop[0] & 0xff)); - } - - private static int bytesToInt(byte[] prop, int offset) { - return ((prop[3 + offset] & 0xff) << 24) - | ((prop[2 + offset] & 0xff) << 16) - | ((prop[1 + offset] & 0xff) << 8) - | ((prop[offset] & 0xff)); - } - - - /** - * X Display. - */ - public static class Display { - /** - * Open display. - */ - private X11.Display x11Display; - /** - * HashMap. - */ - private HashMap atomsHash = new HashMap(); - - /** - * Creates the OOWindowUtils using the default display. - */ - public Display() { - x11Display = x11.XOpenDisplay(null); - - if (x11Display == null) { - throw new Error("Can't open X Display"); - } - } - - /** - * Creates the OOWindowUtils using a given display. - * - * @param x11Display open display - */ - public Display(X11.Display x11Display) { - this.x11Display = x11Display; - - if (x11Display == null) { - throw new Error("X Display is null"); - } - } - - /** - * Closes the display. - */ - public void close() { - x11.XCloseDisplay(x11Display); - } - - /** - * Flushes the output buffer / event queue. - */ - public void flush() { - x11.XFlush(x11Display); - } - - /** - * Returns the X11 display. - * - * @return X11 display - */ - public X11.Display getX11Display() { - return x11Display; - } - - /** - * Get internal atoms by name. - * - * @param name name of the atom - * @return atom - */ - public X11.Atom getAtom(String name) { - X11.Atom atom = atomsHash.get(name); - if (atom == null) { - atom = x11.XInternAtom(x11Display, name, false); - atomsHash.put(name, atom); - } - return atom; - } - - /** - * Returns the window manager information as an window. - * - * @return window manager information as an window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowManagerInfo() throws X11Exception { - Window rootWindow = getRootWindow(); - - try { - return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); - } catch (X11Exception e) { - try { - return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); - } - } - } - - /** - * Returns the root window. - * - * @return root window - */ - public Window getRootWindow() { - return new Window(this, x11.XDefaultRootWindow(x11Display)); - } - - /** - * Returns the current active window. - * - * @return current active window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getActiveWindow() throws X11Exception { - return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); - } - - /** - * Returns all windows managed by the window manager. - * - * @return all windows managed by the window manager - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window[] getWindows() throws X11Exception { - byte[] bytes; - Window rootWindow = getRootWindow(); - - try { - bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); - } catch (X11Exception e) { - try { - bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); - } - } - - Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; - - for (int i = 0; i < windowList.length; i++) { - windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); - } - - return windowList; - } - - /** - * Returns the number of desktops. - * - * @return number of desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktopCount() throws X11Exception { - Window root = getRootWindow(); - - try { - return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); - } catch (X11Exception e) { - try { - return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); - } - } - } - - /** - * Returns the number of the active desktop. - * - * @return number of the active desktop - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getActiveDesktopNumber() throws X11Exception { - Window root = getRootWindow(); - int cur_desktop; - - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); - } catch (X11Exception e) { - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); - } - } - - return cur_desktop; - } - - /** - * Returns the available desktops. - * - * @return available desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public Desktop[] getDesktops() throws X11Exception { - Window root = getRootWindow(); - String[] desktopNames; - try { - desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); - } catch (X11Exception e) { - try { - desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); - } - } - - Desktop[] desktops = new Desktop[getDesktopCount()]; - for (int i = 0; i < desktops.length; i++) { - desktops[i] = new Desktop(this, i, desktopNames[i]); - } - - return desktops; - } - - /** - * Switches to the given desktop. - * - * @param nr desktop number - * @throws X11Exception thrown if X11 window errors occurred - */ - public void switchDesktop(int nr) throws X11Exception { - getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); - } - - /** - * Sets the "showing the desktop" state. - * - * @param state true if the desktop should be shown - * @throws X11Exception thrown if X11 window errors occurred - */ - public void showingDesktop(boolean state) throws X11Exception { - getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); - } - - /** - * Enables / disables the auto-repeat of pressed keys. - * - * @param on true if auto-repeat shall be enabled - */ - public void setKeyAutoRepeat(boolean on) { - if (on) { - x11.XAutoRepeatOn(x11Display); - } else { - x11.XAutoRepeatOff(x11Display); - } - } - - /** - * Returns the key symbol corresponding to the the key name. - * - * @param keyName name of the key - * @return key symbol - */ - public X11.KeySym getKeySym(String keyName) { - return x11.XStringToKeysym(keyName); - } - - /** - * Returns the key symbol corresponding to the keycode. - * - * @param keyCode keycode - * @param index element of the keycode vector - * @return key symbol - */ - public X11.KeySym getKeySym(byte keyCode, int index) { - return x11.XKeycodeToKeysym(x11Display, keyCode, index); - } - - /** - * Returns the keycode corresponding to the key symbol. - * - * @param keySym key symbol - * @return keycode - */ - public byte getKeyCode(X11.KeySym keySym) { - return x11.XKeysymToKeycode(x11Display, keySym); - } - - /** - * Returns the keycode corresponding to the key name. - * - * @param keyName name of the key - * @return keycode - */ - public byte getKeyCode(String keyName) { - return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); - } - - /** - * Returns the key name corresponding to the key symbol. - * - * @param keySym key symbol - * @return name of the key - */ - public String getKeyName(X11.KeySym keySym) { - return x11.XKeysymToString(keySym); - } - - /** - * Returns the key name corresponding to the keycode and the index in the keycode vector. - * - * @param keyCode keycode - * @param index index in the keycode vector - * @return name of the key - */ - public String getKeyName(byte keyCode, int index) { - return getKeyName(getKeySym(keyCode, index)); - } - - /** - * Returns the modifier keymap. - * - * @return modifier keymap - */ - public ModifierKeymap getModifierKeymap() { - X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); - ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); - x11.XFreeModifiermap(xModifierKeymapRef); - return modifierKeymap; - } - - /** - * Sets the modifier keymap. - * - * @param modifierKeymap modifier keymap - */ - public void setModifierKeymap(ModifierKeymap modifierKeymap) { - X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); - x11.XSetModifierMapping(x11Display,xModifierKeymapRef); - } - } - - - /** - * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 - * contain the keycodes as Byte objects. You can directly access these lists to - * read, replace, remove or insert new keycodes to these modifiers. - * To apply a new modifier keymap call - * {@link X.Display#setModifierKeymap(ModifierKeymap)}. - */ - public static class ModifierKeymap { - /** Shift modifier as an ArrayList<Byte>. */ - public ArrayList shift = new ArrayList(4); - /** Lock modifier as an ArrayList<Byte>. */ - public ArrayList lock = new ArrayList(4); - /** Control modifier as an ArrayList<Byte>. */ - public ArrayList control = new ArrayList(4); - /** Mod1 modifier as an ArrayList<Byte>. */ - public ArrayList mod1 = new ArrayList(4); - /** Mod2 modifier as an ArrayList<Byte>. */ - public ArrayList mod2 = new ArrayList(4); - /** Mod3 modifier as an ArrayList<Byte>. */ - public ArrayList mod3 = new ArrayList(4); - /** Mod4 modifier as an ArrayList<Byte>. */ - public ArrayList mod4 = new ArrayList(4); - /** Mod5 modifier as an ArrayList<Byte>. */ - public ArrayList mod5 = new ArrayList(4); - - /** - * Creates an empty modifier keymap. - */ - public ModifierKeymap() { - } - - /** - * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - fromXModifierKeymap(xModifierKeymapRef); - } - - /** - * Reads all modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - int count = xModifierKeymapRef.max_keypermod; - byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); - - ArrayList[] allModifiers = getAllModifiers(); - - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - modifier.clear(); - - for (int keyNr = 0; keyNr < count; keyNr++) { - byte key = keys[modNr*count + keyNr]; - if (key != 0) { - modifier.add(new Byte(key)); - } - } - } - } - - /** - * Returns an XModifierKeymap corresponding to this object. - * - * @return XModifierKeymap - */ - public X11.XModifierKeymapRef toXModifierKeyamp() { - ArrayList[] allModifiers = getAllModifiers(); - - // determine max list size - int count = 0; - for (int i = 0; i < allModifiers.length; i++) { - count = Math.max(count, allModifiers[i].size()); - } - - byte[] keys = new byte[8*count]; - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - - for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { - keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); - } - } - - X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); - xModifierKeymapRef.max_keypermod = count; - xModifierKeymapRef.modifiermap = new Memory(keys.length); - xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); - - return xModifierKeymapRef; - } - - /** - * Returns all modifiers as an array. - * - * @return array of modifier lists - */ - public ArrayList[] getAllModifiers() { - return new ArrayList[] { - shift, lock, control, mod1, mod2, mod3, mod4, mod5 - }; - } - } - - /** - * X Desktop. - */ - public static class Desktop { - public X.Display display; - public int number; - public String name; - - public Desktop(Display display, int number, String name) { - this.display = display; - this.number = number; - this.name = name; - } - } - - - /** - * X Window. - */ - public static class Window { - private X.Display display; - private X11.Window x11Window; - - /** - * Returns the X11 window object. - * - * @return X11 window - */ - public X11.Window getX11Window() { - return x11Window; - } - - /** - * Returns the ID of the window. - * - * @return window ID - */ - public int getID() { - return x11Window.intValue(); - } - - /** - * Creates the window. - * - * @param display display where the window is allocated - * @param x11Window X11 window - */ - public Window(X.Display display, X11.Window x11Window) { - this.display = display; - this.x11Window = x11Window; - } - - /** - * Returns the title of the window. - * - * @return title of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getTitle() throws X11Exception { - try { - return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); - } catch (X11Exception e) { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); - } - - } - - /** - * Returns the window class. - * - * @return window class - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getWindowClass() throws X11Exception { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); - } - - /** - * Returns the PID of the window. - * - * @return PID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getPID() throws X11Exception { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); - } - - /** - * Returns the desktop ID of the window. - * - * @return desktop ID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktop() throws X11Exception { - try { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); - } catch (X11Exception e) { - return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } - } - - /** - * Returns the client machine name of the window. - * - * @return client machine name of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getMachine() throws X11Exception { - return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); - } - - /** - * Returns the XWindowAttributes of the window. - * - * @return XWindowAttributes of the window - */ - public X11.XWindowAttributes getXWindowAttributes() { - X11.XWindowAttributes xwa = new X11.XWindowAttributes(); - x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); - - return xwa; - } - - /** - * Returns the geometry of the window. - * - * @return geometry of the window - */ - public Geometry getGeometry() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference borderWidth = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), - borderWidth.getValue(), depth.getValue()); - } - - /** - * Returns the bounding box of the window. - * - * @return bounding box of the window - */ - public Rectangle getBounds() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference border_width = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - int xVal = x.getValue(); - int yVal = y.getValue(); - - return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); - } - - /** - * Activates the window. - * - * @throws X11Exception thrown if X11 window errors occurred - */ - public void activate() throws X11Exception { - clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); - x11.XMapRaised(display.x11Display, x11Window); - } - - /** - * Moves the window to the specified desktop. - * - * @param desktopNr desktop - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int moveToDesktop(int desktopNr) throws X11Exception { - return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); - } - - /** - * Selects the input events to listen for. - * - * @param eventMask event mask representing the events to listen for - */ - public void selectInput(int eventMask) { - x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); - } - - public int nextEvent(X11.XEvent event) { - return x11.XNextEvent(display.x11Display, event); - } - - public void sendEvent(int eventMask, X11.XEvent event) { - x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); - } - - /** - * Closes the window gracefully. - * - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int close() throws X11Exception { - return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return bytesToInt(property); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); - if( windowId == null ){ - return null; - } - X11.Window x11Window = new X11.Window(windowId); - return new Window(display, x11Window); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); - byte[] bytesDest; - - if( bytesOrig == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytesOrig.length; i++) { - if (bytesOrig[i] == '\0') break; - } - - if (i < bytesOrig.length - 1) { - bytesDest = new byte[i + 1]; - System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); - } else { - bytesDest = bytesOrig; - } - - return bytesDest; - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytes = getProperty(xa_prop_type, xa_prop_name); - - if( bytes == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytes.length; i++) { - if (bytes[i] == '\0') { - bytes[i] = '.'; - } - } - - return bytes; - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list, or null if the property value does not exist - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property).split("\0"); - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property, "UTF8"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); - IntByReference ret_format_ref = new IntByReference(); - NativeLongByReference ret_nitems_ref = new NativeLongByReference(); - NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); - PointerByReference ret_prop_ref = new PointerByReference(); - - NativeLong long_offset = new NativeLong(0); - NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); - - /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): - * - * long_length = Specifies the length in 32-bit multiples of the - * data to be retrieved. - */ - if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, - xa_prop_type, xa_ret_type_ref, ret_format_ref, - ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Cannot get " + prop_name + " property."); - } - - X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); - Pointer ret_prop = ret_prop_ref.getValue(); - - if( xa_ret_type == null ){ - //the specified property does not exist for the specified window - return null; - } - - if (xa_ret_type == null || xa_prop_type == null || - !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { - x11.XFree(ret_prop); - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Invalid type of " + prop_name + " property"); - } - - int ret_format = ret_format_ref.getValue(); - long ret_nitems = ret_nitems_ref.getValue().longValue(); - - // null terminate the result to make string handling easier - int nbytes; - if (ret_format == 32) - nbytes = Native.LONG_SIZE; - else if (ret_format == 16) - nbytes = Native.LONG_SIZE / 2; - else if (ret_format == 8) - nbytes = 1; - else if (ret_format == 0) - nbytes = 0; - else - throw new X11Exception("Invalid return format"); - int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); - - byte[] ret = ret_prop.getByteArray(0, length); - - x11.XFree(ret_prop); - return ret; - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { - return clientMsg( - msg, - new NativeLong(data0), - new NativeLong(data1), - new NativeLong(data2), - new NativeLong(data3), - new NativeLong(data4) - ); - } - - public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { - X11.XClientMessageEvent event; - NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); - - event = new X11.XClientMessageEvent(); - event.type = X11.ClientMessage; - event.serial = new NativeLong(0); - event.send_event = 1; - event.message_type = display.getAtom(msg); - event.window = x11Window; - event.format = 32; - event.data.setType(NativeLong[].class); - event.data.l[0] = data0; - event.data.l[1] = data1; - event.data.l[2] = data2; - event.data.l[3] = data3; - event.data.l[4] = data4; - - X11.XEvent e = new X11.XEvent(); - e.setTypedValue(event); - - if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { - return X11.Success; - } else { - throw new X11Exception("Cannot send " + msg + " event."); - } - } - - public Window[] getSubwindows() throws X11Exception { - WindowByReference root = new WindowByReference(); - WindowByReference parent = new WindowByReference(); - PointerByReference children = new PointerByReference(); - IntByReference childCount = new IntByReference(); - - if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ - throw new X11Exception("Can't query subwindows"); - } - - if( childCount.getValue() == 0 ){ - return null; - } - - Window[] retVal = new Window[ childCount.getValue() ]; - long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); - for( int x = 0; x < retVal.length; x++ ){ - X11.Window win = new X11.Window( windows [ x ] ); - retVal[ x ] = new Window( display, win ); - } - - x11.XFree( children.getValue() ); - - return retVal; - } - - public String toString() { - return x11Window.toString(); - } - - public static class Geometry { - public int x, y, width, height, borderWidth, depth; - - public Geometry(int x, int y, int width, int height, int border_width, int depth) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.borderWidth = border_width; - this.depth = depth; - } - } - } - - /** - * General exception which is thrown when an X11 window error occurred. - */ - public static class X11Exception extends Exception { - private static final long serialVersionUID = 1L; - public X11Exception() { - } - - public X11Exception(String message) { - super(message); - } - - public X11Exception(String message, Throwable cause) { - super(message, cause); - } - - public X11Exception(Throwable cause) { - super(cause); - } - } + /** Remove/unset property. */ + public static final int _NET_WM_STATE_REMOVE = 0; + /** Add/set property. */ + public static final int _NET_WM_STATE_ADD = 1; + /** Toggle property. */ + public static final int _NET_WM_STATE_TOGGLE = 2; + /** Maximal property value length. */ + public static final int MAX_PROPERTY_VALUE_LEN = 4096; + + private static final X11 x11 = X11.INSTANCE; + + private static int bytesToInt(byte[] prop) { + return ((prop[3] & 0xff) << 24) + | ((prop[2] & 0xff) << 16) + | ((prop[1] & 0xff) << 8) + | ((prop[0] & 0xff)); + } + + private static int bytesToInt(byte[] prop, int offset) { + return ((prop[3 + offset] & 0xff) << 24) + | ((prop[2 + offset] & 0xff) << 16) + | ((prop[1 + offset] & 0xff) << 8) + | ((prop[offset] & 0xff)); + } + + + /** + * X Display. + */ + public static class Display { + /** + * Open display. + */ + private X11.Display x11Display; + /** + * HashMap. + */ + private HashMap atomsHash = new HashMap(); + + /** + * Creates the OOWindowUtils using the default display. + */ + public Display() { + x11Display = x11.XOpenDisplay(null); + + if (x11Display == null) { + throw new Error("Can't open X Display"); + } + } + + /** + * Creates the OOWindowUtils using a given display. + * + * @param x11Display open display + */ + public Display(X11.Display x11Display) { + this.x11Display = x11Display; + + if (x11Display == null) { + throw new Error("X Display is null"); + } + } + + /** + * Closes the display. + */ + public void close() { + x11.XCloseDisplay(x11Display); + } + + /** + * Flushes the output buffer / event queue. + */ + public void flush() { + x11.XFlush(x11Display); + } + + /** + * Returns the X11 display. + * + * @return X11 display + */ + public X11.Display getX11Display() { + return x11Display; + } + + /** + * Get internal atoms by name. + * + * @param name name of the atom + * @return atom + */ + public X11.Atom getAtom(String name) { + X11.Atom atom = atomsHash.get(name); + if (atom == null) { + atom = x11.XInternAtom(x11Display, name, false); + atomsHash.put(name, atom); + } + return atom; + } + + /** + * Returns the window manager information as an window. + * + * @return window manager information as an window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowManagerInfo() throws X11Exception { + Window rootWindow = getRootWindow(); + + try { + return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); + } catch (X11Exception e) { + try { + return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); + } + } + } + + /** + * Returns the root window. + * + * @return root window + */ + public Window getRootWindow() { + return new Window(this, x11.XDefaultRootWindow(x11Display)); + } + + /** + * Returns the current active window. + * + * @return current active window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getActiveWindow() throws X11Exception { + return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); + } + + /** + * Returns all windows managed by the window manager. + * + * @return all windows managed by the window manager + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window[] getWindows() throws X11Exception { + byte[] bytes; + Window rootWindow = getRootWindow(); + + try { + bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); + } catch (X11Exception e) { + try { + bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); + } + } + + Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; + + for (int i = 0; i < windowList.length; i++) { + windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); + } + + return windowList; + } + + /** + * Returns the number of desktops. + * + * @return number of desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktopCount() throws X11Exception { + Window root = getRootWindow(); + + try { + return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); + } catch (X11Exception e) { + try { + return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); + } + } + } + + /** + * Returns the number of the active desktop. + * + * @return number of the active desktop + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getActiveDesktopNumber() throws X11Exception { + Window root = getRootWindow(); + int cur_desktop; + + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); + } catch (X11Exception e) { + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); + } + } + + return cur_desktop; + } + + /** + * Returns the available desktops. + * + * @return available desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public Desktop[] getDesktops() throws X11Exception { + Window root = getRootWindow(); + String[] desktopNames; + try { + desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); + } catch (X11Exception e) { + try { + desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); + } + } + + Desktop[] desktops = new Desktop[getDesktopCount()]; + for (int i = 0; i < desktops.length; i++) { + desktops[i] = new Desktop(this, i, desktopNames[i]); + } + + return desktops; + } + + /** + * Switches to the given desktop. + * + * @param nr desktop number + * @throws X11Exception thrown if X11 window errors occurred + */ + public void switchDesktop(int nr) throws X11Exception { + getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); + } + + /** + * Sets the "showing the desktop" state. + * + * @param state true if the desktop should be shown + * @throws X11Exception thrown if X11 window errors occurred + */ + public void showingDesktop(boolean state) throws X11Exception { + getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); + } + + /** + * Enables / disables the auto-repeat of pressed keys. + * + * @param on true if auto-repeat shall be enabled + */ + public void setKeyAutoRepeat(boolean on) { + if (on) { + x11.XAutoRepeatOn(x11Display); + } else { + x11.XAutoRepeatOff(x11Display); + } + } + + /** + * Returns the key symbol corresponding to the the key name. + * + * @param keyName name of the key + * @return key symbol + */ + public X11.KeySym getKeySym(String keyName) { + return x11.XStringToKeysym(keyName); + } + + /** + * Returns the key symbol corresponding to the keycode. + * + * @param keyCode keycode + * @param index element of the keycode vector + * @return key symbol + */ + public X11.KeySym getKeySym(byte keyCode, int index) { + return x11.XKeycodeToKeysym(x11Display, keyCode, index); + } + + /** + * Returns the keycode corresponding to the key symbol. + * + * @param keySym key symbol + * @return keycode + */ + public byte getKeyCode(X11.KeySym keySym) { + return x11.XKeysymToKeycode(x11Display, keySym); + } + + /** + * Returns the keycode corresponding to the key name. + * + * @param keyName name of the key + * @return keycode + */ + public byte getKeyCode(String keyName) { + return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); + } + + /** + * Returns the key name corresponding to the key symbol. + * + * @param keySym key symbol + * @return name of the key + */ + public String getKeyName(X11.KeySym keySym) { + return x11.XKeysymToString(keySym); + } + + /** + * Returns the key name corresponding to the keycode and the index in the keycode vector. + * + * @param keyCode keycode + * @param index index in the keycode vector + * @return name of the key + */ + public String getKeyName(byte keyCode, int index) { + return getKeyName(getKeySym(keyCode, index)); + } + + /** + * Returns the modifier keymap. + * + * @return modifier keymap + */ + public ModifierKeymap getModifierKeymap() { + X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); + ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); + x11.XFreeModifiermap(xModifierKeymapRef); + return modifierKeymap; + } + + /** + * Sets the modifier keymap. + * + * @param modifierKeymap modifier keymap + */ + public void setModifierKeymap(ModifierKeymap modifierKeymap) { + X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); + x11.XSetModifierMapping(x11Display,xModifierKeymapRef); + } + } + + + /** + * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 + * contain the keycodes as Byte objects. You can directly access these lists to + * read, replace, remove or insert new keycodes to these modifiers. + * To apply a new modifier keymap call + * {@link X.Display#setModifierKeymap(ModifierKeymap)}. + */ + public static class ModifierKeymap { + /** Shift modifier as an ArrayList<Byte>. */ + public ArrayList shift = new ArrayList(4); + /** Lock modifier as an ArrayList<Byte>. */ + public ArrayList lock = new ArrayList(4); + /** Control modifier as an ArrayList<Byte>. */ + public ArrayList control = new ArrayList(4); + /** Mod1 modifier as an ArrayList<Byte>. */ + public ArrayList mod1 = new ArrayList(4); + /** Mod2 modifier as an ArrayList<Byte>. */ + public ArrayList mod2 = new ArrayList(4); + /** Mod3 modifier as an ArrayList<Byte>. */ + public ArrayList mod3 = new ArrayList(4); + /** Mod4 modifier as an ArrayList<Byte>. */ + public ArrayList mod4 = new ArrayList(4); + /** Mod5 modifier as an ArrayList<Byte>. */ + public ArrayList mod5 = new ArrayList(4); + + /** + * Creates an empty modifier keymap. + */ + public ModifierKeymap() { + } + + /** + * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + fromXModifierKeymap(xModifierKeymapRef); + } + + /** + * Reads all modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + int count = xModifierKeymapRef.max_keypermod; + byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); + + ArrayList[] allModifiers = getAllModifiers(); + + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + modifier.clear(); + + for (int keyNr = 0; keyNr < count; keyNr++) { + byte key = keys[modNr*count + keyNr]; + if (key != 0) { + modifier.add(new Byte(key)); + } + } + } + } + + /** + * Returns an XModifierKeymap corresponding to this object. + * + * @return XModifierKeymap + */ + public X11.XModifierKeymapRef toXModifierKeyamp() { + ArrayList[] allModifiers = getAllModifiers(); + + // determine max list size + int count = 0; + for (int i = 0; i < allModifiers.length; i++) { + count = Math.max(count, allModifiers[i].size()); + } + + byte[] keys = new byte[8*count]; + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + + for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { + keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); + } + } + + X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); + xModifierKeymapRef.max_keypermod = count; + xModifierKeymapRef.modifiermap = new Memory(keys.length); + xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); + + return xModifierKeymapRef; + } + + /** + * Returns all modifiers as an array. + * + * @return array of modifier lists + */ + public ArrayList[] getAllModifiers() { + return new ArrayList[] { + shift, lock, control, mod1, mod2, mod3, mod4, mod5 + }; + } + } + + /** + * X Desktop. + */ + public static class Desktop { + public X.Display display; + public int number; + public String name; + + public Desktop(Display display, int number, String name) { + this.display = display; + this.number = number; + this.name = name; + } + } + + + /** + * X Window. + */ + public static class Window { + private X.Display display; + private X11.Window x11Window; + + /** + * Returns the X11 window object. + * + * @return X11 window + */ + public X11.Window getX11Window() { + return x11Window; + } + + /** + * Returns the ID of the window. + * + * @return window ID + */ + public int getID() { + return x11Window.intValue(); + } + + /** + * Creates the window. + * + * @param display display where the window is allocated + * @param x11Window X11 window + */ + public Window(X.Display display, X11.Window x11Window) { + this.display = display; + this.x11Window = x11Window; + } + + /** + * Returns the title of the window. + * + * @return title of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getTitle() throws X11Exception { + try { + return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); + } catch (X11Exception e) { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); + } + + } + + /** + * Returns the window class. + * + * @return window class + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getWindowClass() throws X11Exception { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); + } + + /** + * Returns the PID of the window. + * + * @return PID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getPID() throws X11Exception { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); + } + + /** + * Returns the desktop ID of the window. + * + * @return desktop ID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktop() throws X11Exception { + try { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); + } catch (X11Exception e) { + return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } + } + + /** + * Returns the client machine name of the window. + * + * @return client machine name of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getMachine() throws X11Exception { + return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); + } + + /** + * Returns the XWindowAttributes of the window. + * + * @return XWindowAttributes of the window + */ + public X11.XWindowAttributes getXWindowAttributes() { + X11.XWindowAttributes xwa = new X11.XWindowAttributes(); + x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); + + return xwa; + } + + /** + * Returns the geometry of the window. + * + * @return geometry of the window + */ + public Geometry getGeometry() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference borderWidth = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), + borderWidth.getValue(), depth.getValue()); + } + + /** + * Returns the bounding box of the window. + * + * @return bounding box of the window + */ + public Rectangle getBounds() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference border_width = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + int xVal = x.getValue(); + int yVal = y.getValue(); + + return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); + } + + /** + * Activates the window. + * + * @throws X11Exception thrown if X11 window errors occurred + */ + public void activate() throws X11Exception { + clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); + x11.XMapRaised(display.x11Display, x11Window); + } + + /** + * Moves the window to the specified desktop. + * + * @param desktopNr desktop + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int moveToDesktop(int desktopNr) throws X11Exception { + return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); + } + + /** + * Selects the input events to listen for. + * + * @param eventMask event mask representing the events to listen for + */ + public void selectInput(int eventMask) { + x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); + } + + public int nextEvent(X11.XEvent event) { + return x11.XNextEvent(display.x11Display, event); + } + + public void sendEvent(int eventMask, X11.XEvent event) { + x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); + } + + /** + * Closes the window gracefully. + * + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int close() throws X11Exception { + return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } + X11.Window x11Window = new X11.Window(windowId); + return new Window(display, x11Window); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); + byte[] bytesDest; + + if( bytesOrig == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytesOrig.length; i++) { + if (bytesOrig[i] == '\0') break; + } + + if (i < bytesOrig.length - 1) { + bytesDest = new byte[i + 1]; + System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); + } else { + bytesDest = bytesOrig; + } + + return bytesDest; + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + + if( bytes == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytes.length; i++) { + if (bytes[i] == '\0') { + bytes[i] = '.'; + } + } + + return bytes; + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list, or null if the property value does not exist + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); + IntByReference ret_format_ref = new IntByReference(); + NativeLongByReference ret_nitems_ref = new NativeLongByReference(); + NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); + PointerByReference ret_prop_ref = new PointerByReference(); + + NativeLong long_offset = new NativeLong(0); + NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); + + /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): + * + * long_length = Specifies the length in 32-bit multiples of the + * data to be retrieved. + */ + if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, + xa_prop_type, xa_ret_type_ref, ret_format_ref, + ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Cannot get " + prop_name + " property."); + } + + X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); + Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } + + if (xa_ret_type == null || xa_prop_type == null || + !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { + x11.XFree(ret_prop); + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Invalid type of " + prop_name + " property"); + } + + int ret_format = ret_format_ref.getValue(); + long ret_nitems = ret_nitems_ref.getValue().longValue(); + + // null terminate the result to make string handling easier + int nbytes; + if (ret_format == 32) + nbytes = Native.LONG_SIZE; + else if (ret_format == 16) + nbytes = Native.LONG_SIZE / 2; + else if (ret_format == 8) + nbytes = 1; + else if (ret_format == 0) + nbytes = 0; + else + throw new X11Exception("Invalid return format"); + int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); + + byte[] ret = ret_prop.getByteArray(0, length); + + x11.XFree(ret_prop); + return ret; + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { + return clientMsg( + msg, + new NativeLong(data0), + new NativeLong(data1), + new NativeLong(data2), + new NativeLong(data3), + new NativeLong(data4) + ); + } + + public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { + X11.XClientMessageEvent event; + NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); + + event = new X11.XClientMessageEvent(); + event.type = X11.ClientMessage; + event.serial = new NativeLong(0); + event.send_event = 1; + event.message_type = display.getAtom(msg); + event.window = x11Window; + event.format = 32; + event.data.setType(NativeLong[].class); + event.data.l[0] = data0; + event.data.l[1] = data1; + event.data.l[2] = data2; + event.data.l[3] = data3; + event.data.l[4] = data4; + + X11.XEvent e = new X11.XEvent(); + e.setTypedValue(event); + + if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { + return X11.Success; + } else { + throw new X11Exception("Cannot send " + msg + " event."); + } + } + + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + //Depending on if we're running on 64-bit or 32-bit systems, + //the long size may be different; we need to make sure that + //we get the data properly no matter what + if( Native.LONG_SIZE == 4 ){ + int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + }else if( Native.LONG_SIZE == 8 ){ + long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + } + + x11.XFree( children.getValue() ); + + return retVal; + } + + public String toString() { + return x11Window.toString(); + } + + public static class Geometry { + public int x, y, width, height, borderWidth, depth; + + public Geometry(int x, int y, int width, int height, int border_width, int depth) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.borderWidth = border_width; + this.depth = depth; + } + } + } + + /** + * General exception which is thrown when an X11 window error occurred. + */ + public static class X11Exception extends Exception { + private static final long serialVersionUID = 1L; + public X11Exception() { + } + + public X11Exception(String message) { + super(message); + } + + public X11Exception(String message, Throwable cause) { + super(message, cause); + } + + public X11Exception(Throwable cause) { + super(cause); + } + } } From 7983a5b14747278b36fa45a1f42db2c45fb0451e Mon Sep 17 00:00:00 2001 From: rm5248 Date: Sat, 19 Jul 2014 12:24:06 -0400 Subject: [PATCH 03/13] fixed indentation to be spaces instead of tabs --- contrib/x11/src/jnacontrib/x11/api/X.java | 2266 ++++++++++----------- 1 file changed, 1133 insertions(+), 1133 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index 239e373599..7bacfb7c3b 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -39,1137 +39,1137 @@ * @author Stefan Endrullis */ public class X { - /** Remove/unset property. */ - public static final int _NET_WM_STATE_REMOVE = 0; - /** Add/set property. */ - public static final int _NET_WM_STATE_ADD = 1; - /** Toggle property. */ - public static final int _NET_WM_STATE_TOGGLE = 2; - /** Maximal property value length. */ - public static final int MAX_PROPERTY_VALUE_LEN = 4096; - - private static final X11 x11 = X11.INSTANCE; - - private static int bytesToInt(byte[] prop) { - return ((prop[3] & 0xff) << 24) - | ((prop[2] & 0xff) << 16) - | ((prop[1] & 0xff) << 8) - | ((prop[0] & 0xff)); - } - - private static int bytesToInt(byte[] prop, int offset) { - return ((prop[3 + offset] & 0xff) << 24) - | ((prop[2 + offset] & 0xff) << 16) - | ((prop[1 + offset] & 0xff) << 8) - | ((prop[offset] & 0xff)); - } - - - /** - * X Display. - */ - public static class Display { - /** - * Open display. - */ - private X11.Display x11Display; - /** - * HashMap. - */ - private HashMap atomsHash = new HashMap(); - - /** - * Creates the OOWindowUtils using the default display. - */ - public Display() { - x11Display = x11.XOpenDisplay(null); - - if (x11Display == null) { - throw new Error("Can't open X Display"); - } - } - - /** - * Creates the OOWindowUtils using a given display. - * - * @param x11Display open display - */ - public Display(X11.Display x11Display) { - this.x11Display = x11Display; - - if (x11Display == null) { - throw new Error("X Display is null"); - } - } - - /** - * Closes the display. - */ - public void close() { - x11.XCloseDisplay(x11Display); - } - - /** - * Flushes the output buffer / event queue. - */ - public void flush() { - x11.XFlush(x11Display); - } - - /** - * Returns the X11 display. - * - * @return X11 display - */ - public X11.Display getX11Display() { - return x11Display; - } - - /** - * Get internal atoms by name. - * - * @param name name of the atom - * @return atom - */ - public X11.Atom getAtom(String name) { - X11.Atom atom = atomsHash.get(name); - if (atom == null) { - atom = x11.XInternAtom(x11Display, name, false); - atomsHash.put(name, atom); - } - return atom; - } - - /** - * Returns the window manager information as an window. - * - * @return window manager information as an window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowManagerInfo() throws X11Exception { - Window rootWindow = getRootWindow(); - - try { - return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); - } catch (X11Exception e) { - try { - return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); - } - } - } - - /** - * Returns the root window. - * - * @return root window - */ - public Window getRootWindow() { - return new Window(this, x11.XDefaultRootWindow(x11Display)); - } - - /** - * Returns the current active window. - * - * @return current active window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getActiveWindow() throws X11Exception { - return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); - } - - /** - * Returns all windows managed by the window manager. - * - * @return all windows managed by the window manager - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window[] getWindows() throws X11Exception { - byte[] bytes; - Window rootWindow = getRootWindow(); - - try { - bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); - } catch (X11Exception e) { - try { - bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); - } - } - - Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; - - for (int i = 0; i < windowList.length; i++) { - windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); - } - - return windowList; - } - - /** - * Returns the number of desktops. - * - * @return number of desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktopCount() throws X11Exception { - Window root = getRootWindow(); - - try { - return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); - } catch (X11Exception e) { - try { - return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); - } - } - } - - /** - * Returns the number of the active desktop. - * - * @return number of the active desktop - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getActiveDesktopNumber() throws X11Exception { - Window root = getRootWindow(); - int cur_desktop; - - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); - } catch (X11Exception e) { - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); - } - } - - return cur_desktop; - } - - /** - * Returns the available desktops. - * - * @return available desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public Desktop[] getDesktops() throws X11Exception { - Window root = getRootWindow(); - String[] desktopNames; - try { - desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); - } catch (X11Exception e) { - try { - desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); - } - } - - Desktop[] desktops = new Desktop[getDesktopCount()]; - for (int i = 0; i < desktops.length; i++) { - desktops[i] = new Desktop(this, i, desktopNames[i]); - } - - return desktops; - } - - /** - * Switches to the given desktop. - * - * @param nr desktop number - * @throws X11Exception thrown if X11 window errors occurred - */ - public void switchDesktop(int nr) throws X11Exception { - getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); - } - - /** - * Sets the "showing the desktop" state. - * - * @param state true if the desktop should be shown - * @throws X11Exception thrown if X11 window errors occurred - */ - public void showingDesktop(boolean state) throws X11Exception { - getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); - } - - /** - * Enables / disables the auto-repeat of pressed keys. - * - * @param on true if auto-repeat shall be enabled - */ - public void setKeyAutoRepeat(boolean on) { - if (on) { - x11.XAutoRepeatOn(x11Display); - } else { - x11.XAutoRepeatOff(x11Display); - } - } - - /** - * Returns the key symbol corresponding to the the key name. - * - * @param keyName name of the key - * @return key symbol - */ - public X11.KeySym getKeySym(String keyName) { - return x11.XStringToKeysym(keyName); - } - - /** - * Returns the key symbol corresponding to the keycode. - * - * @param keyCode keycode - * @param index element of the keycode vector - * @return key symbol - */ - public X11.KeySym getKeySym(byte keyCode, int index) { - return x11.XKeycodeToKeysym(x11Display, keyCode, index); - } - - /** - * Returns the keycode corresponding to the key symbol. - * - * @param keySym key symbol - * @return keycode - */ - public byte getKeyCode(X11.KeySym keySym) { - return x11.XKeysymToKeycode(x11Display, keySym); - } - - /** - * Returns the keycode corresponding to the key name. - * - * @param keyName name of the key - * @return keycode - */ - public byte getKeyCode(String keyName) { - return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); - } - - /** - * Returns the key name corresponding to the key symbol. - * - * @param keySym key symbol - * @return name of the key - */ - public String getKeyName(X11.KeySym keySym) { - return x11.XKeysymToString(keySym); - } - - /** - * Returns the key name corresponding to the keycode and the index in the keycode vector. - * - * @param keyCode keycode - * @param index index in the keycode vector - * @return name of the key - */ - public String getKeyName(byte keyCode, int index) { - return getKeyName(getKeySym(keyCode, index)); - } - - /** - * Returns the modifier keymap. - * - * @return modifier keymap - */ - public ModifierKeymap getModifierKeymap() { - X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); - ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); - x11.XFreeModifiermap(xModifierKeymapRef); - return modifierKeymap; - } - - /** - * Sets the modifier keymap. - * - * @param modifierKeymap modifier keymap - */ - public void setModifierKeymap(ModifierKeymap modifierKeymap) { - X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); - x11.XSetModifierMapping(x11Display,xModifierKeymapRef); - } - } - - - /** - * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 - * contain the keycodes as Byte objects. You can directly access these lists to - * read, replace, remove or insert new keycodes to these modifiers. - * To apply a new modifier keymap call - * {@link X.Display#setModifierKeymap(ModifierKeymap)}. - */ - public static class ModifierKeymap { - /** Shift modifier as an ArrayList<Byte>. */ - public ArrayList shift = new ArrayList(4); - /** Lock modifier as an ArrayList<Byte>. */ - public ArrayList lock = new ArrayList(4); - /** Control modifier as an ArrayList<Byte>. */ - public ArrayList control = new ArrayList(4); - /** Mod1 modifier as an ArrayList<Byte>. */ - public ArrayList mod1 = new ArrayList(4); - /** Mod2 modifier as an ArrayList<Byte>. */ - public ArrayList mod2 = new ArrayList(4); - /** Mod3 modifier as an ArrayList<Byte>. */ - public ArrayList mod3 = new ArrayList(4); - /** Mod4 modifier as an ArrayList<Byte>. */ - public ArrayList mod4 = new ArrayList(4); - /** Mod5 modifier as an ArrayList<Byte>. */ - public ArrayList mod5 = new ArrayList(4); - - /** - * Creates an empty modifier keymap. - */ - public ModifierKeymap() { - } - - /** - * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - fromXModifierKeymap(xModifierKeymapRef); - } - - /** - * Reads all modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - int count = xModifierKeymapRef.max_keypermod; - byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); - - ArrayList[] allModifiers = getAllModifiers(); - - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - modifier.clear(); - - for (int keyNr = 0; keyNr < count; keyNr++) { - byte key = keys[modNr*count + keyNr]; - if (key != 0) { - modifier.add(new Byte(key)); - } - } - } - } - - /** - * Returns an XModifierKeymap corresponding to this object. - * - * @return XModifierKeymap - */ - public X11.XModifierKeymapRef toXModifierKeyamp() { - ArrayList[] allModifiers = getAllModifiers(); - - // determine max list size - int count = 0; - for (int i = 0; i < allModifiers.length; i++) { - count = Math.max(count, allModifiers[i].size()); - } - - byte[] keys = new byte[8*count]; - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - - for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { - keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); - } - } - - X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); - xModifierKeymapRef.max_keypermod = count; - xModifierKeymapRef.modifiermap = new Memory(keys.length); - xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); - - return xModifierKeymapRef; - } - - /** - * Returns all modifiers as an array. - * - * @return array of modifier lists - */ - public ArrayList[] getAllModifiers() { - return new ArrayList[] { - shift, lock, control, mod1, mod2, mod3, mod4, mod5 - }; - } - } - - /** - * X Desktop. - */ - public static class Desktop { - public X.Display display; - public int number; - public String name; - - public Desktop(Display display, int number, String name) { - this.display = display; - this.number = number; - this.name = name; - } - } - - - /** - * X Window. - */ - public static class Window { - private X.Display display; - private X11.Window x11Window; - - /** - * Returns the X11 window object. - * - * @return X11 window - */ - public X11.Window getX11Window() { - return x11Window; - } - - /** - * Returns the ID of the window. - * - * @return window ID - */ - public int getID() { - return x11Window.intValue(); - } - - /** - * Creates the window. - * - * @param display display where the window is allocated - * @param x11Window X11 window - */ - public Window(X.Display display, X11.Window x11Window) { - this.display = display; - this.x11Window = x11Window; - } - - /** - * Returns the title of the window. - * - * @return title of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getTitle() throws X11Exception { - try { - return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); - } catch (X11Exception e) { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); - } - - } - - /** - * Returns the window class. - * - * @return window class - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getWindowClass() throws X11Exception { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); - } - - /** - * Returns the PID of the window. - * - * @return PID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getPID() throws X11Exception { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); - } - - /** - * Returns the desktop ID of the window. - * - * @return desktop ID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktop() throws X11Exception { - try { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); - } catch (X11Exception e) { - return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } - } - - /** - * Returns the client machine name of the window. - * - * @return client machine name of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getMachine() throws X11Exception { - return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); - } - - /** - * Returns the XWindowAttributes of the window. - * - * @return XWindowAttributes of the window - */ - public X11.XWindowAttributes getXWindowAttributes() { - X11.XWindowAttributes xwa = new X11.XWindowAttributes(); - x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); - - return xwa; - } - - /** - * Returns the geometry of the window. - * - * @return geometry of the window - */ - public Geometry getGeometry() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference borderWidth = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), - borderWidth.getValue(), depth.getValue()); - } - - /** - * Returns the bounding box of the window. - * - * @return bounding box of the window - */ - public Rectangle getBounds() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference border_width = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - int xVal = x.getValue(); - int yVal = y.getValue(); - - return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); - } - - /** - * Activates the window. - * - * @throws X11Exception thrown if X11 window errors occurred - */ - public void activate() throws X11Exception { - clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); - x11.XMapRaised(display.x11Display, x11Window); - } - - /** - * Moves the window to the specified desktop. - * - * @param desktopNr desktop - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int moveToDesktop(int desktopNr) throws X11Exception { - return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); - } - - /** - * Selects the input events to listen for. - * - * @param eventMask event mask representing the events to listen for - */ - public void selectInput(int eventMask) { - x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); - } - - public int nextEvent(X11.XEvent event) { - return x11.XNextEvent(display.x11Display, event); - } - - public void sendEvent(int eventMask, X11.XEvent event) { - x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); - } - - /** - * Closes the window gracefully. - * - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int close() throws X11Exception { - return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return bytesToInt(property); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); - if( windowId == null ){ - return null; - } - X11.Window x11Window = new X11.Window(windowId); - return new Window(display, x11Window); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); - byte[] bytesDest; - - if( bytesOrig == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytesOrig.length; i++) { - if (bytesOrig[i] == '\0') break; - } - - if (i < bytesOrig.length - 1) { - bytesDest = new byte[i + 1]; - System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); - } else { - bytesDest = bytesOrig; - } - - return bytesDest; - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytes = getProperty(xa_prop_type, xa_prop_name); - - if( bytes == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytes.length; i++) { - if (bytes[i] == '\0') { - bytes[i] = '.'; - } - } - - return bytes; - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list, or null if the property value does not exist - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property).split("\0"); - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property, "UTF8"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); - IntByReference ret_format_ref = new IntByReference(); - NativeLongByReference ret_nitems_ref = new NativeLongByReference(); - NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); - PointerByReference ret_prop_ref = new PointerByReference(); - - NativeLong long_offset = new NativeLong(0); - NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); - - /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): - * - * long_length = Specifies the length in 32-bit multiples of the - * data to be retrieved. - */ - if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, - xa_prop_type, xa_ret_type_ref, ret_format_ref, - ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Cannot get " + prop_name + " property."); - } - - X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); - Pointer ret_prop = ret_prop_ref.getValue(); - - if( xa_ret_type == null ){ - //the specified property does not exist for the specified window - return null; - } - - if (xa_ret_type == null || xa_prop_type == null || - !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { - x11.XFree(ret_prop); - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Invalid type of " + prop_name + " property"); - } - - int ret_format = ret_format_ref.getValue(); - long ret_nitems = ret_nitems_ref.getValue().longValue(); - - // null terminate the result to make string handling easier - int nbytes; - if (ret_format == 32) - nbytes = Native.LONG_SIZE; - else if (ret_format == 16) - nbytes = Native.LONG_SIZE / 2; - else if (ret_format == 8) - nbytes = 1; - else if (ret_format == 0) - nbytes = 0; - else - throw new X11Exception("Invalid return format"); - int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); - - byte[] ret = ret_prop.getByteArray(0, length); - - x11.XFree(ret_prop); - return ret; - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { - return clientMsg( - msg, - new NativeLong(data0), - new NativeLong(data1), - new NativeLong(data2), - new NativeLong(data3), - new NativeLong(data4) - ); - } - - public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { - X11.XClientMessageEvent event; - NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); - - event = new X11.XClientMessageEvent(); - event.type = X11.ClientMessage; - event.serial = new NativeLong(0); - event.send_event = 1; - event.message_type = display.getAtom(msg); - event.window = x11Window; - event.format = 32; - event.data.setType(NativeLong[].class); - event.data.l[0] = data0; - event.data.l[1] = data1; - event.data.l[2] = data2; - event.data.l[3] = data3; - event.data.l[4] = data4; - - X11.XEvent e = new X11.XEvent(); - e.setTypedValue(event); - - if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { - return X11.Success; - } else { - throw new X11Exception("Cannot send " + msg + " event."); - } - } - - public Window[] getSubwindows() throws X11Exception { - WindowByReference root = new WindowByReference(); - WindowByReference parent = new WindowByReference(); - PointerByReference children = new PointerByReference(); - IntByReference childCount = new IntByReference(); - - if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ - throw new X11Exception("Can't query subwindows"); - } - - if( childCount.getValue() == 0 ){ - return null; - } - - Window[] retVal = new Window[ childCount.getValue() ]; - //Depending on if we're running on 64-bit or 32-bit systems, - //the long size may be different; we need to make sure that - //we get the data properly no matter what - if( Native.LONG_SIZE == 4 ){ - int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); - for( int x = 0; x < retVal.length; x++ ){ - X11.Window win = new X11.Window( windows [ x ] ); - retVal[ x ] = new Window( display, win ); - } - }else if( Native.LONG_SIZE == 8 ){ - long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); - for( int x = 0; x < retVal.length; x++ ){ - X11.Window win = new X11.Window( windows [ x ] ); - retVal[ x ] = new Window( display, win ); - } - } - - x11.XFree( children.getValue() ); - - return retVal; - } - - public String toString() { - return x11Window.toString(); - } - - public static class Geometry { - public int x, y, width, height, borderWidth, depth; - - public Geometry(int x, int y, int width, int height, int border_width, int depth) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.borderWidth = border_width; - this.depth = depth; - } - } - } - - /** - * General exception which is thrown when an X11 window error occurred. - */ - public static class X11Exception extends Exception { - private static final long serialVersionUID = 1L; - public X11Exception() { - } - - public X11Exception(String message) { - super(message); - } - - public X11Exception(String message, Throwable cause) { - super(message, cause); - } - - public X11Exception(Throwable cause) { - super(cause); - } - } + /** Remove/unset property. */ + public static final int _NET_WM_STATE_REMOVE = 0; + /** Add/set property. */ + public static final int _NET_WM_STATE_ADD = 1; + /** Toggle property. */ + public static final int _NET_WM_STATE_TOGGLE = 2; + /** Maximal property value length. */ + public static final int MAX_PROPERTY_VALUE_LEN = 4096; + + private static final X11 x11 = X11.INSTANCE; + + private static int bytesToInt(byte[] prop) { + return ((prop[3] & 0xff) << 24) + | ((prop[2] & 0xff) << 16) + | ((prop[1] & 0xff) << 8) + | ((prop[0] & 0xff)); + } + + private static int bytesToInt(byte[] prop, int offset) { + return ((prop[3 + offset] & 0xff) << 24) + | ((prop[2 + offset] & 0xff) << 16) + | ((prop[1 + offset] & 0xff) << 8) + | ((prop[offset] & 0xff)); + } + + + /** + * X Display. + */ + public static class Display { + /** + * Open display. + */ + private X11.Display x11Display; + /** + * HashMap. + */ + private HashMap atomsHash = new HashMap(); + + /** + * Creates the OOWindowUtils using the default display. + */ + public Display() { + x11Display = x11.XOpenDisplay(null); + + if (x11Display == null) { + throw new Error("Can't open X Display"); + } + } + + /** + * Creates the OOWindowUtils using a given display. + * + * @param x11Display open display + */ + public Display(X11.Display x11Display) { + this.x11Display = x11Display; + + if (x11Display == null) { + throw new Error("X Display is null"); + } + } + + /** + * Closes the display. + */ + public void close() { + x11.XCloseDisplay(x11Display); + } + + /** + * Flushes the output buffer / event queue. + */ + public void flush() { + x11.XFlush(x11Display); + } + + /** + * Returns the X11 display. + * + * @return X11 display + */ + public X11.Display getX11Display() { + return x11Display; + } + + /** + * Get internal atoms by name. + * + * @param name name of the atom + * @return atom + */ + public X11.Atom getAtom(String name) { + X11.Atom atom = atomsHash.get(name); + if (atom == null) { + atom = x11.XInternAtom(x11Display, name, false); + atomsHash.put(name, atom); + } + return atom; + } + + /** + * Returns the window manager information as an window. + * + * @return window manager information as an window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowManagerInfo() throws X11Exception { + Window rootWindow = getRootWindow(); + + try { + return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); + } catch (X11Exception e) { + try { + return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); + } + } + } + + /** + * Returns the root window. + * + * @return root window + */ + public Window getRootWindow() { + return new Window(this, x11.XDefaultRootWindow(x11Display)); + } + + /** + * Returns the current active window. + * + * @return current active window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getActiveWindow() throws X11Exception { + return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); + } + + /** + * Returns all windows managed by the window manager. + * + * @return all windows managed by the window manager + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window[] getWindows() throws X11Exception { + byte[] bytes; + Window rootWindow = getRootWindow(); + + try { + bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); + } catch (X11Exception e) { + try { + bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); + } + } + + Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; + + for (int i = 0; i < windowList.length; i++) { + windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); + } + + return windowList; + } + + /** + * Returns the number of desktops. + * + * @return number of desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktopCount() throws X11Exception { + Window root = getRootWindow(); + + try { + return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); + } catch (X11Exception e) { + try { + return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); + } + } + } + + /** + * Returns the number of the active desktop. + * + * @return number of the active desktop + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getActiveDesktopNumber() throws X11Exception { + Window root = getRootWindow(); + int cur_desktop; + + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); + } catch (X11Exception e) { + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); + } + } + + return cur_desktop; + } + + /** + * Returns the available desktops. + * + * @return available desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public Desktop[] getDesktops() throws X11Exception { + Window root = getRootWindow(); + String[] desktopNames; + try { + desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); + } catch (X11Exception e) { + try { + desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); + } + } + + Desktop[] desktops = new Desktop[getDesktopCount()]; + for (int i = 0; i < desktops.length; i++) { + desktops[i] = new Desktop(this, i, desktopNames[i]); + } + + return desktops; + } + + /** + * Switches to the given desktop. + * + * @param nr desktop number + * @throws X11Exception thrown if X11 window errors occurred + */ + public void switchDesktop(int nr) throws X11Exception { + getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); + } + + /** + * Sets the "showing the desktop" state. + * + * @param state true if the desktop should be shown + * @throws X11Exception thrown if X11 window errors occurred + */ + public void showingDesktop(boolean state) throws X11Exception { + getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); + } + + /** + * Enables / disables the auto-repeat of pressed keys. + * + * @param on true if auto-repeat shall be enabled + */ + public void setKeyAutoRepeat(boolean on) { + if (on) { + x11.XAutoRepeatOn(x11Display); + } else { + x11.XAutoRepeatOff(x11Display); + } + } + + /** + * Returns the key symbol corresponding to the the key name. + * + * @param keyName name of the key + * @return key symbol + */ + public X11.KeySym getKeySym(String keyName) { + return x11.XStringToKeysym(keyName); + } + + /** + * Returns the key symbol corresponding to the keycode. + * + * @param keyCode keycode + * @param index element of the keycode vector + * @return key symbol + */ + public X11.KeySym getKeySym(byte keyCode, int index) { + return x11.XKeycodeToKeysym(x11Display, keyCode, index); + } + + /** + * Returns the keycode corresponding to the key symbol. + * + * @param keySym key symbol + * @return keycode + */ + public byte getKeyCode(X11.KeySym keySym) { + return x11.XKeysymToKeycode(x11Display, keySym); + } + + /** + * Returns the keycode corresponding to the key name. + * + * @param keyName name of the key + * @return keycode + */ + public byte getKeyCode(String keyName) { + return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); + } + + /** + * Returns the key name corresponding to the key symbol. + * + * @param keySym key symbol + * @return name of the key + */ + public String getKeyName(X11.KeySym keySym) { + return x11.XKeysymToString(keySym); + } + + /** + * Returns the key name corresponding to the keycode and the index in the keycode vector. + * + * @param keyCode keycode + * @param index index in the keycode vector + * @return name of the key + */ + public String getKeyName(byte keyCode, int index) { + return getKeyName(getKeySym(keyCode, index)); + } + + /** + * Returns the modifier keymap. + * + * @return modifier keymap + */ + public ModifierKeymap getModifierKeymap() { + X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); + ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); + x11.XFreeModifiermap(xModifierKeymapRef); + return modifierKeymap; + } + + /** + * Sets the modifier keymap. + * + * @param modifierKeymap modifier keymap + */ + public void setModifierKeymap(ModifierKeymap modifierKeymap) { + X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); + x11.XSetModifierMapping(x11Display,xModifierKeymapRef); + } + } + + + /** + * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 + * contain the keycodes as Byte objects. You can directly access these lists to + * read, replace, remove or insert new keycodes to these modifiers. + * To apply a new modifier keymap call + * {@link X.Display#setModifierKeymap(ModifierKeymap)}. + */ + public static class ModifierKeymap { + /** Shift modifier as an ArrayList<Byte>. */ + public ArrayList shift = new ArrayList(4); + /** Lock modifier as an ArrayList<Byte>. */ + public ArrayList lock = new ArrayList(4); + /** Control modifier as an ArrayList<Byte>. */ + public ArrayList control = new ArrayList(4); + /** Mod1 modifier as an ArrayList<Byte>. */ + public ArrayList mod1 = new ArrayList(4); + /** Mod2 modifier as an ArrayList<Byte>. */ + public ArrayList mod2 = new ArrayList(4); + /** Mod3 modifier as an ArrayList<Byte>. */ + public ArrayList mod3 = new ArrayList(4); + /** Mod4 modifier as an ArrayList<Byte>. */ + public ArrayList mod4 = new ArrayList(4); + /** Mod5 modifier as an ArrayList<Byte>. */ + public ArrayList mod5 = new ArrayList(4); + + /** + * Creates an empty modifier keymap. + */ + public ModifierKeymap() { + } + + /** + * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + fromXModifierKeymap(xModifierKeymapRef); + } + + /** + * Reads all modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + int count = xModifierKeymapRef.max_keypermod; + byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); + + ArrayList[] allModifiers = getAllModifiers(); + + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + modifier.clear(); + + for (int keyNr = 0; keyNr < count; keyNr++) { + byte key = keys[modNr*count + keyNr]; + if (key != 0) { + modifier.add(new Byte(key)); + } + } + } + } + + /** + * Returns an XModifierKeymap corresponding to this object. + * + * @return XModifierKeymap + */ + public X11.XModifierKeymapRef toXModifierKeyamp() { + ArrayList[] allModifiers = getAllModifiers(); + + // determine max list size + int count = 0; + for (int i = 0; i < allModifiers.length; i++) { + count = Math.max(count, allModifiers[i].size()); + } + + byte[] keys = new byte[8*count]; + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + + for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { + keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); + } + } + + X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); + xModifierKeymapRef.max_keypermod = count; + xModifierKeymapRef.modifiermap = new Memory(keys.length); + xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); + + return xModifierKeymapRef; + } + + /** + * Returns all modifiers as an array. + * + * @return array of modifier lists + */ + public ArrayList[] getAllModifiers() { + return new ArrayList[] { + shift, lock, control, mod1, mod2, mod3, mod4, mod5 + }; + } + } + + /** + * X Desktop. + */ + public static class Desktop { + public X.Display display; + public int number; + public String name; + + public Desktop(Display display, int number, String name) { + this.display = display; + this.number = number; + this.name = name; + } + } + + + /** + * X Window. + */ + public static class Window { + private X.Display display; + private X11.Window x11Window; + + /** + * Returns the X11 window object. + * + * @return X11 window + */ + public X11.Window getX11Window() { + return x11Window; + } + + /** + * Returns the ID of the window. + * + * @return window ID + */ + public int getID() { + return x11Window.intValue(); + } + + /** + * Creates the window. + * + * @param display display where the window is allocated + * @param x11Window X11 window + */ + public Window(X.Display display, X11.Window x11Window) { + this.display = display; + this.x11Window = x11Window; + } + + /** + * Returns the title of the window. + * + * @return title of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getTitle() throws X11Exception { + try { + return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); + } catch (X11Exception e) { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); + } + + } + + /** + * Returns the window class. + * + * @return window class + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getWindowClass() throws X11Exception { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); + } + + /** + * Returns the PID of the window. + * + * @return PID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getPID() throws X11Exception { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); + } + + /** + * Returns the desktop ID of the window. + * + * @return desktop ID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktop() throws X11Exception { + try { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); + } catch (X11Exception e) { + return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } + } + + /** + * Returns the client machine name of the window. + * + * @return client machine name of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getMachine() throws X11Exception { + return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); + } + + /** + * Returns the XWindowAttributes of the window. + * + * @return XWindowAttributes of the window + */ + public X11.XWindowAttributes getXWindowAttributes() { + X11.XWindowAttributes xwa = new X11.XWindowAttributes(); + x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); + + return xwa; + } + + /** + * Returns the geometry of the window. + * + * @return geometry of the window + */ + public Geometry getGeometry() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference borderWidth = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), + borderWidth.getValue(), depth.getValue()); + } + + /** + * Returns the bounding box of the window. + * + * @return bounding box of the window + */ + public Rectangle getBounds() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference border_width = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + int xVal = x.getValue(); + int yVal = y.getValue(); + + return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); + } + + /** + * Activates the window. + * + * @throws X11Exception thrown if X11 window errors occurred + */ + public void activate() throws X11Exception { + clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); + x11.XMapRaised(display.x11Display, x11Window); + } + + /** + * Moves the window to the specified desktop. + * + * @param desktopNr desktop + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int moveToDesktop(int desktopNr) throws X11Exception { + return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); + } + + /** + * Selects the input events to listen for. + * + * @param eventMask event mask representing the events to listen for + */ + public void selectInput(int eventMask) { + x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); + } + + public int nextEvent(X11.XEvent event) { + return x11.XNextEvent(display.x11Display, event); + } + + public void sendEvent(int eventMask, X11.XEvent event) { + x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); + } + + /** + * Closes the window gracefully. + * + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int close() throws X11Exception { + return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } + X11.Window x11Window = new X11.Window(windowId); + return new Window(display, x11Window); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); + byte[] bytesDest; + + if( bytesOrig == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytesOrig.length; i++) { + if (bytesOrig[i] == '\0') break; + } + + if (i < bytesOrig.length - 1) { + bytesDest = new byte[i + 1]; + System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); + } else { + bytesDest = bytesOrig; + } + + return bytesDest; + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + + if( bytes == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytes.length; i++) { + if (bytes[i] == '\0') { + bytes[i] = '.'; + } + } + + return bytes; + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list, or null if the property value does not exist + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); + IntByReference ret_format_ref = new IntByReference(); + NativeLongByReference ret_nitems_ref = new NativeLongByReference(); + NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); + PointerByReference ret_prop_ref = new PointerByReference(); + + NativeLong long_offset = new NativeLong(0); + NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); + + /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): + * + * long_length = Specifies the length in 32-bit multiples of the + * data to be retrieved. + */ + if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, + xa_prop_type, xa_ret_type_ref, ret_format_ref, + ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Cannot get " + prop_name + " property."); + } + + X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); + Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } + + if (xa_ret_type == null || xa_prop_type == null || + !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { + x11.XFree(ret_prop); + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Invalid type of " + prop_name + " property"); + } + + int ret_format = ret_format_ref.getValue(); + long ret_nitems = ret_nitems_ref.getValue().longValue(); + + // null terminate the result to make string handling easier + int nbytes; + if (ret_format == 32) + nbytes = Native.LONG_SIZE; + else if (ret_format == 16) + nbytes = Native.LONG_SIZE / 2; + else if (ret_format == 8) + nbytes = 1; + else if (ret_format == 0) + nbytes = 0; + else + throw new X11Exception("Invalid return format"); + int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); + + byte[] ret = ret_prop.getByteArray(0, length); + + x11.XFree(ret_prop); + return ret; + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { + return clientMsg( + msg, + new NativeLong(data0), + new NativeLong(data1), + new NativeLong(data2), + new NativeLong(data3), + new NativeLong(data4) + ); + } + + public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { + X11.XClientMessageEvent event; + NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); + + event = new X11.XClientMessageEvent(); + event.type = X11.ClientMessage; + event.serial = new NativeLong(0); + event.send_event = 1; + event.message_type = display.getAtom(msg); + event.window = x11Window; + event.format = 32; + event.data.setType(NativeLong[].class); + event.data.l[0] = data0; + event.data.l[1] = data1; + event.data.l[2] = data2; + event.data.l[3] = data3; + event.data.l[4] = data4; + + X11.XEvent e = new X11.XEvent(); + e.setTypedValue(event); + + if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { + return X11.Success; + } else { + throw new X11Exception("Cannot send " + msg + " event."); + } + } + + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + //Depending on if we're running on 64-bit or 32-bit systems, + //the long size may be different; we need to make sure that + //we get the data properly no matter what + if( Native.LONG_SIZE == 4 ){ + int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + }else if( Native.LONG_SIZE == 8 ){ + long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + } + + x11.XFree( children.getValue() ); + + return retVal; + } + + public String toString() { + return x11Window.toString(); + } + + public static class Geometry { + public int x, y, width, height, borderWidth, depth; + + public Geometry(int x, int y, int width, int height, int border_width, int depth) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.borderWidth = border_width; + this.depth = depth; + } + } + } + + /** + * General exception which is thrown when an X11 window error occurred. + */ + public static class X11Exception extends Exception { + private static final long serialVersionUID = 1L; + public X11Exception() { + } + + public X11Exception(String message) { + super(message); + } + + public X11Exception(String message, Throwable cause) { + super(message, cause); + } + + public X11Exception(Throwable cause) { + super(cause); + } + } } From 678caa5e775c5da8dd9acb4100ca40d9ee5c2c21 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Sat, 19 Jul 2014 12:26:27 -0400 Subject: [PATCH 04/13] more fixing of formatting --- .../jnacontrib/x11/demos/XDesktopDemo.java | 740 +++++++++--------- 1 file changed, 370 insertions(+), 370 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java index 785c8d618c..f1e4797a6e 100644 --- a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java +++ b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java @@ -30,397 +30,397 @@ * @author Stefan Endrullis */ public class XDesktopDemo extends JFrame { - private static final long serialVersionUID = 1L; - public static void main(String[] args) throws X.X11Exception { - new XDesktopDemo(); - } + private static final long serialVersionUID = 1L; + public static void main(String[] args) throws X.X11Exception { + new XDesktopDemo(); + } - private X.Display display = new X.Display(); - private JList desktopList; - private JTable windowTable; - private JButton refreshButton; - private JButton moveWindowToDesktopButton; - private JButton goToDesktopButton; - private JButton moveWindowAndGoToDesktopButton; - private JButton closeWindowButton; - private JButton goToWindowButton; - private JButton showDesktop; - private JButton showSubwindows; + private X.Display display = new X.Display(); + private JList desktopList; + private JTable windowTable; + private JButton refreshButton; + private JButton moveWindowToDesktopButton; + private JButton goToDesktopButton; + private JButton moveWindowAndGoToDesktopButton; + private JButton closeWindowButton; + private JButton goToWindowButton; + private JButton showDesktop; + private JButton showSubwindows; - public XDesktopDemo() throws X.X11Exception { - super("XDesktopDemo"); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - initGui(); + public XDesktopDemo() throws X.X11Exception { + super("XDesktopDemo"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + initGui(); - refreshDesktopsAndWindows(); + refreshDesktopsAndWindows(); - pack(); - addListeners(); - setVisible(true); + pack(); + addListeners(); + setVisible(true); - printWmInfo(); - } + printWmInfo(); + } - private void printWmInfo() throws X.X11Exception { - X.Window wm = display.getWindowManagerInfo(); - System.out.println("wm.getTitle() = " + wm.getTitle()); - System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); - System.out.println("wm.getPID() = " + wm.getPID()); - } + private void printWmInfo() throws X.X11Exception { + X.Window wm = display.getWindowManagerInfo(); + System.out.println("wm.getTitle() = " + wm.getTitle()); + System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); + System.out.println("wm.getPID() = " + wm.getPID()); + } - private void addListeners() { - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - refreshDesktopsAndWindows(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - goToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - int desktopNr = desktopList.getSelectedIndex(); - if (desktopNr >= 0) { - try { - display.switchDesktop(desktopNr); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - } - }); - goToWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - showDesktop.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - display.showingDesktop(true); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - closeWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.close(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - showSubwindows.addActionListener(new ActionListener() { - - private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ - X.Window[] subWindows = win.getSubwindows(); - String title = win.getTitle(); - if( title != null ){ - area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); - }else{ - area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); - } - area.append( System.getProperty( "line.separator" ) ); - - if( subWindows == null ){ - return; - } - for( int x = 0; x < subWindows.length; x++ ){ - addWindowsToArea( area, depth + 4, subWindows[ x ] ); - } - } + private void addListeners() { + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + refreshDesktopsAndWindows(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + goToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + int desktopNr = desktopList.getSelectedIndex(); + if (desktopNr >= 0) { + try { + display.switchDesktop(desktopNr); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + } + }); + goToWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showDesktop.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + display.showingDesktop(true); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + closeWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.close(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showSubwindows.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); + private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ + X.Window[] subWindows = win.getSubwindows(); + String title = win.getTitle(); + if( title != null ){ + area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); + }else{ + area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); + } + area.append( System.getProperty( "line.separator" ) ); - try{ - final JDialog jd = new JDialog(); - JPanel dialogPanel = new JPanel( new BorderLayout() ); - jd.setSize( 320, 240 ); - jd.setTitle( "Subwindows" ); - jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); - JTextArea area = new JTextArea(); - addWindowsToArea( area, 1, window ); - dialogPanel.add( area, BorderLayout.CENTER ); - JButton closeButton = new JButton( "Close" ); - closeButton.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - jd.dispose(); - } - }); - dialogPanel.add( closeButton, BorderLayout.SOUTH ); - jd.add( dialogPanel ); - jd.setVisible( true ); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - } + if( subWindows == null ){ + return; + } + for( int x = 0; x < subWindows.length; x++ ){ + addWindowsToArea( area, depth + 4, subWindows[ x ] ); + } + } - private X.Window getSelectedWindow() { - WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); - return tableModel.getWindow(windowTable.getSelectedRow()); - } + @Override + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); - private void refreshDesktopsAndWindows() throws X.X11Exception { - // update desktop list - X.Desktop[] desktops = display.getDesktops(); - ArrayList list = new ArrayList(desktops.length); - for (int i = 0; i < desktops.length; i++) { - list.add(desktops[i].name); - } - desktopList.clearSelection(); - desktopList.setModel(new SimpleListModel(list)); + try{ + final JDialog jd = new JDialog(); + JPanel dialogPanel = new JPanel( new BorderLayout() ); + jd.setSize( 320, 240 ); + jd.setTitle( "Subwindows" ); + jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); + JTextArea area = new JTextArea(); + addWindowsToArea( area, 1, window ); + dialogPanel.add( area, BorderLayout.CENTER ); + JButton closeButton = new JButton( "Close" ); + closeButton.addActionListener( new ActionListener() { - // select active desktop - int activeDesktop = display.getActiveDesktopNumber(); - desktopList.setSelectedIndex(activeDesktop); + @Override + public void actionPerformed(ActionEvent e) { + jd.dispose(); + } + }); + dialogPanel.add( closeButton, BorderLayout.SOUTH ); + jd.add( dialogPanel ); + jd.setVisible( true ); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + } - // update window list - int activeWindowId = display.getActiveWindow().getID(); - int activeWindowNumber = -1; - X.Window[] windows = display.getWindows(); - String[] head = new String[]{ - "ID", "Desktop", "Title", - "X", "Y", "Width", "Height" - }; - String[][] data = new String[windows.length][head.length]; - for (int i = 0; i < windows.length; i++) { - X.Window window = windows[i]; - X.Window.Geometry geo = window.getGeometry(); - int windowId = window.getID(); - data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); - data[i][1] = "" + window.getDesktop(); - data[i][2] = window.getTitle(); - data[i][3] = "" + geo.x; - data[i][4] = "" + geo.y; - data[i][5] = "" + geo.width; - data[i][6] = "" + geo.height; - if (windowId == activeWindowId) { - activeWindowNumber = i; - } - } - windowTable.setModel(new WindowTableModel(head, data, windows)); - if (activeWindowNumber >= 0) { - windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); - } - } + private X.Window getSelectedWindow() { + WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); + return tableModel.getWindow(windowTable.getSelectedRow()); + } - private void initGui() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new GridBagLayout()); - final JPanel panel1 = new JPanel(); - panel1.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 0.8; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel1, gbc); - panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); - desktopList = new JList(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel1.add(desktopList, gbc); - final JPanel panel2 = new JPanel(); - panel2.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel2, gbc); - panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); - final JScrollPane scrollPane1 = new JScrollPane(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel2.add(scrollPane1, gbc); - windowTable = new JTable(); - windowTable.setEnabled(true); - scrollPane1.setViewportView(windowTable); - final JPanel panel3 = new JPanel(); - panel3.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 2; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel3, gbc); - panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); - goToDesktopButton = new JButton(); - goToDesktopButton.setText("go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToDesktopButton, gbc); - refreshButton = new JButton(); - refreshButton.setText("refresh"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(refreshButton, gbc); - goToWindowButton = new JButton(); - goToWindowButton.setText("go to window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToWindowButton, gbc); - moveWindowAndGoToDesktopButton = new JButton(); - moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowAndGoToDesktopButton, gbc); - closeWindowButton = new JButton(); - closeWindowButton.setText("close window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 3; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(closeWindowButton, gbc); - moveWindowToDesktopButton = new JButton(); - moveWindowToDesktopButton.setText("move window to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowToDesktopButton, gbc); - showDesktop = new JButton(); - showDesktop.setText("show desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(showDesktop, gbc); - showSubwindows = new JButton(); - showSubwindows.setText("show subwindows"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 3; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(showSubwindows, gbc); + private void refreshDesktopsAndWindows() throws X.X11Exception { + // update desktop list + X.Desktop[] desktops = display.getDesktops(); + ArrayList list = new ArrayList(desktops.length); + for (int i = 0; i < desktops.length; i++) { + list.add(desktops[i].name); + } + desktopList.clearSelection(); + desktopList.setModel(new SimpleListModel(list)); - // more attributes - desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + // select active desktop + int activeDesktop = display.getActiveDesktopNumber(); + desktopList.setSelectedIndex(activeDesktop); - setContentPane(mainPanel); - } + // update window list + int activeWindowId = display.getActiveWindow().getID(); + int activeWindowNumber = -1; + X.Window[] windows = display.getWindows(); + String[] head = new String[]{ + "ID", "Desktop", "Title", + "X", "Y", "Width", "Height" + }; + String[][] data = new String[windows.length][head.length]; + for (int i = 0; i < windows.length; i++) { + X.Window window = windows[i]; + X.Window.Geometry geo = window.getGeometry(); + int windowId = window.getID(); + data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); + data[i][1] = "" + window.getDesktop(); + data[i][2] = window.getTitle(); + data[i][3] = "" + geo.x; + data[i][4] = "" + geo.y; + data[i][5] = "" + geo.width; + data[i][6] = "" + geo.height; + if (windowId == activeWindowId) { + activeWindowNumber = i; + } + } + windowTable.setModel(new WindowTableModel(head, data, windows)); + if (activeWindowNumber >= 0) { + windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); + } + } - /** - * A simple ListModel managing a list of objects. - */ - public static class SimpleListModel extends AbstractListModel { - private static final long serialVersionUID = 1L; - private ArrayList list; + private void initGui() { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new GridBagLayout()); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridBagLayout()); + GridBagConstraints gbc; + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 0.8; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel1, gbc); + panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); + desktopList = new JList(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel1.add(desktopList, gbc); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel2, gbc); + panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); + final JScrollPane scrollPane1 = new JScrollPane(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel2.add(scrollPane1, gbc); + windowTable = new JTable(); + windowTable.setEnabled(true); + scrollPane1.setViewportView(windowTable); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 2; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel3, gbc); + panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); + goToDesktopButton = new JButton(); + goToDesktopButton.setText("go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToDesktopButton, gbc); + refreshButton = new JButton(); + refreshButton.setText("refresh"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(refreshButton, gbc); + goToWindowButton = new JButton(); + goToWindowButton.setText("go to window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToWindowButton, gbc); + moveWindowAndGoToDesktopButton = new JButton(); + moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowAndGoToDesktopButton, gbc); + closeWindowButton = new JButton(); + closeWindowButton.setText("close window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(closeWindowButton, gbc); + moveWindowToDesktopButton = new JButton(); + moveWindowToDesktopButton.setText("move window to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowToDesktopButton, gbc); + showDesktop = new JButton(); + showDesktop.setText("show desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showDesktop, gbc); + showSubwindows = new JButton(); + showSubwindows.setText("show subwindows"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showSubwindows, gbc); - public SimpleListModel(ArrayList list) { - this.list = list; - } + // more attributes + desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - public int getSize() { return list.size(); } - public Object getElementAt(int i) { return list.get(i); } - } + setContentPane(mainPanel); + } - /** - * A simple TableModel managing an array of Strings. - */ - public static class WindowTableModel implements TableModel { - private String[] head; - private String[][] data; - private X.Window[] windows; + /** + * A simple ListModel managing a list of objects. + */ + public static class SimpleListModel extends AbstractListModel { + private static final long serialVersionUID = 1L; + private ArrayList list; - public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { - this.head = head; - this.data = data; - this.windows = windows; - } + public SimpleListModel(ArrayList list) { + this.list = list; + } - public int getRowCount() { - return data.length; - } - public int getColumnCount() { - return head.length; - } - public String getColumnName(int columnIndex) { - return head[columnIndex]; - } - public Class getColumnClass(int columnIndex) { - return String.class; - } - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - public Object getValueAt(int rowIndex, int columnIndex) { - return data[rowIndex][columnIndex]; - } - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - } - public void addTableModelListener(TableModelListener l) { - } - public void removeTableModelListener(TableModelListener l) { - } + public int getSize() { return list.size(); } + public Object getElementAt(int i) { return list.get(i); } + } - public X.Window getWindow(int rowIndex) { - return windows[rowIndex]; - } - } + /** + * A simple TableModel managing an array of Strings. + */ + public static class WindowTableModel implements TableModel { + private String[] head; + private String[][] data; + private X.Window[] windows; + + public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { + this.head = head; + this.data = data; + this.windows = windows; + } + + public int getRowCount() { + return data.length; + } + public int getColumnCount() { + return head.length; + } + public String getColumnName(int columnIndex) { + return head[columnIndex]; + } + public Class getColumnClass(int columnIndex) { + return String.class; + } + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + } + public void addTableModelListener(TableModelListener l) { + } + public void removeTableModelListener(TableModelListener l) { + } + + public X.Window getWindow(int rowIndex) { + return windows[rowIndex]; + } + } } From 1d24197ea355ce1e04569ebc231fde4543b96f4d Mon Sep 17 00:00:00 2001 From: rm5248 Date: Mon, 21 Jul 2014 20:46:05 -0400 Subject: [PATCH 05/13] added a changes line to the CHANGES.md file --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0cd59ccf9b..b2fe49fc6a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,11 +17,13 @@ Features * [#338](https://github.com/twall/jna/pull/338): Added `com.sun.jna.platform.mac.XAttr` and `com.sun.jna.platform.mac.XAttrUtil` JNA wrapper for `` for Mac OS X - [@rednoah](https://github.com/rednoah). * [#339](https://github.com/twall/jna/pull/339): Added `GetWindowPlacement`, `SetWindowPlacement`, `AdjustWindowRect`, `AdjustWindowRectEx`, `ExitWindowsEx`, and `LockWorkstation` to `com.sun.jna.platform.win32.User32` - [@Timeroot](https://github.com/Timeroot). * [#286](https://github.com/twall/jna/pull/286): Added in com.sun.jna.platform.win32.Kernel32: CreateRemoteThread, WritePocessMemory and ReadProcessMemory - [@sstokic-tgm](https://github.com/sstokic-tgm). +* Object-oriented X API allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248) Bug Fixes --------- * [#319](https://github.com/twall/jna/pull/319): Fix direct-mapping type-mapped pointer result types - [@marco2357](https://github.com/marco2357). * Added Variant and TlbImp Fixes - [@wolftobias](https://github.com/wolftobias). +* Object-oriented X API will now return null if the window property is not found - [@rm5248](https://github.com/rm5248) Release 4.1 =========== From 254054e67be1291d5b324d4acccd377841a962c7 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Wed, 23 Jul 2014 16:41:25 -0400 Subject: [PATCH 06/13] fixed changes.md --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b2fe49fc6a..238abab972 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,13 +17,13 @@ Features * [#338](https://github.com/twall/jna/pull/338): Added `com.sun.jna.platform.mac.XAttr` and `com.sun.jna.platform.mac.XAttrUtil` JNA wrapper for `` for Mac OS X - [@rednoah](https://github.com/rednoah). * [#339](https://github.com/twall/jna/pull/339): Added `GetWindowPlacement`, `SetWindowPlacement`, `AdjustWindowRect`, `AdjustWindowRectEx`, `ExitWindowsEx`, and `LockWorkstation` to `com.sun.jna.platform.win32.User32` - [@Timeroot](https://github.com/Timeroot). * [#286](https://github.com/twall/jna/pull/286): Added in com.sun.jna.platform.win32.Kernel32: CreateRemoteThread, WritePocessMemory and ReadProcessMemory - [@sstokic-tgm](https://github.com/sstokic-tgm). -* Object-oriented X API allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248) +* [#350](https://github.com/twall/jna/pull/350): Object-oriented X API(jnacontrib.x11.api.X.Window) allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248). Bug Fixes --------- * [#319](https://github.com/twall/jna/pull/319): Fix direct-mapping type-mapped pointer result types - [@marco2357](https://github.com/marco2357). * Added Variant and TlbImp Fixes - [@wolftobias](https://github.com/wolftobias). -* Object-oriented X API will now return null if the window property is not found - [@rm5248](https://github.com/rm5248) +* [#350](https://github.com/twall/jna/pull/350): jnacontrib.x11.api.X.Window.getXXXProperty returns null if the window property is not found - [@rm5248](https://github.com/rm5248). Release 4.1 =========== From acd1e3256610df62c8c2ff551f8288608eba8fe2 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Fri, 18 Jul 2014 19:15:41 -0400 Subject: [PATCH 07/13] Added the ability to see all subwindows. Added a dialog so users can see the recursive X windows --- contrib/x11/src/jnacontrib/x11/api/X.java | 79 +- .../jnacontrib/x11/demos/XDesktopDemo.java | 687 ++++++++++-------- 2 files changed, 440 insertions(+), 326 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index e8a76b95e9..28ffbfe5ed 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -27,6 +27,7 @@ import com.sun.jna.platform.unix.X11; import com.sun.jna.platform.unix.X11.Atom; +import com.sun.jna.platform.unix.X11.WindowByReference; /** * Object oriented X window system. @@ -586,7 +587,7 @@ public String getWindowClass() throws X11Exception { * @return PID of the window * @throws X11Exception thrown if X11 window errors occurred */ - public int getPID() throws X11Exception { + public Integer getPID() throws X11Exception { return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); } @@ -731,11 +732,15 @@ public int close() throws X11Exception { * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as integer + * @return property value as integer or null if not found * @throws X11Exception thrown if X11 window errors occurred */ - public int getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return bytesToInt(getProperty(xa_prop_type, xa_prop_name)); + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); } /** @@ -746,7 +751,7 @@ public int getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X * @return property value as integer * @throws X11Exception thrown if X11 window errors occurred */ - public int getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); } @@ -755,11 +760,14 @@ public int getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11 * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as window + * @return property value as window, or null if not found * @throws X11Exception thrown if X11 window errors occurred */ public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - int windowId = getIntProperty(xa_prop_type, xa_prop_name); + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } X11.Window x11Window = new X11.Window(windowId); return new Window(display, x11Window); } @@ -781,12 +789,16 @@ public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) thro * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as a null terminated byte array + * @return property value as a null terminated byte array, or null if not found * @throws X11Exception thrown if X11 window errors occurred */ public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); byte[] bytesDest; + + if( bytesOrig == null ){ + return null; + } // search for '\0' int i; @@ -821,12 +833,16 @@ public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_na * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found * @throws X11Exception thrown if X11 window errors occurred */ public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + if( bytes == null ){ + return null; + } + // search for '\0' int i; for (i = 0; i < bytes.length; i++) { @@ -891,11 +907,15 @@ public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_na * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as string list + * @return property value as string list, or null if the property value does not exist * @throws X11Exception thrown if X11 window errors occurred */ public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); } /** @@ -908,7 +928,11 @@ public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name */ public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { try { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name), "UTF8"); + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); } catch (UnsupportedEncodingException e) { throw new X11Exception(e); } @@ -986,6 +1010,11 @@ public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } if (xa_ret_type == null || xa_prop_type == null || !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { @@ -1067,6 +1096,32 @@ public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong throw new X11Exception("Cannot send " + msg + " event."); } } + + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + + x11.XFree( children.getValue() ); + + return retVal; + } public String toString() { return x11Window.toString(); diff --git a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java index f20002f832..785c8d618c 100644 --- a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java +++ b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java @@ -13,10 +13,12 @@ package jnacontrib.x11.demos; import jnacontrib.x11.api.X; +import jnacontrib.x11.api.X.X11Exception; import javax.swing.*; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; + import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -29,339 +31,396 @@ */ public class XDesktopDemo extends JFrame { private static final long serialVersionUID = 1L; - public static void main(String[] args) throws X.X11Exception { - new XDesktopDemo(); - } + public static void main(String[] args) throws X.X11Exception { + new XDesktopDemo(); + } + + private X.Display display = new X.Display(); + private JList desktopList; + private JTable windowTable; + private JButton refreshButton; + private JButton moveWindowToDesktopButton; + private JButton goToDesktopButton; + private JButton moveWindowAndGoToDesktopButton; + private JButton closeWindowButton; + private JButton goToWindowButton; + private JButton showDesktop; + private JButton showSubwindows; + + public XDesktopDemo() throws X.X11Exception { + super("XDesktopDemo"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + initGui(); + + refreshDesktopsAndWindows(); - private X.Display display = new X.Display(); - private JList desktopList; - private JTable windowTable; - private JButton refreshButton; - private JButton moveWindowToDesktopButton; - private JButton goToDesktopButton; - private JButton moveWindowAndGoToDesktopButton; - private JButton closeWindowButton; - private JButton goToWindowButton; - private JButton showDesktop; - - public XDesktopDemo() throws X.X11Exception { - super("XDesktopDemo"); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - initGui(); + pack(); + addListeners(); + setVisible(true); - refreshDesktopsAndWindows(); + printWmInfo(); + } - pack(); - addListeners(); - setVisible(true); + private void printWmInfo() throws X.X11Exception { + X.Window wm = display.getWindowManagerInfo(); + System.out.println("wm.getTitle() = " + wm.getTitle()); + System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); + System.out.println("wm.getPID() = " + wm.getPID()); + } - printWmInfo(); - } + private void addListeners() { + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + refreshDesktopsAndWindows(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + goToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + int desktopNr = desktopList.getSelectedIndex(); + if (desktopNr >= 0) { + try { + display.switchDesktop(desktopNr); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + } + }); + goToWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showDesktop.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + display.showingDesktop(true); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + closeWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.close(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showSubwindows.addActionListener(new ActionListener() { + + private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ + X.Window[] subWindows = win.getSubwindows(); + String title = win.getTitle(); + if( title != null ){ + area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); + }else{ + area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); + } + area.append( System.getProperty( "line.separator" ) ); + + if( subWindows == null ){ + return; + } + for( int x = 0; x < subWindows.length; x++ ){ + addWindowsToArea( area, depth + 4, subWindows[ x ] ); + } + } - private void printWmInfo() throws X.X11Exception { - X.Window wm = display.getWindowManagerInfo(); - System.out.println("wm.getTitle() = " + wm.getTitle()); - System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); - System.out.println("wm.getPID() = " + wm.getPID()); - } + @Override + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); - private void addListeners() { - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - refreshDesktopsAndWindows(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - goToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - int desktopNr = desktopList.getSelectedIndex(); - if (desktopNr >= 0) { - try { - display.switchDesktop(desktopNr); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - } - }); - goToWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - showDesktop.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - display.showingDesktop(true); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - closeWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.close(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - } + try{ + final JDialog jd = new JDialog(); + JPanel dialogPanel = new JPanel( new BorderLayout() ); + jd.setSize( 320, 240 ); + jd.setTitle( "Subwindows" ); + jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); + JTextArea area = new JTextArea(); + addWindowsToArea( area, 1, window ); + dialogPanel.add( area, BorderLayout.CENTER ); + JButton closeButton = new JButton( "Close" ); + closeButton.addActionListener( new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + jd.dispose(); + } + }); + dialogPanel.add( closeButton, BorderLayout.SOUTH ); + jd.add( dialogPanel ); + jd.setVisible( true ); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + } - private X.Window getSelectedWindow() { - WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); - return tableModel.getWindow(windowTable.getSelectedRow()); - } + private X.Window getSelectedWindow() { + WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); + return tableModel.getWindow(windowTable.getSelectedRow()); + } - private void refreshDesktopsAndWindows() throws X.X11Exception { - // update desktop list - X.Desktop[] desktops = display.getDesktops(); - ArrayList list = new ArrayList(desktops.length); - for (int i = 0; i < desktops.length; i++) { - list.add(desktops[i].name); - } - desktopList.clearSelection(); - desktopList.setModel(new SimpleListModel(list)); + private void refreshDesktopsAndWindows() throws X.X11Exception { + // update desktop list + X.Desktop[] desktops = display.getDesktops(); + ArrayList list = new ArrayList(desktops.length); + for (int i = 0; i < desktops.length; i++) { + list.add(desktops[i].name); + } + desktopList.clearSelection(); + desktopList.setModel(new SimpleListModel(list)); - // select active desktop - int activeDesktop = display.getActiveDesktopNumber(); - desktopList.setSelectedIndex(activeDesktop); + // select active desktop + int activeDesktop = display.getActiveDesktopNumber(); + desktopList.setSelectedIndex(activeDesktop); - // update window list - int activeWindowId = display.getActiveWindow().getID(); - int activeWindowNumber = -1; - X.Window[] windows = display.getWindows(); - String[] head = new String[]{ - "ID", "Desktop", "Title", - "X", "Y", "Width", "Height" - }; - String[][] data = new String[windows.length][head.length]; - for (int i = 0; i < windows.length; i++) { - X.Window window = windows[i]; - X.Window.Geometry geo = window.getGeometry(); - int windowId = window.getID(); - data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); - data[i][1] = "" + window.getDesktop(); - data[i][2] = window.getTitle(); - data[i][3] = "" + geo.x; - data[i][4] = "" + geo.y; - data[i][5] = "" + geo.width; - data[i][6] = "" + geo.height; - if (windowId == activeWindowId) { - activeWindowNumber = i; - } - } - windowTable.setModel(new WindowTableModel(head, data, windows)); - if (activeWindowNumber >= 0) { - windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); - } - } + // update window list + int activeWindowId = display.getActiveWindow().getID(); + int activeWindowNumber = -1; + X.Window[] windows = display.getWindows(); + String[] head = new String[]{ + "ID", "Desktop", "Title", + "X", "Y", "Width", "Height" + }; + String[][] data = new String[windows.length][head.length]; + for (int i = 0; i < windows.length; i++) { + X.Window window = windows[i]; + X.Window.Geometry geo = window.getGeometry(); + int windowId = window.getID(); + data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); + data[i][1] = "" + window.getDesktop(); + data[i][2] = window.getTitle(); + data[i][3] = "" + geo.x; + data[i][4] = "" + geo.y; + data[i][5] = "" + geo.width; + data[i][6] = "" + geo.height; + if (windowId == activeWindowId) { + activeWindowNumber = i; + } + } + windowTable.setModel(new WindowTableModel(head, data, windows)); + if (activeWindowNumber >= 0) { + windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); + } + } - private void initGui() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new GridBagLayout()); - final JPanel panel1 = new JPanel(); - panel1.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 0.8; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel1, gbc); - panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); - desktopList = new JList(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel1.add(desktopList, gbc); - final JPanel panel2 = new JPanel(); - panel2.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel2, gbc); - panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); - final JScrollPane scrollPane1 = new JScrollPane(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel2.add(scrollPane1, gbc); - windowTable = new JTable(); - windowTable.setEnabled(true); - scrollPane1.setViewportView(windowTable); - final JPanel panel3 = new JPanel(); - panel3.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 2; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel3, gbc); - panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); - goToDesktopButton = new JButton(); - goToDesktopButton.setText("go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToDesktopButton, gbc); - refreshButton = new JButton(); - refreshButton.setText("refresh"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(refreshButton, gbc); - goToWindowButton = new JButton(); - goToWindowButton.setText("go to window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToWindowButton, gbc); - moveWindowAndGoToDesktopButton = new JButton(); - moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowAndGoToDesktopButton, gbc); - closeWindowButton = new JButton(); - closeWindowButton.setText("close window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 3; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(closeWindowButton, gbc); - moveWindowToDesktopButton = new JButton(); - moveWindowToDesktopButton.setText("move window to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowToDesktopButton, gbc); - showDesktop = new JButton(); - showDesktop.setText("show desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(showDesktop, gbc); + private void initGui() { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new GridBagLayout()); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridBagLayout()); + GridBagConstraints gbc; + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 0.8; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel1, gbc); + panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); + desktopList = new JList(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel1.add(desktopList, gbc); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel2, gbc); + panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); + final JScrollPane scrollPane1 = new JScrollPane(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel2.add(scrollPane1, gbc); + windowTable = new JTable(); + windowTable.setEnabled(true); + scrollPane1.setViewportView(windowTable); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 2; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel3, gbc); + panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); + goToDesktopButton = new JButton(); + goToDesktopButton.setText("go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToDesktopButton, gbc); + refreshButton = new JButton(); + refreshButton.setText("refresh"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(refreshButton, gbc); + goToWindowButton = new JButton(); + goToWindowButton.setText("go to window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToWindowButton, gbc); + moveWindowAndGoToDesktopButton = new JButton(); + moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowAndGoToDesktopButton, gbc); + closeWindowButton = new JButton(); + closeWindowButton.setText("close window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(closeWindowButton, gbc); + moveWindowToDesktopButton = new JButton(); + moveWindowToDesktopButton.setText("move window to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowToDesktopButton, gbc); + showDesktop = new JButton(); + showDesktop.setText("show desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showDesktop, gbc); + showSubwindows = new JButton(); + showSubwindows.setText("show subwindows"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showSubwindows, gbc); - // more attributes - desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + // more attributes + desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - setContentPane(mainPanel); - } + setContentPane(mainPanel); + } - /** - * A simple ListModel managing a list of objects. - */ - public static class SimpleListModel extends AbstractListModel { + /** + * A simple ListModel managing a list of objects. + */ + public static class SimpleListModel extends AbstractListModel { private static final long serialVersionUID = 1L; - private ArrayList list; + private ArrayList list; - public SimpleListModel(ArrayList list) { - this.list = list; - } + public SimpleListModel(ArrayList list) { + this.list = list; + } - public int getSize() { return list.size(); } - public Object getElementAt(int i) { return list.get(i); } - } + public int getSize() { return list.size(); } + public Object getElementAt(int i) { return list.get(i); } + } - /** - * A simple TableModel managing an array of Strings. - */ - public static class WindowTableModel implements TableModel { - private String[] head; - private String[][] data; - private X.Window[] windows; + /** + * A simple TableModel managing an array of Strings. + */ + public static class WindowTableModel implements TableModel { + private String[] head; + private String[][] data; + private X.Window[] windows; - public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { - this.head = head; - this.data = data; - this.windows = windows; - } + public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { + this.head = head; + this.data = data; + this.windows = windows; + } - public int getRowCount() { - return data.length; - } - public int getColumnCount() { - return head.length; - } - public String getColumnName(int columnIndex) { - return head[columnIndex]; - } - public Class getColumnClass(int columnIndex) { - return String.class; - } - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - public Object getValueAt(int rowIndex, int columnIndex) { - return data[rowIndex][columnIndex]; - } - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - } - public void addTableModelListener(TableModelListener l) { - } - public void removeTableModelListener(TableModelListener l) { - } + public int getRowCount() { + return data.length; + } + public int getColumnCount() { + return head.length; + } + public String getColumnName(int columnIndex) { + return head[columnIndex]; + } + public Class getColumnClass(int columnIndex) { + return String.class; + } + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + } + public void addTableModelListener(TableModelListener l) { + } + public void removeTableModelListener(TableModelListener l) { + } - public X.Window getWindow(int rowIndex) { - return windows[rowIndex]; - } - } + public X.Window getWindow(int rowIndex) { + return windows[rowIndex]; + } + } } From 40a6703cafcc55bdfde86aaf9934a9ab86805484 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Fri, 18 Jul 2014 17:36:55 -0700 Subject: [PATCH 08/13] Ensured that getting all windows from the X server works properly on 32-bit --- contrib/x11/src/jnacontrib/x11/api/X.java | 2255 +++++++++++---------- 1 file changed, 1133 insertions(+), 1122 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index 28ffbfe5ed..239e373599 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -39,1126 +39,1137 @@ * @author Stefan Endrullis */ public class X { - /** Remove/unset property. */ - public static final int _NET_WM_STATE_REMOVE = 0; - /** Add/set property. */ - public static final int _NET_WM_STATE_ADD = 1; - /** Toggle property. */ - public static final int _NET_WM_STATE_TOGGLE = 2; - /** Maximal property value length. */ - public static final int MAX_PROPERTY_VALUE_LEN = 4096; - - private static final X11 x11 = X11.INSTANCE; - - private static int bytesToInt(byte[] prop) { - return ((prop[3] & 0xff) << 24) - | ((prop[2] & 0xff) << 16) - | ((prop[1] & 0xff) << 8) - | ((prop[0] & 0xff)); - } - - private static int bytesToInt(byte[] prop, int offset) { - return ((prop[3 + offset] & 0xff) << 24) - | ((prop[2 + offset] & 0xff) << 16) - | ((prop[1 + offset] & 0xff) << 8) - | ((prop[offset] & 0xff)); - } - - - /** - * X Display. - */ - public static class Display { - /** - * Open display. - */ - private X11.Display x11Display; - /** - * HashMap. - */ - private HashMap atomsHash = new HashMap(); - - /** - * Creates the OOWindowUtils using the default display. - */ - public Display() { - x11Display = x11.XOpenDisplay(null); - - if (x11Display == null) { - throw new Error("Can't open X Display"); - } - } - - /** - * Creates the OOWindowUtils using a given display. - * - * @param x11Display open display - */ - public Display(X11.Display x11Display) { - this.x11Display = x11Display; - - if (x11Display == null) { - throw new Error("X Display is null"); - } - } - - /** - * Closes the display. - */ - public void close() { - x11.XCloseDisplay(x11Display); - } - - /** - * Flushes the output buffer / event queue. - */ - public void flush() { - x11.XFlush(x11Display); - } - - /** - * Returns the X11 display. - * - * @return X11 display - */ - public X11.Display getX11Display() { - return x11Display; - } - - /** - * Get internal atoms by name. - * - * @param name name of the atom - * @return atom - */ - public X11.Atom getAtom(String name) { - X11.Atom atom = atomsHash.get(name); - if (atom == null) { - atom = x11.XInternAtom(x11Display, name, false); - atomsHash.put(name, atom); - } - return atom; - } - - /** - * Returns the window manager information as an window. - * - * @return window manager information as an window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowManagerInfo() throws X11Exception { - Window rootWindow = getRootWindow(); - - try { - return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); - } catch (X11Exception e) { - try { - return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); - } - } - } - - /** - * Returns the root window. - * - * @return root window - */ - public Window getRootWindow() { - return new Window(this, x11.XDefaultRootWindow(x11Display)); - } - - /** - * Returns the current active window. - * - * @return current active window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getActiveWindow() throws X11Exception { - return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); - } - - /** - * Returns all windows managed by the window manager. - * - * @return all windows managed by the window manager - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window[] getWindows() throws X11Exception { - byte[] bytes; - Window rootWindow = getRootWindow(); - - try { - bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); - } catch (X11Exception e) { - try { - bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); - } - } - - Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; - - for (int i = 0; i < windowList.length; i++) { - windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); - } - - return windowList; - } - - /** - * Returns the number of desktops. - * - * @return number of desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktopCount() throws X11Exception { - Window root = getRootWindow(); - - try { - return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); - } catch (X11Exception e) { - try { - return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); - } - } - } - - /** - * Returns the number of the active desktop. - * - * @return number of the active desktop - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getActiveDesktopNumber() throws X11Exception { - Window root = getRootWindow(); - int cur_desktop; - - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); - } catch (X11Exception e) { - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); - } - } - - return cur_desktop; - } - - /** - * Returns the available desktops. - * - * @return available desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public Desktop[] getDesktops() throws X11Exception { - Window root = getRootWindow(); - String[] desktopNames; - try { - desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); - } catch (X11Exception e) { - try { - desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); - } - } - - Desktop[] desktops = new Desktop[getDesktopCount()]; - for (int i = 0; i < desktops.length; i++) { - desktops[i] = new Desktop(this, i, desktopNames[i]); - } - - return desktops; - } - - /** - * Switches to the given desktop. - * - * @param nr desktop number - * @throws X11Exception thrown if X11 window errors occurred - */ - public void switchDesktop(int nr) throws X11Exception { - getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); - } - - /** - * Sets the "showing the desktop" state. - * - * @param state true if the desktop should be shown - * @throws X11Exception thrown if X11 window errors occurred - */ - public void showingDesktop(boolean state) throws X11Exception { - getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); - } - - /** - * Enables / disables the auto-repeat of pressed keys. - * - * @param on true if auto-repeat shall be enabled - */ - public void setKeyAutoRepeat(boolean on) { - if (on) { - x11.XAutoRepeatOn(x11Display); - } else { - x11.XAutoRepeatOff(x11Display); - } - } - - /** - * Returns the key symbol corresponding to the the key name. - * - * @param keyName name of the key - * @return key symbol - */ - public X11.KeySym getKeySym(String keyName) { - return x11.XStringToKeysym(keyName); - } - - /** - * Returns the key symbol corresponding to the keycode. - * - * @param keyCode keycode - * @param index element of the keycode vector - * @return key symbol - */ - public X11.KeySym getKeySym(byte keyCode, int index) { - return x11.XKeycodeToKeysym(x11Display, keyCode, index); - } - - /** - * Returns the keycode corresponding to the key symbol. - * - * @param keySym key symbol - * @return keycode - */ - public byte getKeyCode(X11.KeySym keySym) { - return x11.XKeysymToKeycode(x11Display, keySym); - } - - /** - * Returns the keycode corresponding to the key name. - * - * @param keyName name of the key - * @return keycode - */ - public byte getKeyCode(String keyName) { - return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); - } - - /** - * Returns the key name corresponding to the key symbol. - * - * @param keySym key symbol - * @return name of the key - */ - public String getKeyName(X11.KeySym keySym) { - return x11.XKeysymToString(keySym); - } - - /** - * Returns the key name corresponding to the keycode and the index in the keycode vector. - * - * @param keyCode keycode - * @param index index in the keycode vector - * @return name of the key - */ - public String getKeyName(byte keyCode, int index) { - return getKeyName(getKeySym(keyCode, index)); - } - - /** - * Returns the modifier keymap. - * - * @return modifier keymap - */ - public ModifierKeymap getModifierKeymap() { - X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); - ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); - x11.XFreeModifiermap(xModifierKeymapRef); - return modifierKeymap; - } - - /** - * Sets the modifier keymap. - * - * @param modifierKeymap modifier keymap - */ - public void setModifierKeymap(ModifierKeymap modifierKeymap) { - X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); - x11.XSetModifierMapping(x11Display,xModifierKeymapRef); - } - } - - - /** - * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 - * contain the keycodes as Byte objects. You can directly access these lists to - * read, replace, remove or insert new keycodes to these modifiers. - * To apply a new modifier keymap call - * {@link X.Display#setModifierKeymap(ModifierKeymap)}. - */ - public static class ModifierKeymap { - /** Shift modifier as an ArrayList<Byte>. */ - public ArrayList shift = new ArrayList(4); - /** Lock modifier as an ArrayList<Byte>. */ - public ArrayList lock = new ArrayList(4); - /** Control modifier as an ArrayList<Byte>. */ - public ArrayList control = new ArrayList(4); - /** Mod1 modifier as an ArrayList<Byte>. */ - public ArrayList mod1 = new ArrayList(4); - /** Mod2 modifier as an ArrayList<Byte>. */ - public ArrayList mod2 = new ArrayList(4); - /** Mod3 modifier as an ArrayList<Byte>. */ - public ArrayList mod3 = new ArrayList(4); - /** Mod4 modifier as an ArrayList<Byte>. */ - public ArrayList mod4 = new ArrayList(4); - /** Mod5 modifier as an ArrayList<Byte>. */ - public ArrayList mod5 = new ArrayList(4); - - /** - * Creates an empty modifier keymap. - */ - public ModifierKeymap() { - } - - /** - * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - fromXModifierKeymap(xModifierKeymapRef); - } - - /** - * Reads all modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - int count = xModifierKeymapRef.max_keypermod; - byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); - - ArrayList[] allModifiers = getAllModifiers(); - - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - modifier.clear(); - - for (int keyNr = 0; keyNr < count; keyNr++) { - byte key = keys[modNr*count + keyNr]; - if (key != 0) { - modifier.add(new Byte(key)); - } - } - } - } - - /** - * Returns an XModifierKeymap corresponding to this object. - * - * @return XModifierKeymap - */ - public X11.XModifierKeymapRef toXModifierKeyamp() { - ArrayList[] allModifiers = getAllModifiers(); - - // determine max list size - int count = 0; - for (int i = 0; i < allModifiers.length; i++) { - count = Math.max(count, allModifiers[i].size()); - } - - byte[] keys = new byte[8*count]; - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - - for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { - keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); - } - } - - X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); - xModifierKeymapRef.max_keypermod = count; - xModifierKeymapRef.modifiermap = new Memory(keys.length); - xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); - - return xModifierKeymapRef; - } - - /** - * Returns all modifiers as an array. - * - * @return array of modifier lists - */ - public ArrayList[] getAllModifiers() { - return new ArrayList[] { - shift, lock, control, mod1, mod2, mod3, mod4, mod5 - }; - } - } - - /** - * X Desktop. - */ - public static class Desktop { - public X.Display display; - public int number; - public String name; - - public Desktop(Display display, int number, String name) { - this.display = display; - this.number = number; - this.name = name; - } - } - - - /** - * X Window. - */ - public static class Window { - private X.Display display; - private X11.Window x11Window; - - /** - * Returns the X11 window object. - * - * @return X11 window - */ - public X11.Window getX11Window() { - return x11Window; - } - - /** - * Returns the ID of the window. - * - * @return window ID - */ - public int getID() { - return x11Window.intValue(); - } - - /** - * Creates the window. - * - * @param display display where the window is allocated - * @param x11Window X11 window - */ - public Window(X.Display display, X11.Window x11Window) { - this.display = display; - this.x11Window = x11Window; - } - - /** - * Returns the title of the window. - * - * @return title of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getTitle() throws X11Exception { - try { - return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); - } catch (X11Exception e) { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); - } - - } - - /** - * Returns the window class. - * - * @return window class - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getWindowClass() throws X11Exception { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); - } - - /** - * Returns the PID of the window. - * - * @return PID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getPID() throws X11Exception { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); - } - - /** - * Returns the desktop ID of the window. - * - * @return desktop ID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktop() throws X11Exception { - try { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); - } catch (X11Exception e) { - return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } - } - - /** - * Returns the client machine name of the window. - * - * @return client machine name of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getMachine() throws X11Exception { - return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); - } - - /** - * Returns the XWindowAttributes of the window. - * - * @return XWindowAttributes of the window - */ - public X11.XWindowAttributes getXWindowAttributes() { - X11.XWindowAttributes xwa = new X11.XWindowAttributes(); - x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); - - return xwa; - } - - /** - * Returns the geometry of the window. - * - * @return geometry of the window - */ - public Geometry getGeometry() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference borderWidth = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), - borderWidth.getValue(), depth.getValue()); - } - - /** - * Returns the bounding box of the window. - * - * @return bounding box of the window - */ - public Rectangle getBounds() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference border_width = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - int xVal = x.getValue(); - int yVal = y.getValue(); - - return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); - } - - /** - * Activates the window. - * - * @throws X11Exception thrown if X11 window errors occurred - */ - public void activate() throws X11Exception { - clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); - x11.XMapRaised(display.x11Display, x11Window); - } - - /** - * Moves the window to the specified desktop. - * - * @param desktopNr desktop - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int moveToDesktop(int desktopNr) throws X11Exception { - return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); - } - - /** - * Selects the input events to listen for. - * - * @param eventMask event mask representing the events to listen for - */ - public void selectInput(int eventMask) { - x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); - } - - public int nextEvent(X11.XEvent event) { - return x11.XNextEvent(display.x11Display, event); - } - - public void sendEvent(int eventMask, X11.XEvent event) { - x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); - } - - /** - * Closes the window gracefully. - * - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int close() throws X11Exception { - return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return bytesToInt(property); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); - if( windowId == null ){ - return null; - } - X11.Window x11Window = new X11.Window(windowId); - return new Window(display, x11Window); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); - byte[] bytesDest; - - if( bytesOrig == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytesOrig.length; i++) { - if (bytesOrig[i] == '\0') break; - } - - if (i < bytesOrig.length - 1) { - bytesDest = new byte[i + 1]; - System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); - } else { - bytesDest = bytesOrig; - } - - return bytesDest; - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytes = getProperty(xa_prop_type, xa_prop_name); - - if( bytes == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytes.length; i++) { - if (bytes[i] == '\0') { - bytes[i] = '.'; - } - } - - return bytes; - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list, or null if the property value does not exist - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property).split("\0"); - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property, "UTF8"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); - IntByReference ret_format_ref = new IntByReference(); - NativeLongByReference ret_nitems_ref = new NativeLongByReference(); - NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); - PointerByReference ret_prop_ref = new PointerByReference(); - - NativeLong long_offset = new NativeLong(0); - NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); - - /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): - * - * long_length = Specifies the length in 32-bit multiples of the - * data to be retrieved. - */ - if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, - xa_prop_type, xa_ret_type_ref, ret_format_ref, - ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Cannot get " + prop_name + " property."); - } - - X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); - Pointer ret_prop = ret_prop_ref.getValue(); - - if( xa_ret_type == null ){ - //the specified property does not exist for the specified window - return null; - } - - if (xa_ret_type == null || xa_prop_type == null || - !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { - x11.XFree(ret_prop); - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Invalid type of " + prop_name + " property"); - } - - int ret_format = ret_format_ref.getValue(); - long ret_nitems = ret_nitems_ref.getValue().longValue(); - - // null terminate the result to make string handling easier - int nbytes; - if (ret_format == 32) - nbytes = Native.LONG_SIZE; - else if (ret_format == 16) - nbytes = Native.LONG_SIZE / 2; - else if (ret_format == 8) - nbytes = 1; - else if (ret_format == 0) - nbytes = 0; - else - throw new X11Exception("Invalid return format"); - int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); - - byte[] ret = ret_prop.getByteArray(0, length); - - x11.XFree(ret_prop); - return ret; - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { - return clientMsg( - msg, - new NativeLong(data0), - new NativeLong(data1), - new NativeLong(data2), - new NativeLong(data3), - new NativeLong(data4) - ); - } - - public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { - X11.XClientMessageEvent event; - NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); - - event = new X11.XClientMessageEvent(); - event.type = X11.ClientMessage; - event.serial = new NativeLong(0); - event.send_event = 1; - event.message_type = display.getAtom(msg); - event.window = x11Window; - event.format = 32; - event.data.setType(NativeLong[].class); - event.data.l[0] = data0; - event.data.l[1] = data1; - event.data.l[2] = data2; - event.data.l[3] = data3; - event.data.l[4] = data4; - - X11.XEvent e = new X11.XEvent(); - e.setTypedValue(event); - - if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { - return X11.Success; - } else { - throw new X11Exception("Cannot send " + msg + " event."); - } - } - - public Window[] getSubwindows() throws X11Exception { - WindowByReference root = new WindowByReference(); - WindowByReference parent = new WindowByReference(); - PointerByReference children = new PointerByReference(); - IntByReference childCount = new IntByReference(); - - if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ - throw new X11Exception("Can't query subwindows"); - } - - if( childCount.getValue() == 0 ){ - return null; - } - - Window[] retVal = new Window[ childCount.getValue() ]; - long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); - for( int x = 0; x < retVal.length; x++ ){ - X11.Window win = new X11.Window( windows [ x ] ); - retVal[ x ] = new Window( display, win ); - } - - x11.XFree( children.getValue() ); - - return retVal; - } - - public String toString() { - return x11Window.toString(); - } - - public static class Geometry { - public int x, y, width, height, borderWidth, depth; - - public Geometry(int x, int y, int width, int height, int border_width, int depth) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.borderWidth = border_width; - this.depth = depth; - } - } - } - - /** - * General exception which is thrown when an X11 window error occurred. - */ - public static class X11Exception extends Exception { - private static final long serialVersionUID = 1L; - public X11Exception() { - } - - public X11Exception(String message) { - super(message); - } - - public X11Exception(String message, Throwable cause) { - super(message, cause); - } - - public X11Exception(Throwable cause) { - super(cause); - } - } + /** Remove/unset property. */ + public static final int _NET_WM_STATE_REMOVE = 0; + /** Add/set property. */ + public static final int _NET_WM_STATE_ADD = 1; + /** Toggle property. */ + public static final int _NET_WM_STATE_TOGGLE = 2; + /** Maximal property value length. */ + public static final int MAX_PROPERTY_VALUE_LEN = 4096; + + private static final X11 x11 = X11.INSTANCE; + + private static int bytesToInt(byte[] prop) { + return ((prop[3] & 0xff) << 24) + | ((prop[2] & 0xff) << 16) + | ((prop[1] & 0xff) << 8) + | ((prop[0] & 0xff)); + } + + private static int bytesToInt(byte[] prop, int offset) { + return ((prop[3 + offset] & 0xff) << 24) + | ((prop[2 + offset] & 0xff) << 16) + | ((prop[1 + offset] & 0xff) << 8) + | ((prop[offset] & 0xff)); + } + + + /** + * X Display. + */ + public static class Display { + /** + * Open display. + */ + private X11.Display x11Display; + /** + * HashMap. + */ + private HashMap atomsHash = new HashMap(); + + /** + * Creates the OOWindowUtils using the default display. + */ + public Display() { + x11Display = x11.XOpenDisplay(null); + + if (x11Display == null) { + throw new Error("Can't open X Display"); + } + } + + /** + * Creates the OOWindowUtils using a given display. + * + * @param x11Display open display + */ + public Display(X11.Display x11Display) { + this.x11Display = x11Display; + + if (x11Display == null) { + throw new Error("X Display is null"); + } + } + + /** + * Closes the display. + */ + public void close() { + x11.XCloseDisplay(x11Display); + } + + /** + * Flushes the output buffer / event queue. + */ + public void flush() { + x11.XFlush(x11Display); + } + + /** + * Returns the X11 display. + * + * @return X11 display + */ + public X11.Display getX11Display() { + return x11Display; + } + + /** + * Get internal atoms by name. + * + * @param name name of the atom + * @return atom + */ + public X11.Atom getAtom(String name) { + X11.Atom atom = atomsHash.get(name); + if (atom == null) { + atom = x11.XInternAtom(x11Display, name, false); + atomsHash.put(name, atom); + } + return atom; + } + + /** + * Returns the window manager information as an window. + * + * @return window manager information as an window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowManagerInfo() throws X11Exception { + Window rootWindow = getRootWindow(); + + try { + return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); + } catch (X11Exception e) { + try { + return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); + } + } + } + + /** + * Returns the root window. + * + * @return root window + */ + public Window getRootWindow() { + return new Window(this, x11.XDefaultRootWindow(x11Display)); + } + + /** + * Returns the current active window. + * + * @return current active window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getActiveWindow() throws X11Exception { + return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); + } + + /** + * Returns all windows managed by the window manager. + * + * @return all windows managed by the window manager + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window[] getWindows() throws X11Exception { + byte[] bytes; + Window rootWindow = getRootWindow(); + + try { + bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); + } catch (X11Exception e) { + try { + bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); + } + } + + Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; + + for (int i = 0; i < windowList.length; i++) { + windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); + } + + return windowList; + } + + /** + * Returns the number of desktops. + * + * @return number of desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktopCount() throws X11Exception { + Window root = getRootWindow(); + + try { + return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); + } catch (X11Exception e) { + try { + return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); + } + } + } + + /** + * Returns the number of the active desktop. + * + * @return number of the active desktop + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getActiveDesktopNumber() throws X11Exception { + Window root = getRootWindow(); + int cur_desktop; + + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); + } catch (X11Exception e) { + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); + } + } + + return cur_desktop; + } + + /** + * Returns the available desktops. + * + * @return available desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public Desktop[] getDesktops() throws X11Exception { + Window root = getRootWindow(); + String[] desktopNames; + try { + desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); + } catch (X11Exception e) { + try { + desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); + } + } + + Desktop[] desktops = new Desktop[getDesktopCount()]; + for (int i = 0; i < desktops.length; i++) { + desktops[i] = new Desktop(this, i, desktopNames[i]); + } + + return desktops; + } + + /** + * Switches to the given desktop. + * + * @param nr desktop number + * @throws X11Exception thrown if X11 window errors occurred + */ + public void switchDesktop(int nr) throws X11Exception { + getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); + } + + /** + * Sets the "showing the desktop" state. + * + * @param state true if the desktop should be shown + * @throws X11Exception thrown if X11 window errors occurred + */ + public void showingDesktop(boolean state) throws X11Exception { + getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); + } + + /** + * Enables / disables the auto-repeat of pressed keys. + * + * @param on true if auto-repeat shall be enabled + */ + public void setKeyAutoRepeat(boolean on) { + if (on) { + x11.XAutoRepeatOn(x11Display); + } else { + x11.XAutoRepeatOff(x11Display); + } + } + + /** + * Returns the key symbol corresponding to the the key name. + * + * @param keyName name of the key + * @return key symbol + */ + public X11.KeySym getKeySym(String keyName) { + return x11.XStringToKeysym(keyName); + } + + /** + * Returns the key symbol corresponding to the keycode. + * + * @param keyCode keycode + * @param index element of the keycode vector + * @return key symbol + */ + public X11.KeySym getKeySym(byte keyCode, int index) { + return x11.XKeycodeToKeysym(x11Display, keyCode, index); + } + + /** + * Returns the keycode corresponding to the key symbol. + * + * @param keySym key symbol + * @return keycode + */ + public byte getKeyCode(X11.KeySym keySym) { + return x11.XKeysymToKeycode(x11Display, keySym); + } + + /** + * Returns the keycode corresponding to the key name. + * + * @param keyName name of the key + * @return keycode + */ + public byte getKeyCode(String keyName) { + return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); + } + + /** + * Returns the key name corresponding to the key symbol. + * + * @param keySym key symbol + * @return name of the key + */ + public String getKeyName(X11.KeySym keySym) { + return x11.XKeysymToString(keySym); + } + + /** + * Returns the key name corresponding to the keycode and the index in the keycode vector. + * + * @param keyCode keycode + * @param index index in the keycode vector + * @return name of the key + */ + public String getKeyName(byte keyCode, int index) { + return getKeyName(getKeySym(keyCode, index)); + } + + /** + * Returns the modifier keymap. + * + * @return modifier keymap + */ + public ModifierKeymap getModifierKeymap() { + X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); + ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); + x11.XFreeModifiermap(xModifierKeymapRef); + return modifierKeymap; + } + + /** + * Sets the modifier keymap. + * + * @param modifierKeymap modifier keymap + */ + public void setModifierKeymap(ModifierKeymap modifierKeymap) { + X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); + x11.XSetModifierMapping(x11Display,xModifierKeymapRef); + } + } + + + /** + * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 + * contain the keycodes as Byte objects. You can directly access these lists to + * read, replace, remove or insert new keycodes to these modifiers. + * To apply a new modifier keymap call + * {@link X.Display#setModifierKeymap(ModifierKeymap)}. + */ + public static class ModifierKeymap { + /** Shift modifier as an ArrayList<Byte>. */ + public ArrayList shift = new ArrayList(4); + /** Lock modifier as an ArrayList<Byte>. */ + public ArrayList lock = new ArrayList(4); + /** Control modifier as an ArrayList<Byte>. */ + public ArrayList control = new ArrayList(4); + /** Mod1 modifier as an ArrayList<Byte>. */ + public ArrayList mod1 = new ArrayList(4); + /** Mod2 modifier as an ArrayList<Byte>. */ + public ArrayList mod2 = new ArrayList(4); + /** Mod3 modifier as an ArrayList<Byte>. */ + public ArrayList mod3 = new ArrayList(4); + /** Mod4 modifier as an ArrayList<Byte>. */ + public ArrayList mod4 = new ArrayList(4); + /** Mod5 modifier as an ArrayList<Byte>. */ + public ArrayList mod5 = new ArrayList(4); + + /** + * Creates an empty modifier keymap. + */ + public ModifierKeymap() { + } + + /** + * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + fromXModifierKeymap(xModifierKeymapRef); + } + + /** + * Reads all modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + int count = xModifierKeymapRef.max_keypermod; + byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); + + ArrayList[] allModifiers = getAllModifiers(); + + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + modifier.clear(); + + for (int keyNr = 0; keyNr < count; keyNr++) { + byte key = keys[modNr*count + keyNr]; + if (key != 0) { + modifier.add(new Byte(key)); + } + } + } + } + + /** + * Returns an XModifierKeymap corresponding to this object. + * + * @return XModifierKeymap + */ + public X11.XModifierKeymapRef toXModifierKeyamp() { + ArrayList[] allModifiers = getAllModifiers(); + + // determine max list size + int count = 0; + for (int i = 0; i < allModifiers.length; i++) { + count = Math.max(count, allModifiers[i].size()); + } + + byte[] keys = new byte[8*count]; + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + + for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { + keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); + } + } + + X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); + xModifierKeymapRef.max_keypermod = count; + xModifierKeymapRef.modifiermap = new Memory(keys.length); + xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); + + return xModifierKeymapRef; + } + + /** + * Returns all modifiers as an array. + * + * @return array of modifier lists + */ + public ArrayList[] getAllModifiers() { + return new ArrayList[] { + shift, lock, control, mod1, mod2, mod3, mod4, mod5 + }; + } + } + + /** + * X Desktop. + */ + public static class Desktop { + public X.Display display; + public int number; + public String name; + + public Desktop(Display display, int number, String name) { + this.display = display; + this.number = number; + this.name = name; + } + } + + + /** + * X Window. + */ + public static class Window { + private X.Display display; + private X11.Window x11Window; + + /** + * Returns the X11 window object. + * + * @return X11 window + */ + public X11.Window getX11Window() { + return x11Window; + } + + /** + * Returns the ID of the window. + * + * @return window ID + */ + public int getID() { + return x11Window.intValue(); + } + + /** + * Creates the window. + * + * @param display display where the window is allocated + * @param x11Window X11 window + */ + public Window(X.Display display, X11.Window x11Window) { + this.display = display; + this.x11Window = x11Window; + } + + /** + * Returns the title of the window. + * + * @return title of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getTitle() throws X11Exception { + try { + return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); + } catch (X11Exception e) { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); + } + + } + + /** + * Returns the window class. + * + * @return window class + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getWindowClass() throws X11Exception { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); + } + + /** + * Returns the PID of the window. + * + * @return PID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getPID() throws X11Exception { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); + } + + /** + * Returns the desktop ID of the window. + * + * @return desktop ID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktop() throws X11Exception { + try { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); + } catch (X11Exception e) { + return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } + } + + /** + * Returns the client machine name of the window. + * + * @return client machine name of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getMachine() throws X11Exception { + return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); + } + + /** + * Returns the XWindowAttributes of the window. + * + * @return XWindowAttributes of the window + */ + public X11.XWindowAttributes getXWindowAttributes() { + X11.XWindowAttributes xwa = new X11.XWindowAttributes(); + x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); + + return xwa; + } + + /** + * Returns the geometry of the window. + * + * @return geometry of the window + */ + public Geometry getGeometry() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference borderWidth = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), + borderWidth.getValue(), depth.getValue()); + } + + /** + * Returns the bounding box of the window. + * + * @return bounding box of the window + */ + public Rectangle getBounds() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference border_width = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + int xVal = x.getValue(); + int yVal = y.getValue(); + + return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); + } + + /** + * Activates the window. + * + * @throws X11Exception thrown if X11 window errors occurred + */ + public void activate() throws X11Exception { + clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); + x11.XMapRaised(display.x11Display, x11Window); + } + + /** + * Moves the window to the specified desktop. + * + * @param desktopNr desktop + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int moveToDesktop(int desktopNr) throws X11Exception { + return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); + } + + /** + * Selects the input events to listen for. + * + * @param eventMask event mask representing the events to listen for + */ + public void selectInput(int eventMask) { + x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); + } + + public int nextEvent(X11.XEvent event) { + return x11.XNextEvent(display.x11Display, event); + } + + public void sendEvent(int eventMask, X11.XEvent event) { + x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); + } + + /** + * Closes the window gracefully. + * + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int close() throws X11Exception { + return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } + X11.Window x11Window = new X11.Window(windowId); + return new Window(display, x11Window); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); + byte[] bytesDest; + + if( bytesOrig == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytesOrig.length; i++) { + if (bytesOrig[i] == '\0') break; + } + + if (i < bytesOrig.length - 1) { + bytesDest = new byte[i + 1]; + System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); + } else { + bytesDest = bytesOrig; + } + + return bytesDest; + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + + if( bytes == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytes.length; i++) { + if (bytes[i] == '\0') { + bytes[i] = '.'; + } + } + + return bytes; + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list, or null if the property value does not exist + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); + IntByReference ret_format_ref = new IntByReference(); + NativeLongByReference ret_nitems_ref = new NativeLongByReference(); + NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); + PointerByReference ret_prop_ref = new PointerByReference(); + + NativeLong long_offset = new NativeLong(0); + NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); + + /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): + * + * long_length = Specifies the length in 32-bit multiples of the + * data to be retrieved. + */ + if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, + xa_prop_type, xa_ret_type_ref, ret_format_ref, + ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Cannot get " + prop_name + " property."); + } + + X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); + Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } + + if (xa_ret_type == null || xa_prop_type == null || + !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { + x11.XFree(ret_prop); + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Invalid type of " + prop_name + " property"); + } + + int ret_format = ret_format_ref.getValue(); + long ret_nitems = ret_nitems_ref.getValue().longValue(); + + // null terminate the result to make string handling easier + int nbytes; + if (ret_format == 32) + nbytes = Native.LONG_SIZE; + else if (ret_format == 16) + nbytes = Native.LONG_SIZE / 2; + else if (ret_format == 8) + nbytes = 1; + else if (ret_format == 0) + nbytes = 0; + else + throw new X11Exception("Invalid return format"); + int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); + + byte[] ret = ret_prop.getByteArray(0, length); + + x11.XFree(ret_prop); + return ret; + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { + return clientMsg( + msg, + new NativeLong(data0), + new NativeLong(data1), + new NativeLong(data2), + new NativeLong(data3), + new NativeLong(data4) + ); + } + + public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { + X11.XClientMessageEvent event; + NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); + + event = new X11.XClientMessageEvent(); + event.type = X11.ClientMessage; + event.serial = new NativeLong(0); + event.send_event = 1; + event.message_type = display.getAtom(msg); + event.window = x11Window; + event.format = 32; + event.data.setType(NativeLong[].class); + event.data.l[0] = data0; + event.data.l[1] = data1; + event.data.l[2] = data2; + event.data.l[3] = data3; + event.data.l[4] = data4; + + X11.XEvent e = new X11.XEvent(); + e.setTypedValue(event); + + if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { + return X11.Success; + } else { + throw new X11Exception("Cannot send " + msg + " event."); + } + } + + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + //Depending on if we're running on 64-bit or 32-bit systems, + //the long size may be different; we need to make sure that + //we get the data properly no matter what + if( Native.LONG_SIZE == 4 ){ + int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + }else if( Native.LONG_SIZE == 8 ){ + long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + } + + x11.XFree( children.getValue() ); + + return retVal; + } + + public String toString() { + return x11Window.toString(); + } + + public static class Geometry { + public int x, y, width, height, borderWidth, depth; + + public Geometry(int x, int y, int width, int height, int border_width, int depth) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.borderWidth = border_width; + this.depth = depth; + } + } + } + + /** + * General exception which is thrown when an X11 window error occurred. + */ + public static class X11Exception extends Exception { + private static final long serialVersionUID = 1L; + public X11Exception() { + } + + public X11Exception(String message) { + super(message); + } + + public X11Exception(String message, Throwable cause) { + super(message, cause); + } + + public X11Exception(Throwable cause) { + super(cause); + } + } } From 45ad1b280236121b680d49a5c7846762d7436b98 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Sat, 19 Jul 2014 12:24:06 -0400 Subject: [PATCH 09/13] fixed indentation to be spaces instead of tabs --- contrib/x11/src/jnacontrib/x11/api/X.java | 2266 ++++++++++----------- 1 file changed, 1133 insertions(+), 1133 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index 239e373599..7bacfb7c3b 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -39,1137 +39,1137 @@ * @author Stefan Endrullis */ public class X { - /** Remove/unset property. */ - public static final int _NET_WM_STATE_REMOVE = 0; - /** Add/set property. */ - public static final int _NET_WM_STATE_ADD = 1; - /** Toggle property. */ - public static final int _NET_WM_STATE_TOGGLE = 2; - /** Maximal property value length. */ - public static final int MAX_PROPERTY_VALUE_LEN = 4096; - - private static final X11 x11 = X11.INSTANCE; - - private static int bytesToInt(byte[] prop) { - return ((prop[3] & 0xff) << 24) - | ((prop[2] & 0xff) << 16) - | ((prop[1] & 0xff) << 8) - | ((prop[0] & 0xff)); - } - - private static int bytesToInt(byte[] prop, int offset) { - return ((prop[3 + offset] & 0xff) << 24) - | ((prop[2 + offset] & 0xff) << 16) - | ((prop[1 + offset] & 0xff) << 8) - | ((prop[offset] & 0xff)); - } - - - /** - * X Display. - */ - public static class Display { - /** - * Open display. - */ - private X11.Display x11Display; - /** - * HashMap. - */ - private HashMap atomsHash = new HashMap(); - - /** - * Creates the OOWindowUtils using the default display. - */ - public Display() { - x11Display = x11.XOpenDisplay(null); - - if (x11Display == null) { - throw new Error("Can't open X Display"); - } - } - - /** - * Creates the OOWindowUtils using a given display. - * - * @param x11Display open display - */ - public Display(X11.Display x11Display) { - this.x11Display = x11Display; - - if (x11Display == null) { - throw new Error("X Display is null"); - } - } - - /** - * Closes the display. - */ - public void close() { - x11.XCloseDisplay(x11Display); - } - - /** - * Flushes the output buffer / event queue. - */ - public void flush() { - x11.XFlush(x11Display); - } - - /** - * Returns the X11 display. - * - * @return X11 display - */ - public X11.Display getX11Display() { - return x11Display; - } - - /** - * Get internal atoms by name. - * - * @param name name of the atom - * @return atom - */ - public X11.Atom getAtom(String name) { - X11.Atom atom = atomsHash.get(name); - if (atom == null) { - atom = x11.XInternAtom(x11Display, name, false); - atomsHash.put(name, atom); - } - return atom; - } - - /** - * Returns the window manager information as an window. - * - * @return window manager information as an window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowManagerInfo() throws X11Exception { - Window rootWindow = getRootWindow(); - - try { - return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); - } catch (X11Exception e) { - try { - return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); - } - } - } - - /** - * Returns the root window. - * - * @return root window - */ - public Window getRootWindow() { - return new Window(this, x11.XDefaultRootWindow(x11Display)); - } - - /** - * Returns the current active window. - * - * @return current active window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getActiveWindow() throws X11Exception { - return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); - } - - /** - * Returns all windows managed by the window manager. - * - * @return all windows managed by the window manager - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window[] getWindows() throws X11Exception { - byte[] bytes; - Window rootWindow = getRootWindow(); - - try { - bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); - } catch (X11Exception e) { - try { - bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); - } - } - - Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; - - for (int i = 0; i < windowList.length; i++) { - windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); - } - - return windowList; - } - - /** - * Returns the number of desktops. - * - * @return number of desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktopCount() throws X11Exception { - Window root = getRootWindow(); - - try { - return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); - } catch (X11Exception e) { - try { - return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); - } - } - } - - /** - * Returns the number of the active desktop. - * - * @return number of the active desktop - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getActiveDesktopNumber() throws X11Exception { - Window root = getRootWindow(); - int cur_desktop; - - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); - } catch (X11Exception e) { - try { - cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); - } - } - - return cur_desktop; - } - - /** - * Returns the available desktops. - * - * @return available desktops - * @throws X11Exception thrown if X11 window errors occurred - */ - public Desktop[] getDesktops() throws X11Exception { - Window root = getRootWindow(); - String[] desktopNames; - try { - desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); - } catch (X11Exception e) { - try { - desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); - } catch (X11Exception e1) { - throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); - } - } - - Desktop[] desktops = new Desktop[getDesktopCount()]; - for (int i = 0; i < desktops.length; i++) { - desktops[i] = new Desktop(this, i, desktopNames[i]); - } - - return desktops; - } - - /** - * Switches to the given desktop. - * - * @param nr desktop number - * @throws X11Exception thrown if X11 window errors occurred - */ - public void switchDesktop(int nr) throws X11Exception { - getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); - } - - /** - * Sets the "showing the desktop" state. - * - * @param state true if the desktop should be shown - * @throws X11Exception thrown if X11 window errors occurred - */ - public void showingDesktop(boolean state) throws X11Exception { - getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); - } - - /** - * Enables / disables the auto-repeat of pressed keys. - * - * @param on true if auto-repeat shall be enabled - */ - public void setKeyAutoRepeat(boolean on) { - if (on) { - x11.XAutoRepeatOn(x11Display); - } else { - x11.XAutoRepeatOff(x11Display); - } - } - - /** - * Returns the key symbol corresponding to the the key name. - * - * @param keyName name of the key - * @return key symbol - */ - public X11.KeySym getKeySym(String keyName) { - return x11.XStringToKeysym(keyName); - } - - /** - * Returns the key symbol corresponding to the keycode. - * - * @param keyCode keycode - * @param index element of the keycode vector - * @return key symbol - */ - public X11.KeySym getKeySym(byte keyCode, int index) { - return x11.XKeycodeToKeysym(x11Display, keyCode, index); - } - - /** - * Returns the keycode corresponding to the key symbol. - * - * @param keySym key symbol - * @return keycode - */ - public byte getKeyCode(X11.KeySym keySym) { - return x11.XKeysymToKeycode(x11Display, keySym); - } - - /** - * Returns the keycode corresponding to the key name. - * - * @param keyName name of the key - * @return keycode - */ - public byte getKeyCode(String keyName) { - return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); - } - - /** - * Returns the key name corresponding to the key symbol. - * - * @param keySym key symbol - * @return name of the key - */ - public String getKeyName(X11.KeySym keySym) { - return x11.XKeysymToString(keySym); - } - - /** - * Returns the key name corresponding to the keycode and the index in the keycode vector. - * - * @param keyCode keycode - * @param index index in the keycode vector - * @return name of the key - */ - public String getKeyName(byte keyCode, int index) { - return getKeyName(getKeySym(keyCode, index)); - } - - /** - * Returns the modifier keymap. - * - * @return modifier keymap - */ - public ModifierKeymap getModifierKeymap() { - X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); - ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); - x11.XFreeModifiermap(xModifierKeymapRef); - return modifierKeymap; - } - - /** - * Sets the modifier keymap. - * - * @param modifierKeymap modifier keymap - */ - public void setModifierKeymap(ModifierKeymap modifierKeymap) { - X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); - x11.XSetModifierMapping(x11Display,xModifierKeymapRef); - } - } - - - /** - * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 - * contain the keycodes as Byte objects. You can directly access these lists to - * read, replace, remove or insert new keycodes to these modifiers. - * To apply a new modifier keymap call - * {@link X.Display#setModifierKeymap(ModifierKeymap)}. - */ - public static class ModifierKeymap { - /** Shift modifier as an ArrayList<Byte>. */ - public ArrayList shift = new ArrayList(4); - /** Lock modifier as an ArrayList<Byte>. */ - public ArrayList lock = new ArrayList(4); - /** Control modifier as an ArrayList<Byte>. */ - public ArrayList control = new ArrayList(4); - /** Mod1 modifier as an ArrayList<Byte>. */ - public ArrayList mod1 = new ArrayList(4); - /** Mod2 modifier as an ArrayList<Byte>. */ - public ArrayList mod2 = new ArrayList(4); - /** Mod3 modifier as an ArrayList<Byte>. */ - public ArrayList mod3 = new ArrayList(4); - /** Mod4 modifier as an ArrayList<Byte>. */ - public ArrayList mod4 = new ArrayList(4); - /** Mod5 modifier as an ArrayList<Byte>. */ - public ArrayList mod5 = new ArrayList(4); - - /** - * Creates an empty modifier keymap. - */ - public ModifierKeymap() { - } - - /** - * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - fromXModifierKeymap(xModifierKeymapRef); - } - - /** - * Reads all modifiers from the XModifierKeymap. - * - * @param xModifierKeymapRef XModifierKeymap - */ - public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { - int count = xModifierKeymapRef.max_keypermod; - byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); - - ArrayList[] allModifiers = getAllModifiers(); - - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - modifier.clear(); - - for (int keyNr = 0; keyNr < count; keyNr++) { - byte key = keys[modNr*count + keyNr]; - if (key != 0) { - modifier.add(new Byte(key)); - } - } - } - } - - /** - * Returns an XModifierKeymap corresponding to this object. - * - * @return XModifierKeymap - */ - public X11.XModifierKeymapRef toXModifierKeyamp() { - ArrayList[] allModifiers = getAllModifiers(); - - // determine max list size - int count = 0; - for (int i = 0; i < allModifiers.length; i++) { - count = Math.max(count, allModifiers[i].size()); - } - - byte[] keys = new byte[8*count]; - for (int modNr = 0; modNr < 8; modNr++) { - ArrayList modifier = allModifiers[modNr]; - - for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { - keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); - } - } - - X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); - xModifierKeymapRef.max_keypermod = count; - xModifierKeymapRef.modifiermap = new Memory(keys.length); - xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); - - return xModifierKeymapRef; - } - - /** - * Returns all modifiers as an array. - * - * @return array of modifier lists - */ - public ArrayList[] getAllModifiers() { - return new ArrayList[] { - shift, lock, control, mod1, mod2, mod3, mod4, mod5 - }; - } - } - - /** - * X Desktop. - */ - public static class Desktop { - public X.Display display; - public int number; - public String name; - - public Desktop(Display display, int number, String name) { - this.display = display; - this.number = number; - this.name = name; - } - } - - - /** - * X Window. - */ - public static class Window { - private X.Display display; - private X11.Window x11Window; - - /** - * Returns the X11 window object. - * - * @return X11 window - */ - public X11.Window getX11Window() { - return x11Window; - } - - /** - * Returns the ID of the window. - * - * @return window ID - */ - public int getID() { - return x11Window.intValue(); - } - - /** - * Creates the window. - * - * @param display display where the window is allocated - * @param x11Window X11 window - */ - public Window(X.Display display, X11.Window x11Window) { - this.display = display; - this.x11Window = x11Window; - } - - /** - * Returns the title of the window. - * - * @return title of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getTitle() throws X11Exception { - try { - return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); - } catch (X11Exception e) { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); - } - - } - - /** - * Returns the window class. - * - * @return window class - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getWindowClass() throws X11Exception { - return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); - } - - /** - * Returns the PID of the window. - * - * @return PID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getPID() throws X11Exception { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); - } - - /** - * Returns the desktop ID of the window. - * - * @return desktop ID of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public int getDesktop() throws X11Exception { - try { - return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); - } catch (X11Exception e) { - return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); - } - } - - /** - * Returns the client machine name of the window. - * - * @return client machine name of the window - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getMachine() throws X11Exception { - return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); - } - - /** - * Returns the XWindowAttributes of the window. - * - * @return XWindowAttributes of the window - */ - public X11.XWindowAttributes getXWindowAttributes() { - X11.XWindowAttributes xwa = new X11.XWindowAttributes(); - x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); - - return xwa; - } - - /** - * Returns the geometry of the window. - * - * @return geometry of the window - */ - public Geometry getGeometry() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference borderWidth = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), - borderWidth.getValue(), depth.getValue()); - } - - /** - * Returns the bounding box of the window. - * - * @return bounding box of the window - */ - public Rectangle getBounds() { - X11.WindowByReference junkRoot = new X11.WindowByReference(); - IntByReference junkX = new IntByReference(); - IntByReference junkY = new IntByReference(); - IntByReference x = new IntByReference(); - IntByReference y = new IntByReference(); - IntByReference width = new IntByReference(); - IntByReference height = new IntByReference(); - IntByReference border_width = new IntByReference(); - IntByReference depth = new IntByReference(); - - x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); - - x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); - - int xVal = x.getValue(); - int yVal = y.getValue(); - - return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); - } - - /** - * Activates the window. - * - * @throws X11Exception thrown if X11 window errors occurred - */ - public void activate() throws X11Exception { - clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); - x11.XMapRaised(display.x11Display, x11Window); - } - - /** - * Moves the window to the specified desktop. - * - * @param desktopNr desktop - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int moveToDesktop(int desktopNr) throws X11Exception { - return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); - } - - /** - * Selects the input events to listen for. - * - * @param eventMask event mask representing the events to listen for - */ - public void selectInput(int eventMask) { - x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); - } - - public int nextEvent(X11.XEvent event) { - return x11.XNextEvent(display.x11Display, event); - } - - public void sendEvent(int eventMask, X11.XEvent event) { - x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); - } - - /** - * Closes the window gracefully. - * - * @return X11.SUCCESS if closing was successful - * @throws X11Exception thrown if X11 window errors occurred - */ - public int close() throws X11Exception { - return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return bytesToInt(property); - } - - /** - * Returns the property value as integer. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as integer - * @throws X11Exception thrown if X11 window errors occurred - */ - public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); - if( windowId == null ){ - return null; - } - X11.Window x11Window = new X11.Window(windowId); - return new Window(display, x11Window); - } - - /** - * Returns the property value as window. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as window - * @throws X11Exception thrown if X11 window errors occurred - */ - public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array, or null if not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); - byte[] bytesDest; - - if( bytesOrig == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytesOrig.length; i++) { - if (bytesOrig[i] == '\0') break; - } - - if (i < bytesOrig.length - 1) { - bytesDest = new byte[i + 1]; - System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); - } else { - bytesDest = bytesOrig; - } - - return bytesDest; - } - - /** - * Returns the property value as a null terminated byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a null terminated byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - byte[] bytes = getProperty(xa_prop_type, xa_prop_name); - - if( bytes == null ){ - return null; - } - - // search for '\0' - int i; - for (i = 0; i < bytes.length; i++) { - if (bytes[i] == '\0') { - bytes[i] = '.'; - } - } - - return bytes; - } - - /** - * Returns the property value as byte array where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); - } - - /** - * Returns the property value as string list. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as string list, or null if the property value does not exist - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - byte[] property = getProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property).split("\0"); - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); - if( property == null ){ - return null; - } - return new String(property, "UTF8"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string where every '\0' character is replaced by '.' - * @throws X11Exception thrown if X11 window errors occurred - */ - public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - try { - return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); - } catch (UnsupportedEncodingException e) { - throw new X11Exception(e); - } - } - - /** - * Returns the property value as UTF8 string list - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as UTF8 string list - * @throws X11Exception thrown if X11 window errors occurred - */ - public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); - IntByReference ret_format_ref = new IntByReference(); - NativeLongByReference ret_nitems_ref = new NativeLongByReference(); - NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); - PointerByReference ret_prop_ref = new PointerByReference(); - - NativeLong long_offset = new NativeLong(0); - NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); - - /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): - * - * long_length = Specifies the length in 32-bit multiples of the - * data to be retrieved. - */ - if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, - xa_prop_type, xa_ret_type_ref, ret_format_ref, - ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Cannot get " + prop_name + " property."); - } - - X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); - Pointer ret_prop = ret_prop_ref.getValue(); - - if( xa_ret_type == null ){ - //the specified property does not exist for the specified window - return null; - } - - if (xa_ret_type == null || xa_prop_type == null || - !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { - x11.XFree(ret_prop); - String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); - throw new X11Exception("Invalid type of " + prop_name + " property"); - } - - int ret_format = ret_format_ref.getValue(); - long ret_nitems = ret_nitems_ref.getValue().longValue(); - - // null terminate the result to make string handling easier - int nbytes; - if (ret_format == 32) - nbytes = Native.LONG_SIZE; - else if (ret_format == 16) - nbytes = Native.LONG_SIZE / 2; - else if (ret_format == 8) - nbytes = 1; - else if (ret_format == 0) - nbytes = 0; - else - throw new X11Exception("Invalid return format"); - int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); - - byte[] ret = ret_prop.getByteArray(0, length); - - x11.XFree(ret_prop); - return ret; - } - - /** - * Returns the property value as a byte array. - * - * @param xa_prop_type property type - * @param xa_prop_name property name - * @return property value as a byte array - * @throws X11Exception thrown if X11 window errors occurred - */ - public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); - } - - public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { - return clientMsg( - msg, - new NativeLong(data0), - new NativeLong(data1), - new NativeLong(data2), - new NativeLong(data3), - new NativeLong(data4) - ); - } - - public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { - X11.XClientMessageEvent event; - NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); - - event = new X11.XClientMessageEvent(); - event.type = X11.ClientMessage; - event.serial = new NativeLong(0); - event.send_event = 1; - event.message_type = display.getAtom(msg); - event.window = x11Window; - event.format = 32; - event.data.setType(NativeLong[].class); - event.data.l[0] = data0; - event.data.l[1] = data1; - event.data.l[2] = data2; - event.data.l[3] = data3; - event.data.l[4] = data4; - - X11.XEvent e = new X11.XEvent(); - e.setTypedValue(event); - - if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { - return X11.Success; - } else { - throw new X11Exception("Cannot send " + msg + " event."); - } - } - - public Window[] getSubwindows() throws X11Exception { - WindowByReference root = new WindowByReference(); - WindowByReference parent = new WindowByReference(); - PointerByReference children = new PointerByReference(); - IntByReference childCount = new IntByReference(); - - if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ - throw new X11Exception("Can't query subwindows"); - } - - if( childCount.getValue() == 0 ){ - return null; - } - - Window[] retVal = new Window[ childCount.getValue() ]; - //Depending on if we're running on 64-bit or 32-bit systems, - //the long size may be different; we need to make sure that - //we get the data properly no matter what - if( Native.LONG_SIZE == 4 ){ - int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); - for( int x = 0; x < retVal.length; x++ ){ - X11.Window win = new X11.Window( windows [ x ] ); - retVal[ x ] = new Window( display, win ); - } - }else if( Native.LONG_SIZE == 8 ){ - long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); - for( int x = 0; x < retVal.length; x++ ){ - X11.Window win = new X11.Window( windows [ x ] ); - retVal[ x ] = new Window( display, win ); - } - } - - x11.XFree( children.getValue() ); - - return retVal; - } - - public String toString() { - return x11Window.toString(); - } - - public static class Geometry { - public int x, y, width, height, borderWidth, depth; - - public Geometry(int x, int y, int width, int height, int border_width, int depth) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.borderWidth = border_width; - this.depth = depth; - } - } - } - - /** - * General exception which is thrown when an X11 window error occurred. - */ - public static class X11Exception extends Exception { - private static final long serialVersionUID = 1L; - public X11Exception() { - } - - public X11Exception(String message) { - super(message); - } - - public X11Exception(String message, Throwable cause) { - super(message, cause); - } - - public X11Exception(Throwable cause) { - super(cause); - } - } + /** Remove/unset property. */ + public static final int _NET_WM_STATE_REMOVE = 0; + /** Add/set property. */ + public static final int _NET_WM_STATE_ADD = 1; + /** Toggle property. */ + public static final int _NET_WM_STATE_TOGGLE = 2; + /** Maximal property value length. */ + public static final int MAX_PROPERTY_VALUE_LEN = 4096; + + private static final X11 x11 = X11.INSTANCE; + + private static int bytesToInt(byte[] prop) { + return ((prop[3] & 0xff) << 24) + | ((prop[2] & 0xff) << 16) + | ((prop[1] & 0xff) << 8) + | ((prop[0] & 0xff)); + } + + private static int bytesToInt(byte[] prop, int offset) { + return ((prop[3 + offset] & 0xff) << 24) + | ((prop[2 + offset] & 0xff) << 16) + | ((prop[1 + offset] & 0xff) << 8) + | ((prop[offset] & 0xff)); + } + + + /** + * X Display. + */ + public static class Display { + /** + * Open display. + */ + private X11.Display x11Display; + /** + * HashMap. + */ + private HashMap atomsHash = new HashMap(); + + /** + * Creates the OOWindowUtils using the default display. + */ + public Display() { + x11Display = x11.XOpenDisplay(null); + + if (x11Display == null) { + throw new Error("Can't open X Display"); + } + } + + /** + * Creates the OOWindowUtils using a given display. + * + * @param x11Display open display + */ + public Display(X11.Display x11Display) { + this.x11Display = x11Display; + + if (x11Display == null) { + throw new Error("X Display is null"); + } + } + + /** + * Closes the display. + */ + public void close() { + x11.XCloseDisplay(x11Display); + } + + /** + * Flushes the output buffer / event queue. + */ + public void flush() { + x11.XFlush(x11Display); + } + + /** + * Returns the X11 display. + * + * @return X11 display + */ + public X11.Display getX11Display() { + return x11Display; + } + + /** + * Get internal atoms by name. + * + * @param name name of the atom + * @return atom + */ + public X11.Atom getAtom(String name) { + X11.Atom atom = atomsHash.get(name); + if (atom == null) { + atom = x11.XInternAtom(x11Display, name, false); + atomsHash.put(name, atom); + } + return atom; + } + + /** + * Returns the window manager information as an window. + * + * @return window manager information as an window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowManagerInfo() throws X11Exception { + Window rootWindow = getRootWindow(); + + try { + return rootWindow.getWindowProperty(X11.XA_WINDOW, "_NET_SUPPORTING_WM_CHECK"); + } catch (X11Exception e) { + try { + return rootWindow.getWindowProperty(X11.XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get window manager info properties. (_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)"); + } + } + } + + /** + * Returns the root window. + * + * @return root window + */ + public Window getRootWindow() { + return new Window(this, x11.XDefaultRootWindow(x11Display)); + } + + /** + * Returns the current active window. + * + * @return current active window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getActiveWindow() throws X11Exception { + return getRootWindow().getWindowProperty(X11.XA_WINDOW, "_NET_ACTIVE_WINDOW"); + } + + /** + * Returns all windows managed by the window manager. + * + * @return all windows managed by the window manager + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window[] getWindows() throws X11Exception { + byte[] bytes; + Window rootWindow = getRootWindow(); + + try { + bytes = rootWindow.getProperty(X11.XA_WINDOW, "_NET_CLIENT_LIST"); + } catch (X11Exception e) { + try { + bytes = rootWindow.getProperty(X11.XA_CARDINAL, "_WIN_CLIENT_LIST"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get client list properties (_NET_CLIENT_LIST or _WIN_CLIENT_LIST)"); + } + } + + Window[] windowList = new Window[bytes.length / X11.Window.SIZE]; + + for (int i = 0; i < windowList.length; i++) { + windowList[i] = new Window(this, new X11.Window(bytesToInt(bytes, X11.XID.SIZE * i))); + } + + return windowList; + } + + /** + * Returns the number of desktops. + * + * @return number of desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktopCount() throws X11Exception { + Window root = getRootWindow(); + + try { + return root.getIntProperty(X11.XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS"); + } catch (X11Exception e) { + try { + return root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE_COUNT"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get number of desktops properties (_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)"); + } + } + } + + /** + * Returns the number of the active desktop. + * + * @return number of the active desktop + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getActiveDesktopNumber() throws X11Exception { + Window root = getRootWindow(); + int cur_desktop; + + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_NET_CURRENT_DESKTOP"); + } catch (X11Exception e) { + try { + cur_desktop = root.getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get current desktop properties (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)"); + } + } + + return cur_desktop; + } + + /** + * Returns the available desktops. + * + * @return available desktops + * @throws X11Exception thrown if X11 window errors occurred + */ + public Desktop[] getDesktops() throws X11Exception { + Window root = getRootWindow(); + String[] desktopNames; + try { + desktopNames = root.getUtf8ListProperty(getAtom("UTF8_STRING"), "_NET_DESKTOP_NAMES"); + } catch (X11Exception e) { + try { + desktopNames = root.getStringListProperty(X11.XA_STRING, "_WIN_WORKSPACE_NAMES"); + } catch (X11Exception e1) { + throw new X11Exception("Cannot get desktop names properties (_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)"); + } + } + + Desktop[] desktops = new Desktop[getDesktopCount()]; + for (int i = 0; i < desktops.length; i++) { + desktops[i] = new Desktop(this, i, desktopNames[i]); + } + + return desktops; + } + + /** + * Switches to the given desktop. + * + * @param nr desktop number + * @throws X11Exception thrown if X11 window errors occurred + */ + public void switchDesktop(int nr) throws X11Exception { + getRootWindow().clientMsg("_NET_CURRENT_DESKTOP", nr, 0, 0, 0, 0); + } + + /** + * Sets the "showing the desktop" state. + * + * @param state true if the desktop should be shown + * @throws X11Exception thrown if X11 window errors occurred + */ + public void showingDesktop(boolean state) throws X11Exception { + getRootWindow().clientMsg("_NET_SHOWING_DESKTOP", state ? 1 : 0, 0, 0, 0, 0); + } + + /** + * Enables / disables the auto-repeat of pressed keys. + * + * @param on true if auto-repeat shall be enabled + */ + public void setKeyAutoRepeat(boolean on) { + if (on) { + x11.XAutoRepeatOn(x11Display); + } else { + x11.XAutoRepeatOff(x11Display); + } + } + + /** + * Returns the key symbol corresponding to the the key name. + * + * @param keyName name of the key + * @return key symbol + */ + public X11.KeySym getKeySym(String keyName) { + return x11.XStringToKeysym(keyName); + } + + /** + * Returns the key symbol corresponding to the keycode. + * + * @param keyCode keycode + * @param index element of the keycode vector + * @return key symbol + */ + public X11.KeySym getKeySym(byte keyCode, int index) { + return x11.XKeycodeToKeysym(x11Display, keyCode, index); + } + + /** + * Returns the keycode corresponding to the key symbol. + * + * @param keySym key symbol + * @return keycode + */ + public byte getKeyCode(X11.KeySym keySym) { + return x11.XKeysymToKeycode(x11Display, keySym); + } + + /** + * Returns the keycode corresponding to the key name. + * + * @param keyName name of the key + * @return keycode + */ + public byte getKeyCode(String keyName) { + return x11.XKeysymToKeycode(x11Display, getKeySym(keyName)); + } + + /** + * Returns the key name corresponding to the key symbol. + * + * @param keySym key symbol + * @return name of the key + */ + public String getKeyName(X11.KeySym keySym) { + return x11.XKeysymToString(keySym); + } + + /** + * Returns the key name corresponding to the keycode and the index in the keycode vector. + * + * @param keyCode keycode + * @param index index in the keycode vector + * @return name of the key + */ + public String getKeyName(byte keyCode, int index) { + return getKeyName(getKeySym(keyCode, index)); + } + + /** + * Returns the modifier keymap. + * + * @return modifier keymap + */ + public ModifierKeymap getModifierKeymap() { + X11.XModifierKeymapRef xModifierKeymapRef = x11.XGetModifierMapping(x11Display); + ModifierKeymap modifierKeymap = new ModifierKeymap(xModifierKeymapRef); + x11.XFreeModifiermap(xModifierKeymapRef); + return modifierKeymap; + } + + /** + * Sets the modifier keymap. + * + * @param modifierKeymap modifier keymap + */ + public void setModifierKeymap(ModifierKeymap modifierKeymap) { + X11.XModifierKeymapRef xModifierKeymapRef = modifierKeymap.toXModifierKeyamp(); + x11.XSetModifierMapping(x11Display,xModifierKeymapRef); + } + } + + + /** + * Modifier keymap. The lists shift, lock, control, mod1, mod1, mod1, mod1, mod1 + * contain the keycodes as Byte objects. You can directly access these lists to + * read, replace, remove or insert new keycodes to these modifiers. + * To apply a new modifier keymap call + * {@link X.Display#setModifierKeymap(ModifierKeymap)}. + */ + public static class ModifierKeymap { + /** Shift modifier as an ArrayList<Byte>. */ + public ArrayList shift = new ArrayList(4); + /** Lock modifier as an ArrayList<Byte>. */ + public ArrayList lock = new ArrayList(4); + /** Control modifier as an ArrayList<Byte>. */ + public ArrayList control = new ArrayList(4); + /** Mod1 modifier as an ArrayList<Byte>. */ + public ArrayList mod1 = new ArrayList(4); + /** Mod2 modifier as an ArrayList<Byte>. */ + public ArrayList mod2 = new ArrayList(4); + /** Mod3 modifier as an ArrayList<Byte>. */ + public ArrayList mod3 = new ArrayList(4); + /** Mod4 modifier as an ArrayList<Byte>. */ + public ArrayList mod4 = new ArrayList(4); + /** Mod5 modifier as an ArrayList<Byte>. */ + public ArrayList mod5 = new ArrayList(4); + + /** + * Creates an empty modifier keymap. + */ + public ModifierKeymap() { + } + + /** + * Creates a modifier keymap and reads the modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public ModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + fromXModifierKeymap(xModifierKeymapRef); + } + + /** + * Reads all modifiers from the XModifierKeymap. + * + * @param xModifierKeymapRef XModifierKeymap + */ + public void fromXModifierKeymap(X11.XModifierKeymapRef xModifierKeymapRef) { + int count = xModifierKeymapRef.max_keypermod; + byte[] keys = xModifierKeymapRef.modifiermap.getByteArray(0, 8*count); + + ArrayList[] allModifiers = getAllModifiers(); + + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + modifier.clear(); + + for (int keyNr = 0; keyNr < count; keyNr++) { + byte key = keys[modNr*count + keyNr]; + if (key != 0) { + modifier.add(new Byte(key)); + } + } + } + } + + /** + * Returns an XModifierKeymap corresponding to this object. + * + * @return XModifierKeymap + */ + public X11.XModifierKeymapRef toXModifierKeyamp() { + ArrayList[] allModifiers = getAllModifiers(); + + // determine max list size + int count = 0; + for (int i = 0; i < allModifiers.length; i++) { + count = Math.max(count, allModifiers[i].size()); + } + + byte[] keys = new byte[8*count]; + for (int modNr = 0; modNr < 8; modNr++) { + ArrayList modifier = allModifiers[modNr]; + + for (int keyNr = 0; keyNr < modifier.size(); keyNr++) { + keys[modNr*count + keyNr] = modifier.get(keyNr).byteValue(); + } + } + + X11.XModifierKeymapRef xModifierKeymapRef = new X11.XModifierKeymapRef(); + xModifierKeymapRef.max_keypermod = count; + xModifierKeymapRef.modifiermap = new Memory(keys.length); + xModifierKeymapRef.modifiermap.write(0, keys, 0, keys.length); + + return xModifierKeymapRef; + } + + /** + * Returns all modifiers as an array. + * + * @return array of modifier lists + */ + public ArrayList[] getAllModifiers() { + return new ArrayList[] { + shift, lock, control, mod1, mod2, mod3, mod4, mod5 + }; + } + } + + /** + * X Desktop. + */ + public static class Desktop { + public X.Display display; + public int number; + public String name; + + public Desktop(Display display, int number, String name) { + this.display = display; + this.number = number; + this.name = name; + } + } + + + /** + * X Window. + */ + public static class Window { + private X.Display display; + private X11.Window x11Window; + + /** + * Returns the X11 window object. + * + * @return X11 window + */ + public X11.Window getX11Window() { + return x11Window; + } + + /** + * Returns the ID of the window. + * + * @return window ID + */ + public int getID() { + return x11Window.intValue(); + } + + /** + * Creates the window. + * + * @param display display where the window is allocated + * @param x11Window X11 window + */ + public Window(X.Display display, X11.Window x11Window) { + this.display = display; + this.x11Window = x11Window; + } + + /** + * Returns the title of the window. + * + * @return title of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getTitle() throws X11Exception { + try { + return getUtf8Property(display.getAtom("UTF8_STRING"), "_NET_WM_NAME"); + } catch (X11Exception e) { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_NAME); + } + + } + + /** + * Returns the window class. + * + * @return window class + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getWindowClass() throws X11Exception { + return getUtf8Property(X11.XA_STRING, X11.XA_WM_CLASS); + } + + /** + * Returns the PID of the window. + * + * @return PID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getPID() throws X11Exception { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); + } + + /** + * Returns the desktop ID of the window. + * + * @return desktop ID of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public int getDesktop() throws X11Exception { + try { + return getIntProperty(X11.XA_CARDINAL, "_NET_WM_DESKTOP"); + } catch (X11Exception e) { + return getIntProperty(X11.XA_CARDINAL, "_WIN_WORKSPACE"); + } + } + + /** + * Returns the client machine name of the window. + * + * @return client machine name of the window + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getMachine() throws X11Exception { + return getStringProperty(X11.XA_STRING, "WM_CLIENT_MACHINE"); + } + + /** + * Returns the XWindowAttributes of the window. + * + * @return XWindowAttributes of the window + */ + public X11.XWindowAttributes getXWindowAttributes() { + X11.XWindowAttributes xwa = new X11.XWindowAttributes(); + x11.XGetWindowAttributes(display.x11Display, x11Window, xwa); + + return xwa; + } + + /** + * Returns the geometry of the window. + * + * @return geometry of the window + */ + public Geometry getGeometry() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference borderWidth = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), + borderWidth.getValue(), depth.getValue()); + } + + /** + * Returns the bounding box of the window. + * + * @return bounding box of the window + */ + public Rectangle getBounds() { + X11.WindowByReference junkRoot = new X11.WindowByReference(); + IntByReference junkX = new IntByReference(); + IntByReference junkY = new IntByReference(); + IntByReference x = new IntByReference(); + IntByReference y = new IntByReference(); + IntByReference width = new IntByReference(); + IntByReference height = new IntByReference(); + IntByReference border_width = new IntByReference(); + IntByReference depth = new IntByReference(); + + x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); + + x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), + junkY.getValue(), x, y, junkRoot); + + int xVal = x.getValue(); + int yVal = y.getValue(); + + return new Rectangle(xVal, yVal, xVal + width.getValue(), yVal + height.getValue()); + } + + /** + * Activates the window. + * + * @throws X11Exception thrown if X11 window errors occurred + */ + public void activate() throws X11Exception { + clientMsg("_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); + x11.XMapRaised(display.x11Display, x11Window); + } + + /** + * Moves the window to the specified desktop. + * + * @param desktopNr desktop + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int moveToDesktop(int desktopNr) throws X11Exception { + return clientMsg("_NET_WM_DESKTOP", desktopNr, 0, 0, 0, 0); + } + + /** + * Selects the input events to listen for. + * + * @param eventMask event mask representing the events to listen for + */ + public void selectInput(int eventMask) { + x11.XSelectInput(display.x11Display, x11Window, new NativeLong(eventMask)); + } + + public int nextEvent(X11.XEvent event) { + return x11.XNextEvent(display.x11Display, event); + } + + public void sendEvent(int eventMask, X11.XEvent event) { + x11.XSendEvent(display.x11Display, x11Window, 1, new NativeLong(eventMask), event); + } + + /** + * Closes the window gracefully. + * + * @return X11.SUCCESS if closing was successful + * @throws X11Exception thrown if X11 window errors occurred + */ + public int close() throws X11Exception { + return clientMsg("_NET_CLOSE_WINDOW", 0, 0, 0, 0, 0); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); + } + + /** + * Returns the property value as integer. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as integer + * @throws X11Exception thrown if X11 window errors occurred + */ + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } + X11.Window x11Window = new X11.Window(windowId); + return new Window(display, x11Window); + } + + /** + * Returns the property value as window. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as window + * @throws X11Exception thrown if X11 window errors occurred + */ + public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getWindowProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array, or null if not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); + byte[] bytesDest; + + if( bytesOrig == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytesOrig.length; i++) { + if (bytesOrig[i] == '\0') break; + } + + if (i < bytesOrig.length - 1) { + bytesDest = new byte[i + 1]; + System.arraycopy(bytesOrig, 0, bytesDest, 0, i + 1); + } else { + bytesDest = bytesOrig; + } + + return bytesDest; + } + + /** + * Returns the property value as a null terminated byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a null terminated byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullTerminatedProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + + if( bytes == null ){ + return null; + } + + // search for '\0' + int i; + for (i = 0; i < bytes.length; i++) { + if (bytes[i] == '\0') { + bytes[i] = '.'; + } + } + + return bytes; + } + + /** + * Returns the property value as byte array where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as byte array where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getNullReplacedStringProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getStringProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name)); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + } + + /** + * Returns the property value as string list. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as string list, or null if the property value does not exist + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string where every '\0' character is replaced by '.'. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string where every '\0' character is replaced by '.' + * @throws X11Exception thrown if X11 window errors occurred + */ + public String getUtf8Property(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8Property(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + try { + return new String(getProperty(xa_prop_type, xa_prop_name), "UTF8").split("\0"); + } catch (UnsupportedEncodingException e) { + throw new X11Exception(e); + } + } + + /** + * Returns the property value as UTF8 string list + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as UTF8 string list + * @throws X11Exception thrown if X11 window errors occurred + */ + public String[] getUtf8ListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getUtf8ListProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference(); + IntByReference ret_format_ref = new IntByReference(); + NativeLongByReference ret_nitems_ref = new NativeLongByReference(); + NativeLongByReference ret_bytes_after_ref = new NativeLongByReference(); + PointerByReference ret_prop_ref = new PointerByReference(); + + NativeLong long_offset = new NativeLong(0); + NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); + + /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): + * + * long_length = Specifies the length in 32-bit multiples of the + * data to be retrieved. + */ + if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, + xa_prop_type, xa_ret_type_ref, ret_format_ref, + ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Cannot get " + prop_name + " property."); + } + + X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); + Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } + + if (xa_ret_type == null || xa_prop_type == null || + !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { + x11.XFree(ret_prop); + String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); + throw new X11Exception("Invalid type of " + prop_name + " property"); + } + + int ret_format = ret_format_ref.getValue(); + long ret_nitems = ret_nitems_ref.getValue().longValue(); + + // null terminate the result to make string handling easier + int nbytes; + if (ret_format == 32) + nbytes = Native.LONG_SIZE; + else if (ret_format == 16) + nbytes = Native.LONG_SIZE / 2; + else if (ret_format == 8) + nbytes = 1; + else if (ret_format == 0) + nbytes = 0; + else + throw new X11Exception("Invalid return format"); + int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN); + + byte[] ret = ret_prop.getByteArray(0, length); + + x11.XFree(ret_prop); + return ret; + } + + /** + * Returns the property value as a byte array. + * + * @param xa_prop_type property type + * @param xa_prop_name property name + * @return property value as a byte array + * @throws X11Exception thrown if X11 window errors occurred + */ + public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + return getProperty(xa_prop_type, display.getAtom(xa_prop_name)); + } + + public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { + return clientMsg( + msg, + new NativeLong(data0), + new NativeLong(data1), + new NativeLong(data2), + new NativeLong(data3), + new NativeLong(data4) + ); + } + + public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { + X11.XClientMessageEvent event; + NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask); + + event = new X11.XClientMessageEvent(); + event.type = X11.ClientMessage; + event.serial = new NativeLong(0); + event.send_event = 1; + event.message_type = display.getAtom(msg); + event.window = x11Window; + event.format = 32; + event.data.setType(NativeLong[].class); + event.data.l[0] = data0; + event.data.l[1] = data1; + event.data.l[2] = data2; + event.data.l[3] = data3; + event.data.l[4] = data4; + + X11.XEvent e = new X11.XEvent(); + e.setTypedValue(event); + + if (x11.XSendEvent(display.x11Display, display.getRootWindow().x11Window, 0, mask, e) != 0) { + return X11.Success; + } else { + throw new X11Exception("Cannot send " + msg + " event."); + } + } + + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + //Depending on if we're running on 64-bit or 32-bit systems, + //the long size may be different; we need to make sure that + //we get the data properly no matter what + if( Native.LONG_SIZE == 4 ){ + int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + }else if( Native.LONG_SIZE == 8 ){ + long[] windows = children.getValue().getLongArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } + } + + x11.XFree( children.getValue() ); + + return retVal; + } + + public String toString() { + return x11Window.toString(); + } + + public static class Geometry { + public int x, y, width, height, borderWidth, depth; + + public Geometry(int x, int y, int width, int height, int border_width, int depth) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.borderWidth = border_width; + this.depth = depth; + } + } + } + + /** + * General exception which is thrown when an X11 window error occurred. + */ + public static class X11Exception extends Exception { + private static final long serialVersionUID = 1L; + public X11Exception() { + } + + public X11Exception(String message) { + super(message); + } + + public X11Exception(String message, Throwable cause) { + super(message, cause); + } + + public X11Exception(Throwable cause) { + super(cause); + } + } } From 8fc536e1a3a909d60808dedb30b3e9cbbdef9e4e Mon Sep 17 00:00:00 2001 From: rm5248 Date: Sat, 19 Jul 2014 12:26:27 -0400 Subject: [PATCH 10/13] more fixing of formatting --- .../jnacontrib/x11/demos/XDesktopDemo.java | 740 +++++++++--------- 1 file changed, 370 insertions(+), 370 deletions(-) diff --git a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java index 785c8d618c..f1e4797a6e 100644 --- a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java +++ b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java @@ -30,397 +30,397 @@ * @author Stefan Endrullis */ public class XDesktopDemo extends JFrame { - private static final long serialVersionUID = 1L; - public static void main(String[] args) throws X.X11Exception { - new XDesktopDemo(); - } + private static final long serialVersionUID = 1L; + public static void main(String[] args) throws X.X11Exception { + new XDesktopDemo(); + } - private X.Display display = new X.Display(); - private JList desktopList; - private JTable windowTable; - private JButton refreshButton; - private JButton moveWindowToDesktopButton; - private JButton goToDesktopButton; - private JButton moveWindowAndGoToDesktopButton; - private JButton closeWindowButton; - private JButton goToWindowButton; - private JButton showDesktop; - private JButton showSubwindows; + private X.Display display = new X.Display(); + private JList desktopList; + private JTable windowTable; + private JButton refreshButton; + private JButton moveWindowToDesktopButton; + private JButton goToDesktopButton; + private JButton moveWindowAndGoToDesktopButton; + private JButton closeWindowButton; + private JButton goToWindowButton; + private JButton showDesktop; + private JButton showSubwindows; - public XDesktopDemo() throws X.X11Exception { - super("XDesktopDemo"); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - initGui(); + public XDesktopDemo() throws X.X11Exception { + super("XDesktopDemo"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + initGui(); - refreshDesktopsAndWindows(); + refreshDesktopsAndWindows(); - pack(); - addListeners(); - setVisible(true); + pack(); + addListeners(); + setVisible(true); - printWmInfo(); - } + printWmInfo(); + } - private void printWmInfo() throws X.X11Exception { - X.Window wm = display.getWindowManagerInfo(); - System.out.println("wm.getTitle() = " + wm.getTitle()); - System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); - System.out.println("wm.getPID() = " + wm.getPID()); - } + private void printWmInfo() throws X.X11Exception { + X.Window wm = display.getWindowManagerInfo(); + System.out.println("wm.getTitle() = " + wm.getTitle()); + System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); + System.out.println("wm.getPID() = " + wm.getPID()); + } - private void addListeners() { - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - refreshDesktopsAndWindows(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - goToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - int desktopNr = desktopList.getSelectedIndex(); - if (desktopNr >= 0) { - try { - display.switchDesktop(desktopNr); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - } - }); - goToWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - showDesktop.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - try { - display.showingDesktop(true); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.moveToDesktop(desktopList.getSelectedIndex()); - window.activate(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - closeWindowButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); - try { - window.close(); - display.flush(); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - showSubwindows.addActionListener(new ActionListener() { - - private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ - X.Window[] subWindows = win.getSubwindows(); - String title = win.getTitle(); - if( title != null ){ - area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); - }else{ - area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); - } - area.append( System.getProperty( "line.separator" ) ); - - if( subWindows == null ){ - return; - } - for( int x = 0; x < subWindows.length; x++ ){ - addWindowsToArea( area, depth + 4, subWindows[ x ] ); - } - } + private void addListeners() { + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + refreshDesktopsAndWindows(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + goToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + int desktopNr = desktopList.getSelectedIndex(); + if (desktopNr >= 0) { + try { + display.switchDesktop(desktopNr); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + } + }); + goToWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showDesktop.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + display.showingDesktop(true); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + closeWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.close(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showSubwindows.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - X.Window window = getSelectedWindow(); + private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ + X.Window[] subWindows = win.getSubwindows(); + String title = win.getTitle(); + if( title != null ){ + area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); + }else{ + area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); + } + area.append( System.getProperty( "line.separator" ) ); - try{ - final JDialog jd = new JDialog(); - JPanel dialogPanel = new JPanel( new BorderLayout() ); - jd.setSize( 320, 240 ); - jd.setTitle( "Subwindows" ); - jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); - JTextArea area = new JTextArea(); - addWindowsToArea( area, 1, window ); - dialogPanel.add( area, BorderLayout.CENTER ); - JButton closeButton = new JButton( "Close" ); - closeButton.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - jd.dispose(); - } - }); - dialogPanel.add( closeButton, BorderLayout.SOUTH ); - jd.add( dialogPanel ); - jd.setVisible( true ); - } catch (X.X11Exception e) { - e.printStackTrace(); - } - } - }); - } + if( subWindows == null ){ + return; + } + for( int x = 0; x < subWindows.length; x++ ){ + addWindowsToArea( area, depth + 4, subWindows[ x ] ); + } + } - private X.Window getSelectedWindow() { - WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); - return tableModel.getWindow(windowTable.getSelectedRow()); - } + @Override + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); - private void refreshDesktopsAndWindows() throws X.X11Exception { - // update desktop list - X.Desktop[] desktops = display.getDesktops(); - ArrayList list = new ArrayList(desktops.length); - for (int i = 0; i < desktops.length; i++) { - list.add(desktops[i].name); - } - desktopList.clearSelection(); - desktopList.setModel(new SimpleListModel(list)); + try{ + final JDialog jd = new JDialog(); + JPanel dialogPanel = new JPanel( new BorderLayout() ); + jd.setSize( 320, 240 ); + jd.setTitle( "Subwindows" ); + jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); + JTextArea area = new JTextArea(); + addWindowsToArea( area, 1, window ); + dialogPanel.add( area, BorderLayout.CENTER ); + JButton closeButton = new JButton( "Close" ); + closeButton.addActionListener( new ActionListener() { - // select active desktop - int activeDesktop = display.getActiveDesktopNumber(); - desktopList.setSelectedIndex(activeDesktop); + @Override + public void actionPerformed(ActionEvent e) { + jd.dispose(); + } + }); + dialogPanel.add( closeButton, BorderLayout.SOUTH ); + jd.add( dialogPanel ); + jd.setVisible( true ); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + } - // update window list - int activeWindowId = display.getActiveWindow().getID(); - int activeWindowNumber = -1; - X.Window[] windows = display.getWindows(); - String[] head = new String[]{ - "ID", "Desktop", "Title", - "X", "Y", "Width", "Height" - }; - String[][] data = new String[windows.length][head.length]; - for (int i = 0; i < windows.length; i++) { - X.Window window = windows[i]; - X.Window.Geometry geo = window.getGeometry(); - int windowId = window.getID(); - data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); - data[i][1] = "" + window.getDesktop(); - data[i][2] = window.getTitle(); - data[i][3] = "" + geo.x; - data[i][4] = "" + geo.y; - data[i][5] = "" + geo.width; - data[i][6] = "" + geo.height; - if (windowId == activeWindowId) { - activeWindowNumber = i; - } - } - windowTable.setModel(new WindowTableModel(head, data, windows)); - if (activeWindowNumber >= 0) { - windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); - } - } + private X.Window getSelectedWindow() { + WindowTableModel tableModel = (WindowTableModel) windowTable.getModel(); + return tableModel.getWindow(windowTable.getSelectedRow()); + } - private void initGui() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new GridBagLayout()); - final JPanel panel1 = new JPanel(); - panel1.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 0.8; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel1, gbc); - panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); - desktopList = new JList(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel1.add(desktopList, gbc); - final JPanel panel2 = new JPanel(); - panel2.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel2, gbc); - panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); - final JScrollPane scrollPane1 = new JScrollPane(); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - panel2.add(scrollPane1, gbc); - windowTable = new JTable(); - windowTable.setEnabled(true); - scrollPane1.setViewportView(windowTable); - final JPanel panel3 = new JPanel(); - panel3.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 2; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.fill = GridBagConstraints.BOTH; - mainPanel.add(panel3, gbc); - panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); - goToDesktopButton = new JButton(); - goToDesktopButton.setText("go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToDesktopButton, gbc); - refreshButton = new JButton(); - refreshButton.setText("refresh"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(refreshButton, gbc); - goToWindowButton = new JButton(); - goToWindowButton.setText("go to window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(goToWindowButton, gbc); - moveWindowAndGoToDesktopButton = new JButton(); - moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 2; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowAndGoToDesktopButton, gbc); - closeWindowButton = new JButton(); - closeWindowButton.setText("close window"); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 3; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(closeWindowButton, gbc); - moveWindowToDesktopButton = new JButton(); - moveWindowToDesktopButton.setText("move window to desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(moveWindowToDesktopButton, gbc); - showDesktop = new JButton(); - showDesktop.setText("show desktop"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(showDesktop, gbc); - showSubwindows = new JButton(); - showSubwindows.setText("show subwindows"); - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 3; - gbc.fill = GridBagConstraints.HORIZONTAL; - panel3.add(showSubwindows, gbc); + private void refreshDesktopsAndWindows() throws X.X11Exception { + // update desktop list + X.Desktop[] desktops = display.getDesktops(); + ArrayList list = new ArrayList(desktops.length); + for (int i = 0; i < desktops.length; i++) { + list.add(desktops[i].name); + } + desktopList.clearSelection(); + desktopList.setModel(new SimpleListModel(list)); - // more attributes - desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + // select active desktop + int activeDesktop = display.getActiveDesktopNumber(); + desktopList.setSelectedIndex(activeDesktop); - setContentPane(mainPanel); - } + // update window list + int activeWindowId = display.getActiveWindow().getID(); + int activeWindowNumber = -1; + X.Window[] windows = display.getWindows(); + String[] head = new String[]{ + "ID", "Desktop", "Title", + "X", "Y", "Width", "Height" + }; + String[][] data = new String[windows.length][head.length]; + for (int i = 0; i < windows.length; i++) { + X.Window window = windows[i]; + X.Window.Geometry geo = window.getGeometry(); + int windowId = window.getID(); + data[i][0] = String.format("0x%08X", new Object[]{new Integer(windowId)}); + data[i][1] = "" + window.getDesktop(); + data[i][2] = window.getTitle(); + data[i][3] = "" + geo.x; + data[i][4] = "" + geo.y; + data[i][5] = "" + geo.width; + data[i][6] = "" + geo.height; + if (windowId == activeWindowId) { + activeWindowNumber = i; + } + } + windowTable.setModel(new WindowTableModel(head, data, windows)); + if (activeWindowNumber >= 0) { + windowTable.getSelectionModel().setSelectionInterval(activeWindowNumber, activeWindowNumber); + } + } - /** - * A simple ListModel managing a list of objects. - */ - public static class SimpleListModel extends AbstractListModel { - private static final long serialVersionUID = 1L; - private ArrayList list; + private void initGui() { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new GridBagLayout()); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridBagLayout()); + GridBagConstraints gbc; + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 0.8; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel1, gbc); + panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Desktops")); + desktopList = new JList(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel1.add(desktopList, gbc); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel2, gbc); + panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Windows")); + final JScrollPane scrollPane1 = new JScrollPane(); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + panel2.add(scrollPane1, gbc); + windowTable = new JTable(); + windowTable.setEnabled(true); + scrollPane1.setViewportView(windowTable); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridBagLayout()); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 2; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.add(panel3, gbc); + panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "Actions")); + goToDesktopButton = new JButton(); + goToDesktopButton.setText("go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToDesktopButton, gbc); + refreshButton = new JButton(); + refreshButton.setText("refresh"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(refreshButton, gbc); + goToWindowButton = new JButton(); + goToWindowButton.setText("go to window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(goToWindowButton, gbc); + moveWindowAndGoToDesktopButton = new JButton(); + moveWindowAndGoToDesktopButton.setText("move window and go to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowAndGoToDesktopButton, gbc); + closeWindowButton = new JButton(); + closeWindowButton.setText("close window"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(closeWindowButton, gbc); + moveWindowToDesktopButton = new JButton(); + moveWindowToDesktopButton.setText("move window to desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(moveWindowToDesktopButton, gbc); + showDesktop = new JButton(); + showDesktop.setText("show desktop"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showDesktop, gbc); + showSubwindows = new JButton(); + showSubwindows.setText("show subwindows"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showSubwindows, gbc); - public SimpleListModel(ArrayList list) { - this.list = list; - } + // more attributes + desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - public int getSize() { return list.size(); } - public Object getElementAt(int i) { return list.get(i); } - } + setContentPane(mainPanel); + } - /** - * A simple TableModel managing an array of Strings. - */ - public static class WindowTableModel implements TableModel { - private String[] head; - private String[][] data; - private X.Window[] windows; + /** + * A simple ListModel managing a list of objects. + */ + public static class SimpleListModel extends AbstractListModel { + private static final long serialVersionUID = 1L; + private ArrayList list; - public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { - this.head = head; - this.data = data; - this.windows = windows; - } + public SimpleListModel(ArrayList list) { + this.list = list; + } - public int getRowCount() { - return data.length; - } - public int getColumnCount() { - return head.length; - } - public String getColumnName(int columnIndex) { - return head[columnIndex]; - } - public Class getColumnClass(int columnIndex) { - return String.class; - } - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - public Object getValueAt(int rowIndex, int columnIndex) { - return data[rowIndex][columnIndex]; - } - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - } - public void addTableModelListener(TableModelListener l) { - } - public void removeTableModelListener(TableModelListener l) { - } + public int getSize() { return list.size(); } + public Object getElementAt(int i) { return list.get(i); } + } - public X.Window getWindow(int rowIndex) { - return windows[rowIndex]; - } - } + /** + * A simple TableModel managing an array of Strings. + */ + public static class WindowTableModel implements TableModel { + private String[] head; + private String[][] data; + private X.Window[] windows; + + public WindowTableModel(String[] head, String[][] data, X.Window[] windows) { + this.head = head; + this.data = data; + this.windows = windows; + } + + public int getRowCount() { + return data.length; + } + public int getColumnCount() { + return head.length; + } + public String getColumnName(int columnIndex) { + return head[columnIndex]; + } + public Class getColumnClass(int columnIndex) { + return String.class; + } + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + } + public void addTableModelListener(TableModelListener l) { + } + public void removeTableModelListener(TableModelListener l) { + } + + public X.Window getWindow(int rowIndex) { + return windows[rowIndex]; + } + } } From 3e4222da6c29729ffc7ca87c8913972532bf9af5 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Mon, 21 Jul 2014 20:46:05 -0400 Subject: [PATCH 11/13] added a changes line to the CHANGES.md file --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0cd59ccf9b..b2fe49fc6a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,11 +17,13 @@ Features * [#338](https://github.com/twall/jna/pull/338): Added `com.sun.jna.platform.mac.XAttr` and `com.sun.jna.platform.mac.XAttrUtil` JNA wrapper for `` for Mac OS X - [@rednoah](https://github.com/rednoah). * [#339](https://github.com/twall/jna/pull/339): Added `GetWindowPlacement`, `SetWindowPlacement`, `AdjustWindowRect`, `AdjustWindowRectEx`, `ExitWindowsEx`, and `LockWorkstation` to `com.sun.jna.platform.win32.User32` - [@Timeroot](https://github.com/Timeroot). * [#286](https://github.com/twall/jna/pull/286): Added in com.sun.jna.platform.win32.Kernel32: CreateRemoteThread, WritePocessMemory and ReadProcessMemory - [@sstokic-tgm](https://github.com/sstokic-tgm). +* Object-oriented X API allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248) Bug Fixes --------- * [#319](https://github.com/twall/jna/pull/319): Fix direct-mapping type-mapped pointer result types - [@marco2357](https://github.com/marco2357). * Added Variant and TlbImp Fixes - [@wolftobias](https://github.com/wolftobias). +* Object-oriented X API will now return null if the window property is not found - [@rm5248](https://github.com/rm5248) Release 4.1 =========== From a7475710b640f7276fc42b744b2a75e3b1f6fc4c Mon Sep 17 00:00:00 2001 From: rm5248 Date: Wed, 23 Jul 2014 16:41:25 -0400 Subject: [PATCH 12/13] fixed changes.md --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b2fe49fc6a..238abab972 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,13 +17,13 @@ Features * [#338](https://github.com/twall/jna/pull/338): Added `com.sun.jna.platform.mac.XAttr` and `com.sun.jna.platform.mac.XAttrUtil` JNA wrapper for `` for Mac OS X - [@rednoah](https://github.com/rednoah). * [#339](https://github.com/twall/jna/pull/339): Added `GetWindowPlacement`, `SetWindowPlacement`, `AdjustWindowRect`, `AdjustWindowRectEx`, `ExitWindowsEx`, and `LockWorkstation` to `com.sun.jna.platform.win32.User32` - [@Timeroot](https://github.com/Timeroot). * [#286](https://github.com/twall/jna/pull/286): Added in com.sun.jna.platform.win32.Kernel32: CreateRemoteThread, WritePocessMemory and ReadProcessMemory - [@sstokic-tgm](https://github.com/sstokic-tgm). -* Object-oriented X API allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248) +* [#350](https://github.com/twall/jna/pull/350): Object-oriented X API(jnacontrib.x11.api.X.Window) allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248). Bug Fixes --------- * [#319](https://github.com/twall/jna/pull/319): Fix direct-mapping type-mapped pointer result types - [@marco2357](https://github.com/marco2357). * Added Variant and TlbImp Fixes - [@wolftobias](https://github.com/wolftobias). -* Object-oriented X API will now return null if the window property is not found - [@rm5248](https://github.com/rm5248) +* [#350](https://github.com/twall/jna/pull/350): jnacontrib.x11.api.X.Window.getXXXProperty returns null if the window property is not found - [@rm5248](https://github.com/rm5248). Release 4.1 =========== From ba0b0fd052d3d607ba47c99b8f266f33e59064a4 Mon Sep 17 00:00:00 2001 From: rm5248 Date: Fri, 18 Jul 2014 19:15:41 -0400 Subject: [PATCH 13/13] Added the ability to see all subwindows. Added a dialog so users can see the recursive X windows Ensured that getting all windows from the X server works properly on 32-bit fixed indentation to be spaces instead of tabs more fixing of formatting added a changes line to the CHANGES.md file fixed changes.md Added the ability to see all subwindows. Added a dialog so users can see the recursive X windows Ensured that getting all windows from the X server works properly on 32-bit fixed indentation to be spaces instead of tabs more fixing of formatting added a changes line to the CHANGES.md file fixed changes.md --- CHANGES.md | 732 ++++++++++++++++++ contrib/x11/src/jnacontrib/x11/api/X.java | 139 +++- .../jnacontrib/x11/demos/XDesktopDemo.java | 198 ++++- 3 files changed, 1017 insertions(+), 52 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0cd59ccf9b..986710db39 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,732 @@ +<<<<<<< HEAD +NOTE: as of JNA 4.0, JNA is now dual-licensed under LGPL and ASL (see LICENSE). + +NOTE: JNI native support is typically incompatible between minor versions, and almost always incompatible between major versions. + +Next Release +============ + +Features +-------- +* Updated AIX natives and build - [@twall](https://github.com/twall). +* [#290](https://github.com/twall/jna/pull/290): Improved the stacktrace for the exceptions thrown by `com.sun.jna.Structure` - [@ebourg](https://github.com/ebourg). +* [#332](https://github.com/twall/jna/pull/332): Added Win32 Monitor Configuration API in `com.sun.jna.platform.win32.Dxva2` - [@msteiger](https://github.com/msteiger). +* Added Winspool monitor sample and updated Kernel32, WinBase, Winspool - [@wolftobias](https://github.com/wolftobias). +* Added Some minor changes to MS Office samples Test and small changes to the MS Office samples Bug Fixes - [@wolftobias](https://github.com/wolftobias). +* [#333](https://github.com/twall/jna/pull/333): Added `CoTaskMemAlloc`, `CoTaskMemRealloc` and `CoTaskMemFree` to `com.sun.jna.platform.win32.Ole32` - [@msteiger](https://github.com/msteiger). +* [#334](https://github.com/twall/jna/pull/334): Added `com.sun.jna.platform.win32.Shell32.SHGetKnownFolderPath` and `KnownFolders` GUID constants - [@msteiger](https://github.com/msteiger). +* [#338](https://github.com/twall/jna/pull/338): Added `com.sun.jna.platform.mac.XAttr` and `com.sun.jna.platform.mac.XAttrUtil` JNA wrapper for `` for Mac OS X - [@rednoah](https://github.com/rednoah). +* [#339](https://github.com/twall/jna/pull/339): Added `GetWindowPlacement`, `SetWindowPlacement`, `AdjustWindowRect`, `AdjustWindowRectEx`, `ExitWindowsEx`, and `LockWorkstation` to `com.sun.jna.platform.win32.User32` - [@Timeroot](https://github.com/Timeroot). +* [#286](https://github.com/twall/jna/pull/286): Added in com.sun.jna.platform.win32.Kernel32: CreateRemoteThread, WritePocessMemory and ReadProcessMemory - [@sstokic-tgm](https://github.com/sstokic-tgm). +* [#350](https://github.com/twall/jna/pull/350): Object-oriented X API(jnacontrib.x11.api.X.Window) allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248). + +Bug Fixes +--------- +* [#319](https://github.com/twall/jna/pull/319): Fix direct-mapping type-mapped pointer result types - [@marco2357](https://github.com/marco2357). +* Added Variant and TlbImp Fixes - [@wolftobias](https://github.com/wolftobias). +* [#350](https://github.com/twall/jna/pull/350): jnacontrib.x11.api.X.Window.getXXXProperty returns null if the window property is not found - [@rm5248](https://github.com/rm5248). + +Release 4.1 +=========== + +Features +-------- +* Added `com.sun.jna.platform.win32.Advapi32Util.registryCloseKey` - [@falldog](https://github.com/falldog). +* Enabled platform tests to be run w/o building native bits - [@twall](https://github.com/twall). +* Added COM/Typelib java code generator `com.sun.jna.platform.win32.COM.tlb.TlbImp` - [@wolftobias](https://github.com/wolftobias). +* [#226](https://github.com/twall/jna/issues/226): Added OSGI information to jna-platform.jar - [@brettwooldridge](https://github.com/brettwooldridge). +* [#267](https://github.com/twall/jna/pull/267): Added support for Windows RAS32 API, `com.sun.jna.platform.win32.Rasapi32` and `Rasapi32Util` - [@kc7bfi](https://github.com/kc7bfi). +* [#101](https://github.com/twall/jna/issues/101): Modify `com.sun.jna.platform.win32.Advapi32Util.registryGet*` API to support `KEY_WOW64` option - [@falldog](https://github.com/falldog). +* [#271](https://github.com/twall/jna/pull/271): Added `com.sun.jna.platform.win32.Gdi32.ChoosePixelFormat` and `SetPixelFormat` - [@kc7bfi](https://github.com/kc7bfi). +* [#271](https://github.com/twall/jna/pull/271): Added `com.sun.jna.platform.win32.OpenGL32`, `OpenGL32Util` and `WinOpenGL` - [@kc7bfi](https://github.com/kc7bfi). +* [#250](https://github.com/twall/jna/pull/250): Added `com.sun.jna.platform.win32.Kernel32.GetPrivateProfileSection`, `GetPrivateProfileSectionNames` and `WritePrivateProfileSection` and corresponding `Kernel32Util` helpers - [@quipsy-karg](https://github.com/quipsy-karg). +* [#287](https://github.com/twall/jna/pull/287): Added `DBTF_MEDIA` and `DBTF_NET` to `com.sun.jna.platform.win32.DBT` - [@daifei4321](https://github.com/daifei4321). +* [#295](https://github.com/twall/jna/pull/295): Added `com.sun.jna.platform.win32.Kernel32.ResetEvent` - [@manithree](https://github.com/manithree). +* [#301](https://github.com/twall/jna/pull/301): Added `accessCheck` to `com.sun.jna.platform.win32.Advapi32Util`, `MapGenericMask` and `AccessCheck` to `com.sun.jna.platform.win32.Advapi32`, `PRIVILEGE_SET` and `GENERIC_MAPPING` to `com.sun.jna.platform.win32.WinNT` - [@BusyByte](https://github.com/BusyByte). + +Bug Fixes +--------- +* Fixed inconsistent behavior on `Structure.ByValue` fields within a `Structure` - [@twall](https://github.com/twall). +* [#279](https://github.com/twall/jna/issues/279): Accommodate FreeBSD libc loading - [@sevan](https://github.com/sevan). +* [#287](https://github.com/twall/jna/pull/287): Fixed contrib `win32.Win32WindowDemo`, now showing the added/removed drive letter, and whether the event is about media in drive or physical drive - [@daifei4321](https://github.com/daifei4321). +* [#300](https://github.com/twall/jna/issues/300): Fix stdcall argument alignment - [@twall](https://github.com/twall). + +Release 4.0 +=========== + +Features +-------- +* Added ASL licensing to facilitate distribution - [@twall](https://github.com/twall). +* [#109](https://github.com/twall/jna/issues/109): Set default Java compatibility level to 1.6 - [@twall](https://github.com/twall). +* [#209](https://github.com/twall/jna/issues/209): Improved default performance saving last error results - [@twall](https://github.com/twall). +* Use predictable names for CPU architecture prefix (namely x86, x86-64); names correspond to OSGI processor values - [@twall](https://github.com/twall). +* Avoid superfluous Structure memory allocation from native - [@twall](https://github.com/twall). +* Added `Library.OPTION_CLASSLOADER`, which enables loading native libraries from any class loader (including JNA's native library). This enables parallel dependencies on JNA (e.g. within a tomcat deployment without having to include JNA in the app server environment) - [@twall](https://github.com/twall). +* Use per-library String encoding settings (see `Native.getDefaultStringEncoding()` and `Structure.getStringEncoding()`) - [@twall](https://github.com/twall). +* Added memory dump for debugging (see `com.sun.jna.Memory`) - [@twall](https://github.com/twall). +* Improved caching of Structure alignment, type mapping, and encoding information - [@twall](https://github.com/twall). +* [#225](https://github.com/twall/jna/pull/225): Added `platform.win32.Kernel32.GetLogicalProcessorInformation` and `platform.win32.Kernel32Util.getLogicalProcessorInformation` - [@trejkaz](https://github.com/trejkaz). +* [#236](https://github.com/twall/jna/issues/236): Auto-strip profiler native method prefix specified by `jna.profiler.prefix`, which defaults to $$YJP$$ - [@twall](https://github.com/twall). +* Added `jna.debug_load` property to diagnose library loading issues - [@twall](https://github.com/twall). +* Throw explicit `IllegalArgumentException` when `Structure.ByReference` is used where it shouldn't be (can result in multiply freed memory or other unexpected behavior) - [@twall](https://github.com/twall). +* [#243](https://github.com/twall/jna/issues/243): Automatically accommodate long library paths on Windows which would otherwise fail - [@twall](https://github.com/twall). +* [#241](https://github.com/twall/jna/issues/241) - Added `com.sun.jna.platform.win32.Shell32.SHAppBarMessage` - [@bsorrentino](https://github.com/bsorrentino). +* Make `Structure.read/writeField()` protected to facilitate per-field overrides - [@twall](https://github.com/twall). +* Speed up callback lookup where large numbers of native function pointers are in use - [@twall](https://github.com/twall). + +Bug Fixes +--------- +* [#213](https://github.com/twall/jna/pull/213): Fixed `Structure.toString()` not to dump memory when `jna.dump_memory` is false - [@tomohiron](https://github.com/tomohiron). +* Use dedicated TLS to indicate callback detach state, to avoid any potential conflicts with last error storage - [@twall](https://github.com/twall). +* [#173](https://github.com/twall/jna/issues/173): Fixed OSX 10.8/Xcode 4+ builds, web start path with Oracle 1.7 JDK - [@mkjellman](https://github.com/mkjellman). +* [#215](https://github.com/twall/jna/issues/215): Forced use of XSI `strerror_r` on linux - [LionelCons](https://github.com/LionelCons). +* [#214](https://github.com/twall/jna/issues/214): Don't map library names when an absolute path is provided - [@twall](https://github.com/twall). +* [#218](https://github.com/twall/jna/issues/218): Explicitly handled broken Android `SecurityManager` implementation - [@twall](https://github.com/twall). +* [#223](https://github.com/twall/jna/issues/223): Fixed layout/size derivation for unions - [@twall](https://github.com/twall). +* [#229](https://github.com/twall/jna/issues/229): Added `CreateProcessW` (Unicode version) - [@twall](https://github.com/twall). +* Avoid solaris/x86 JVM bug w/library open flags - [@twall](https://github.com/twall). +* Fixed NPE returning wide string from a direct-mapped function - [@twall](https://github.com/twall). +* [#237](https://github.com/twall/jna/issues/237): Fix LastErrorException/getLastError on AIX - [@skissane](https://github.com/skissane). +* [#228](https://github.com/twall/jna/issues/228): Fix win32/win64 crashes due to LastErrorException buffer overruns (`snprintf` on windows is broken) - [@davidhoyt](https://github.com/davidhoyt). + +Release 3.5.2 +============= + +Features +-------- +* Basic [COM support](https://github.com/twall/jna/blob/master/www/PlatformLibrary.md) for w32 - [@wolftobias](https://github.com/wolftobias). +* Avoid superfluous Structure memory allocation by using Structure(Pointer) ctors if available - [@twall](https://github.com/twall). +* [PR#120](https://github.com/twall/jna/pull/120): Provide methods for extracting native libraries from the class path for use by JNA - [@Zlika](https://github.com/Zlika). +* [PR#163](https://github.com/twall/jna/pull/163): The Java `GUID` structure can be used directly as alternative to `Ole32Util.getGUIDFromString()` - [@wolftobias](https://github.com/wolftobias). +* [PR#163](https://github.com/twall/jna/pull/163): Ported Win32 `dbt.h` - [@wolftobias](https://github.com/wolftobias). +* [PR#163](https://github.com/twall/jna/pull/163): Added Win32 `WTSRegisterSessionNotification()` and `WTSUnRegisterSessionNotification()` from `Wtsapi32.dll` - [@wolftobias](https://github.com/wolftobias). +* [PR#163](https://github.com/twall/jna/pull/163): Added Win32 `native_window_msg` that creates windows, registers for USB device and logon/logoff notifications - [@wolftobias](https://github.com/wolftobias). +* [PR#178](https://github.com/twall/jna/pull/178): Added Win32 `USER_INFO_10` structure from `LMAccess.h` - [@davidmc24](https://github.com/davidmc24). +* [PR#192](https://github.com/twall/jna/pull/192): Added Win32 `SHGetSpecialFolderPath()` and initialization file (.ini) API functions from `kernel32.dll` - [@headcrashing](https://github.com/headcrashing). +* [PR#194](https://github.com/twall/jna/pull/194): Added Unit Test for `CLSIDFromProgID()` - [@headcrashing](https://github.com/headcrashing). +* [PR#196](https://github.com/twall/jna/pull/196): Added Win32 `RegisterWindowMessage()` and new wrapper `User32Util` for convenient use of `RegisterWindowMessage`, `CreateWindow` and `CreateWindowEx` - [@headcrashing](https://github.com/headcrashing). +* [PR#187](https://github.com/twall/jna/pull/187): Allow StructureFieldOrderTest unit test in platform project to run on Linux. - [@bhamail](https://github.com/bhamail). + +Bug Fixes +--------- +* [PR#180](https://github.com/twall/jna/pull/180): Fix: added missing fields in `XEvents.getFieldOrder()` - [@xwizard](https://github.com/xwizard). +* [PR#183](https://github.com/twall/jna/pull/183): Fix `LMAccess.GROUP_INFO_3.getFieldOrder()` to return correct fields names - [@bhamail](https://github.com/bhamail). +* [PR#187](https://github.com/twall/jna/pull/187): Fix `getFieldOrder()` to return correct field names for some X11 structures - [@bhamail](https://github.com/bhamail). +* Remove deprecated methods on Memory (getSize,isValid) and Structure (getSize) - [@twall](https://github.com/twall). +* Remove problematic AWT check via `Class.forName("java.awt.Component")` (see [here](https://bugs.eclipse.org/bugs/show_bug.cgi?id=388170)) - [@twall](https://github.com/twall). +* [PR#210](https://github.com/twall/jna/pull/210) Add OSGI processor specs for Mac OS X - [@bertfrees](https://github.com/bertfrees). +* [PR#174](https://github.com/twall/jna/pull/174): Recompile linux-amd64 natives to remove glibc-2.11 dependencies, now requires only 2.2.5 or better - [@twall](https://github.com/twall). +* [PR#183](https://github.com/twall/jna/pull/183): Added `StructureFieldOrderInspector` unit test utility to scan for `Structure` field issues; see: `com.sun.jna.platform.StructureFieldOrderTest.testMethodGetFieldOrder` - [@bhamail](https://github.com/bhamail). +* [PR#187](https://github.com/twall/jna/pull/187): Allow `StructureFieldOrderTest` unit test in platform project to run on Linux - [@bhamail](https://github.com/bhamail). +* [#206](https://github.com/twall/jna/issues/206): Fix `moveToTrash()` on OSX to work with symlinks - [@twall](https://github.com/twall). +* Fix NPE if `Thread.getContextClassLoader()` returns `null` - [@twall](https://github.com/twall). + +Release 3.5.1 +============= + +Bug Fixes +--------- +* Fix bug where string fields sometimes failed to be writtern - [@twall](https://github.com/twall) (roman kisluhin). +* [PR#145](https://github.com/twall/jna/pull/145): Fix `Netapi32Util.getDomainTrusts()` returns "empty" domain object - [@aikidojohn](https://github.com/aikidojohn). +* [PR#145](https://github.com/twall/jna/pull/145): Fix `Netapi32.getDC()` - added missing fields in `DOMAIN_CONTROLLER_INFO` - [@aikidojohn](https://github.com/aikidojohn). +* [PR#151](https://github.com/twall/jna/pull/151): 'platform.jar' in the dist directory was not updated for release 3.5.0. (The 'platform.jar' published to maven central was correct.) + +Release 3.5.0 +============= + +Features +-------- +* [#62](https://github.com/twall/jna/issues/62) If a callback is required to reside in a DLL, use [`DLLCallback`](http://twall.github.com/jna/3.5.1/javadoc/com/sun/jna/win32/DLLCallback.html) to tag your Callback object - [@twall](https://github.com/twall). +* `Structure.getFieldOrder()` supersedes `Structure.setFieldOrder()` and is now required - [@twall](https://github.com/twall). +* Search `~/Library/Frameworks` and `/Library/Frameworks` on OSX - [@shaneholloway](https://github.com/shaneholloway). +* Automatic cleanup of native threads (based on suggestions from neil smith) - [@twall](https://github.com/twall). +* Add `android-arm` target - [@ochafik](https://github.com/ochafik), [@twall](https://github.com/twall). +* Add `jna.tmpdir` to override temporary JNA storage location - [@twall](https://github.com/twall). +* Add `EXTRA_MAKE_OPTS` ant property to override make variables - [@twall](https://github.com/twall). +* Add `Library.OPTION_OPEN_FLAGS` to customize dlopen behavior - [@twall](https://github.com/twall). +* [#113](https://github.com/twall/jna/issues/113), [#114](https://github.com/twall/jna/issues/114): Add support for GNU/kFreeBSD and debian multi-arch distros - [@twall](https://github.com/twall). + +Bug Fixes +--------- +* Fix `Advapi32Util.registryGetValues()` tried to allocate memory for a zero-length `REG_BINARY` value - [@phailwhale22](https://github.com/phailwhale22). +* Fix crash in direct mode callbacks with certain type conversions - [@twall](https://github.com/twall). +* More thoroughly propagate unexpected exceptions generated in jnidispatch - [@twall](https://github.com/twall). +* Cleanup maven poms and publishing to central repo - [@bhamail](https://github.com/bhamail). +* [#129](https://github.com/twall/jna/issues/129): Allow `Memory` field in structure - [@twall](https://github.com/twall). +* Preserve `PointerType` fields on `Structure.read()` if unchanged - [@twall](https://github.com/twall). +* [#128](https://github.com/twall/jna/issues/128): Fix masking extracting DWORD upper and lower WORD values - [@twall](https://github.com/twall). +* [#135](https://github.com/twall/jna/issues/135): Fix for `Advapi32Util.registryGetValues()` when reading zero length values - [@danwi](https://github.com/danwi). + +Release 3.4.2 +============= + +Features +-------- +* Add `platform.win32.Kernel32.GetEnvironmentVariable` and `platform.win32.Kernel32Util.getEnvironmentVariable` - [@dblock](https://github.com/dblock). +* Moved `Kernel32.dll` function definitions from `WinNT.java` into `Kernel32.java` - [@dblock](https://github.com/dblock). +* Provide `toPointer()` methods on all `_PTR` types (platform win32) - [@twall](https://github.com/twall). +* Provide `ant -Dskip-native` to skip platform native build - [@twall](https://github.com/twall). +* Provide `ant -Dheadless=true` to run unit tests headless - [@twall](https://github.com/twall). +* Added Windows dev environment instructions - [@twall](https://github.com/twall). + +Bug Fixes +--------- +* Ensure platform win32 classes use unsigned where appropriate (`ULONG_PTR`, `UINT_PTR`, `ULONGLONG`, `WORD`, `DWORDLONG`) - [@twall](https://github.com/twall). +* [#71](https://github.com/twall/jna/issues/71), [#73](https://github.com/twall/jna/issues/73): Fix OSGI entries in manifest - [@twall](https://github.com/twall). +* [#78](https://github.com/twall/jna/issues/78): Fix NPE in `platform.win32.Netapi32Util.getDomainTrusts` - [@dblock](https://github.com/dblock). +* Fix: auto-sync memory for `struct**` arguments (array of struct pointers) - [@twall](https://github.com/twall). +* Fix: `platform.win32.Secur32.AcquireCredentialsHandle`, `InitializeSecurityContext` and `AcceptSecurityContext` on Win32 64-bit - [@dblock](https://github.com/dblock). +* Fix: avoid overwriting native `char *` or `wchar_t *` fields within structures when unmodified (similar to current operation with pointers) - [@twall](https://github.com/twall). +* Fix: `platform.win32.DsGetDC.DS_DOMAIN_TRUSTS` and `DsEnumerateDomainTrusts` on Win32 64-bit - [@trejkaz](https://github.com/trejkaz). +* Fix: Crash freeing the wrong pointer in `Netapi32Util.getDomainTrusts` - [@trejkaz](https://github.com/trejkaz). +* [#100](https://github.com/twall/jna/issues/100): Fix `platform.win32.W32FileMonitor` - [@dblock](https://github.com/dblock). +* Return INT_PTR from `platform.win32.Shell32.ShellExecute`, since returning +`HINSTANCE` is useless. +* Fix runtime error in some instances where Structure.setFieldOrder is used (never return self when sharing AutoAllocated memory). +* [#107](https://github.com/twall/jna/issues/107): `Structure.clear()` always calls `ensureAllocated()` to avoid NPE. +* Ensure internal memory pointer is *always* allocated when calling `Structure.useMemory()`, even if layout is not yet determined. + +Release 3.4.1 +============= + +Features +-------- +* Add 'unsigned' modifier to IntegerType. +* Add to `platform.win32.User32`: `GetLastInputInfo`. +* Add `platform.win32.WinNT.GetFileType` and `platform.win32.Kernel32Util.getFileType`. +* Add to `platform.win32.Kernel32Util`: `getFileType`. + +Bug Fixes +--------- +* Re-build linux-amd and linux-i386 against older versions of glibc (2.2.5 and +2.1.3 respectively). +* Properly initialize first printer info struct in winspool library. +* Properly support getting and setting zero-array-length `REG_MULTI_SZ` values on Win32. +* Fixed SID in Win32 `USER_INFO_23` and `GROUP_INFO_3`. +* Fixed passing domain name into Win32 `Netapi32Util.getUserInfo`. + +Release 3.4.0 +============= + +Features +-------- +* Provide `jna.nosys=true` to avoid loading any system-provided JNA (useful for local build/development). +* Allow override of default jnidispatch library name with `jna.boot.library.name` system property. +* Throw an Error if a system install of JNA is incompatible or if JNA's JNI library does not match. +* Disable automatic jnidispatch unpacking with `jna.nounpack=true`. +* Automatically look up system error messages for LastErrorException. +* Improved callback thread-mapping support; re-use, rename, and group callback +threads. +* Cache structure layout results, improving performance of structure creation. +* linux/arm 32-bit support (hardware provided by Alex Lam). +* linux/ppc 32-bit support (hardware provided by Fritiof Hedman). +* Preliminary linux/ia64, linux/ppc64 support (thanks to Laurent Guerby and the GCC compile farm). +* Windows CE/Mobile support (w32ce-arm) (resources provided by andrea antonello and Hydrologis SRL). +* linux multi-arch support (kohsuke). +* Added REG_QWORD registry type support +* Add to `platform.unix.x11`: `XGrabKey`, `XUngrabKey`, `XSetErrorHandler`. +* Add to `platform.mac.Carbon`: `GetEventDispatcherTarget`, `InstallEventHandler`, `RegisterEventHotKey`, `GetEventParameter`, `RemoveEventHandler`, `UnregisterEventHotKey`. +* Add to `platform.win32.Kernel32`: `CopyFile`, `MoveFile`, `MoveFileEx`, `CreateProcess`, `SetEnvironmentVariables`, `GetFileTime`, `SetFileTime`, `SetFileAttributes`, `DeviceIoControl`, `GetDiskFreeSpaceEx`, `CreateToolhelp32Snapshot`, `Process32First`, `Process32Next`. +* Add to `platform.win32.Msi`: `MsiGetComponentPath`, `MsiLocateComponent`, `MsiGetProductCode`, `MsiEnumComponents`. +* Add to `platform.win32.User32`: `RegisterHotKey`, `UnregisterHotKey` +* Add to `platform.win32.SetupApi`: `SetupDiGetClassDevs`, `SetupDiDestroyDeviceInfoList`, `SetupDiEnumDeviceInterfaces`, `SetupDiGetDeviceInterfaceDetail`, `SetupDiGetDeviceRegistryProperty`. +* Add `platform.win32.Shell32.ShellExecute`. +* Add to `platform.win32.User32`: `SetParent`, `IsWindowVisible`, `MoveWindow`, `SetWindowPos`, `AttachInputThread`, `SetForegroundWindow`, `GetForegroundWindow`, `SetFocus`, `SendInput`, `WaitForInputIdle`, `InvalidateRect`, `RedrawWindow`, `GetWindow`, `UpdateWindow`, `ShowWindow`, `CloseWindow`. +* Add to `platform.win32.Version`: `GetFileVersionInfoSize`, `GetFileVersionInfo`, `VerQueryValue`. +* Add to `platform.win32.Advapi32`: `GetFileSecurity`, `RegQueryValueEx(...Long...)`. +* Add to `platform.win32.Netapi32`: `NetUserGetInfo`. + +Bug Fixes +-------- +* Revise cleanup of in-use temporary files on win32 (issue 6). +* Fix structure alignment issues on linux/ppc. +* Fix structure alignment issues on linux/arm. +* Account for NIO Buffer position (JIRA issue 185). +* Avoid crash with very long Strings (> 150k in length). +* Fix bug tracking Memory with an associated direct ByteBuffer. +* Fix bug handling structs by value when type mappers are in effect (JIRA issue 188). + +Release 3.3.0 +============= + +Features +-------- + +* Facilitate `Memory` subclasses (jbellis). +* Allow multiple fields of the same type in Unions (Francis Barber). +* Add `platform.win32.Advapi32.AdjustTokenPrivileges`, `platform.win32.Advapi32.LookupPrivilegeName`, `platform.win32.Advapi32.LookupPrivilegeValue`, `platform.win32.Advapi32.ImpersonateSelf`. +* Add `platform.win32.Advapi32.DuplicateTokenEx`, `platform.win32.Advapi32.CreateProcessAsUser`, `platform.win32.Kernel32.GetExitCodeProcess`, `platform.win32.Kernel32.TerminateProcess`, `platform.win32.Kernel32.ReadFile`, `platform.win32.Kernel32.CreatePipe`, `platform.win32.Kernel32.SetHandleInformation` and related constants / structures in `platform.win32.WinBase` and `platform.win32.WinNT`. Please note that the `SECURITY_ATTRIBUTES` structure has been moved from `platform.win32.WinNT` to `platform.win32.WinBase`. +* Add `platform.win32.Kernel32.DeleteFile` and `platform.win32.Kernel32Util.deleteFile`. +* Add `platform.win32.Kernel32.GetFileAttributes` and `platform.win32.Kernel32Util.getFileAttributes`. +* Add `platform.win32.Kernel32.GetTickCount`. +* Add Win32 Service functions to `platform.win32.Advapi32`. +* Add `platform.win32.W32ServiceManager` and `W32Service`. +* Add Win32 Event Logging functions to `platform.win32.Advapi32` and `platform.win32.Advapi32Util.EventLogIterator`. +* `platform.win32.Advapi32Util.registryCreateKey` returns `true` if key was created, `false` if it already exists. +* Add `REG_BINARY`, `REG_EXPAND_SZ` and `REG_MULTI_SZ` support to `platform.win32.Advapi32Util` registry functions. +* Reduce JNI crossings in a number of native methods, moving object creation out into pure Java code. + +Bug Fixes +--------- + +* Move all native functions into `com.sun.jna.Native`, to ensure that all dependent classes must be disposed before the `Native` class is unloaded. Note that this change is incompatible with all previous JNA native libraries. +* Fix `platform.win32.Kernel32.GetNativeSystemInfo` and `GetSystemInfo` AV on Win64. +* Fix several potential minor bugs as reported by TvT. +* Fix bug in Structure.StructureSet.toString (Blair Zajac), exposed by Tomcat ThreadLocal cleanup. +* Fix several bugs when using Structure(Pointer) ctor and array fields (Samuel Audet). + +Release 3.2.7 +============= + +Features +-------- + +* Add native peer value accessors for Pointer +* The `jna.library.path` property is now re-evaluated whenever a native library is loaded. Previously this value was cached when the JNA classes loaded. +* `Native.loadLibrary` can now load `.drv` files. +* Refactor `com.sun.jna.platform.win32.WINBASE` into `WinDef`, `WinNT` and `BaseTSD`, matching Windows SDK headers. +* Refactor constants from `com.sun.jna.platform.win32.GDI32` into `WinGDI`, matching Windows SDK headers. +* Refactor constants from `com.sun.jna.platform.win32.User32` into `WinUser`, matching Windows SDK headers. +* Refactor `platform.win32.WinNT.LARGE_INTEGER` into a union. +* Add `platform.win32.ObjBase`, `com.sun.jna.platform.win32.Ole32.CoInitializeEx`, `CoUninitialize`, and `CoCreateInstance`. +* Add `platform.win32.Oleaut32.SysAllocString` and `SysFreeString`. +* Add `platform.win32.Secur32.ImpersonateSecurityContext` and `RevertSecurityContext`. +* Add `platform.win32.WinNT.WELL_KNOWN_SID_TYPE`, `SECURITY_MAX_SID_SIZE` and other related SID-related constants. +* Add `platform.win32.Advapi32.CreateWellKnownSid` and `IsWellKnownSid` and `com.sun.jna.platform.win32.Advapi32Util.isWellKnownSid`. +* Add `platform.win32.Kernel32.GetVersion`, `GetVersionEx`, `GetSystemInfo`, `GetNativeSystemInfo`, `GlobalMemoryStatusEx`, `GetLogicalDriveStrings` and `IsWow64Process`. +* Add `platform.win32.Kernel32Util.getLogicalDriveStrings`. +* Add `platform.win32.User32.GetSystemMetrics`. +* Add `platform.win32.BaseTSD.DWORD_PTR`. +* Add `platform.win32.WinBase.SYSTEM_INFO` and `MEMORYSTATUSEX`. +* Add `platform.win32.WinNT.OSVERSIONINFOEX`, `VER` constants. +* Add `platform.win32.WinDef.ULONGLONG` and `DWORDLONG`. +* Add `platform.win32.Shell32.SHGetDesktopFolder` (prep work for Com4JNA). +* Add `platform.win32.Winspool.GetPrinterInfo`. +* Add `platform.win32.WinspoolUtil.getPrinterInfo1`. +* Add `platform.win32.GDI32.GetDeviceCaps`. +* Add `platform.win32.GDI32.GetDIBits`. + +Bug Fixes +--------- + +* Fix `ClassCastException` in `Structure.equals` (issue 152). +* Fix bug initializing a structure object from existing memory when the structure has initialized fields (issue 133). +* Fix NPE reading an array of string from a pointer when an element of the array is `NULL` (issue 151). +* Avoid calling `UnregisterNatives` in native code (issue 154). +* Compare unpacked library path against canonical (long) filename (issue 156). +* Fix `read()` of uninitialized memory in `platform.win32.Advapi32Util.getTokenGroups` and `getTokenAccount`. +* Fix `com.sun.jna.platform.win32.Secur32.QuerySecurityContextToken` to take a `CtxtHandle` instead of `PSecHandle`. +* Fix definition of BITMAPINFO (platform/win32). + +Release 3.2.5 +============= + +Features +-------- + +* Split code in examples.jar into a contrib platform.jar package and individual packages for demos. +* Fix Eclipse build and added Eclipse projects for all contrib samples, import projects from jnalib and contrib. +* Ensure Structure fields correctly ordered when inherited. +* Use explicit Structure field whenever provided, regardless of whether the VM requires it. +* Add Win32 mappings for two dozen functions from Kernel32.dll, Advapi32.dll, Netapi32.dll, Secur32.dll, NtDll.dll, Ole32.dll, Shell32.dll and Crypt32.dll to com.sun.jna.platform.win32. +* Port parts of WinError.h, WinNT.h, LMAccess.h, LMCons.h, LMErr.h, LMJoin.h, NTStatus.h, ShlObj.h, WinDef.h, ShellApi.h, Wdm.h, WinReg.h, WinCrypt.h, Sspi.h, Guid.h, NtSecApi.h and DsGetDc.h. +* Add Win32 simplified utility interfaces Kernel32Util, Advapi32Util, Netapi32Util, Crypt32Util, NtDllUtil, Shell32Util, Ole32Util and Secur32Util to com.sun.jna.platform.win32. +* Support unicode paths in W32FileUtils. +* Fix exception during dispose in W32FileMonitor. + +Bug Fixes +--------- + +* Provide String.replace for 1.4 compatibility. +* Avoid allocating memory when Structure is provided a pointer in the ctor. +* Ensure proper value returned in Pointer.getValue() for non-null, unchanged NIO Buffer values. +* Use 1.4-compatible URI generation (issue 149). + +Release 3.2.4 +============= + +Features +-------- + +* Make Pointer ctor public. +* Provide access to Function objects for arbitrary Pointer values. +* Add linux/ia64 binaries (bpiwowar). See issue 134 patch. + +Bug Fixes +--------- + +* Use a more robust method to decode a file-based URL (issue 135). + +Release 3.2.3 +============= + +Features +-------- + +* Include version information in code in case package information lost. + +Bug Fixes +--------- + +* Fix WindowUtils exception on mouse over TrayIcon. +* Fix bug toggling windows transparent/opaque (win32/OSX). +* Avoid overwriting unchanged Pointer values in arrays (function calls with Pointer[] and Structure.read). +* Ensure Structure fields marked `final` are never written. +* Fix bug preventing proper population Structure.ByReference fields on Structure read. +* Ensure double buffering is disabled in components added to a transparent window. +* Fix UnsatisfiedLinkError attempting to load system libraries under Web Start. +* Fix loading Web Start-provided libraries on OSX (libraries must have a .jnilib suffix under Web Start). +* Properly include sources in Maven zip file (Issue 129). + +Release 3.2.2 +============= + +Features +-------- + +* Provide length-specified Pointer.getStringArray() + +Bug Fixes +--------- + +* Fix crash with direct mapping if NULL struct* used (Issue 125). +* Fix case where null-valued Structure fields would get non-null values on write. +* Synch callback Structure/Structure[] arguments on callback return. +* Fix NPE when mapping an interface to the current process. +* Automatically load proper C library version from current process on Linux (avoids crashing bug on Ubuntu with libc-i686 packages active). +* Avoid scanning structure contents in Structure.toString if contents aren't actually used. + +Release 3.2.1 +========== + +Features +-------- + +* Add HRESULT, LONG mapping to W32API (marc strapetz). + + +Bug Fixes +--------- + +* Fix definition of HWND_BROADCAST in W32API. +* Fix memory alignment checking (Issue 121). +* Fix Structure equals/hashCode implementation, based on current Java fields rather than strictly native memory contents. Avoid using equals/hashCode when avoiding recursive reads/writes. + +Release 3.2.0 +============= + +Features +-------- + +* Handle String, Structure, Callback, Buffer, and primitive arrays in direct mappings. Handle NativeMapped and TypeMapper, with optimized paths for IntegerType and PointerType. +* Optionally throw errno/GetLastError as an exception. This is preferred to (and more efficient than) calling Native.getLastError(). +* Unload/delete native library unpacked from jna.jar if Native class is garbage collected. Only install shutdown hook if using the system class loader. +* Auto-write contiguous Structure arrays when first element is written. +* Support NativeMapped[] as function arguments for interface-mapped libraries (Issue 90). +* Enable function lookup within current process on Windows. + +Bug Fixes +--------- + +* Restrict recursive structure reads/writes by thread instead of globally. This avoids potentially missed reads/writes with concurrent access (Issue 120). +* Ensure Memory is not GC'd and freed if direct NIO buffers mapped to it are extant. +* Allow types derived from java.nio.Buffer as Structure fields. + +Release 3.1.0 +============= + +Features +-------- + +* Add raw JNI mapping of static Java methods. Performance is about 10X that of traditional JNA interface mapping, although with less type conversion functionality. +* Add library option to allow passing/return of Java Objects. +* Allow handling of uncaught callback exceptions (Issue 63). +* Object oriented interface to X server (see contrib/x11) +* Make Memory class more accessible. +* Provide Structure ctor with Pointer argument (issue 102). +* Allow implicit library access to current process on linux (issue 98). +* Open all shared libraries with RTLD_GLOBAL, if applicable. This was the default behavior on OSX and changes the default behavior on linux. +* Allow NIO Buffer as Structure field (with limitations) (Issue 57) +* Add `size_t` size. + +Bug Fixes +--------- + +* Run tests with libjsig.so, if available, which fixes some crashes when running tests on 64-bit platforms. +* Fix Issue 104. +* Fix Issue 94 (Java 1.6 update 10 regression). +* Fix Issue 51 (Java 1.6 update 10 regression). +* Fix Issue 95. +* Fix Issue 101. +* Fix Issue 111, memory leak with String-returning Callback. +* Fix missing storage of union type information (affects usage of struct/union by value as argument and return type). +* Remove non-functional Structure ctors requiring explicit size. + +Release 3.0.9 +============= + +Bug Fixes +--------- + +* Fix issue 93 by only manually searching jna.library.path, then falling back to passing the mapped library name to dlopen/LoadLibrary. This fixes an issue in JRUBY where the incorrect libc.so.6 was being loaded. + +Release 3.0.8 +========== + +Features +-------- + +* Auto-map Pointer[]/String[]/WString[] return values. +* Provide utility functions to convert String to primitive array. +* Add jna.library.boot.path property to define the directory that the native stub library is loaded from + +Release 3.0.7 +========== + +Features +-------- + +* Improve Win32 loading of libraries with dependencies. + +Bug Fixes +--------- + +* Fix bug reading structures with PointerType fields, introduced with Pointer field preservation fix. + +Release 3.0.6 +============= + +Features +-------- + +* Allow arbitrary callback method names if only one method is defined in the class which implements Callback (colinwalters). +* Allow specification of callback type mappers by using a TYPE_MAPPER field (colinwalters). +* Allow uninitialized (null-valued) boxed primitives in Structures (colinwalters). +* Add convenience methods to set active Union field and value simultaneously (xylo). +* Augment Union read/writeField to set the active field. +* Allow Structure auto-synch across native calls to be disabled. +* Win64 support. + +Bug Fixes +--------- + +* Avoid overwriting unchanged Structure fields of type Pointer. +* Avoid more content dragging on OSX or warn if it's too late. +* Fix UnsatisfiedLinkError using transparent window on Win2K. +* Fix memory leak with callbacks called from native threads with no Java context (johnwallace). +* Defer structure size calculation if type mapper not yet set, allowing type mapper to be set in derived constructors (colinwalters). +* Ensure structure memory is allocated in Structure.read/writeField. + +Release 3.0.5 +============= + +Features +-------- + +* Allow explicit declaration of field order for VMs which have an unpredictable field order. +* Check for w32 libraries with a "lib" prefix in addition to normal lookup. +* Allow String[]/WString[] as callback argument/return value (assume NULL-terminated array). +* Add Solaris8 compatibility to sunos-sparc build (Corey Puffalt). +* Look up libraries using web start library path, if appropriate (Corey Puffalt). +* Use constants to return integer boolean values. + +Bug Fixes +--------- + +* Properly track cursor on alpha-masked windows. +* Avoid searching /lib or /usr/lib on 64-bit Linux. +* Avoid using incorrect version of a library when both 32- and 64-bit versions are found. +* Avoid transparent window events always dragging window bug on OSX. +* Fix division by zero error calculating structure size on OSX/ppc. +* Avoid overwriting initialized NativeMapped Structure fields when calculating structure size. +* Fix NPE reading back into StringArray. + +Release 3.0.4 +============= + +Features +-------- + +* Automatically write contents of Structure.ByReference fields on Structure.write(). +* Use the actual parameter type in Function invocations if no parameter type information is available (whether method is missing or untyped varargs). +* Augmented X11 library mappings (xylo). +* Support read/write of NativeMapped arrays within Structure (notably NativeLong). + +Bug Fixes +--------- + +* Fix library load error when /usr/lib32 and /usr/lib both exist (linux) (Marek Slama). +* Avoid incorrect matches against libraries named with the same prefix (e.g. libc-client.so vs libc.so) (xylo). +* Properly handle arrays of NativeMapped (e.g. NativeLong) as a Structure field (stefan endrullis). +* Ensure structure size calculated prior to setting union active type. +* XID is 64-bits on 64-bit X clients (xylo). +* Ensure proper arch name is used on Debian (amd64 instead of x86_64). + +Release 3.0.3 +============= + +Features +-------- + +* Enable build/run using IBM's J9 VM (leonardo). +* Make StdCallFunctionMapper attempt a leading underscore if the simpler mapping doesn't work. +* Allow Structure.read to overwrite final fields (may not work on some 1.4 VMs). + +Bug Fixes +--------- + +* Fix NPE when passing an array of Structure.ByReference. +* Compare entire linux library version when finding a match. +* Don't pass struct by value unless the method signature declares it. +* Restrict custom first element structure alignment to OSX/ppc. +* Improve performance and reduce memory footprint for window masks. Optimize polygon-based masks on w32. Use XFillRectangles on X11. +* Fix linkage settings on sunos-amd64 to avoid relocation errors. +* Fix callback allocation code on w32, solaris, freebsd, darwin (libffi was misconfigured). +* Fix bug when NativeMapped fields are used in a Structure.ByValue instance. +* Fix NPE calling Structure.read() before memory is initialized. +* Fix NPE calling Structure.read/write with uninitialized NativeMapped fields. + +Release 3.0.2 +============= + +Features +-------- + +* Attempt to force unload of jnidispatch library prior to deleting it (w32). +* Added amd64 targets for OSX, FreeBSD, and Solaris. + +Bug Fixes +--------- + +* Reduce space allocated for invocation arguments. +* Fix NPE when NativeMapped type is used in a Structure. +* Fix some X11 type mappings for 64-bit. +* Fix OSX Leopard/JRE1.5+ window transparency. +* Fix window alpha compositing on X11. +* Fix loading of libraries with unicode names on OSX. + +Release 3.0.1 +============= + +Features +-------- + +* Improve transparent window drawing performance on w32 +* Use closure allocation from libffi + +Bug Fixes +--------- + +* Ensure nested structure arrays initialized with Structure.toArray use the appropriate native memory. +* Ensure structure size is calculated prior to converting to array +* Avoid creating new windows when setting a window mask +* Fix bug in Pointer.setChar. + +Release 3.0 +=========== + +Features +-------- + +* More supported platforms, via GCC's libffi (wmeissner) +* Support struct by value as parameter and return value (duncan) +* Support struct by reference within structures +* Provide access to native peer for java.awt.Component +* Provide access to native peer on OS X. +* Support MINGW32 builds (fullung) +* Allow per-field Structure read/write by field name +* Avoid writing Structure fields marked 'volatile' +* Read and wrap function pointers in Structure fields when read with a Java proxy to allow easy Java-side invocation (Ken Larson) +* Support array-backed Buffers as arguments (wmeissner) +* Auto-conversion of custom types (wmeissner) +* Allow pointer type-safety +* Optional VM crash protection, via Native.setProtected(boolean) +* Auto-convert WString[] +* Provide library synchronization wrapper similar to Collections.synchronizedX +* Support lookup of OSX framework libraries by name +* Explicit access to shared library global data +* Invocation interception to facilitate translation of C preprocessor macros and inline functions +* Provide utility to determine Web Start native library cache location; auto-include this path if jnidispatch is included as a <nativelib> (robertengels) +* Provide access to aligned memory +* Versioning information embedded in jna.jar and native library + +Bug Fixes +--------- + +* Avoid attempts to free native library if it failed to load (wmeissner) +* Explicitly check method signatures for varargs instead of heuristically guessing (wmeissner) +* Disallow declaring Pointer-derived fields in Structures (Function, Memory) +* Ensure Object.toString/hashCode/equals methods are intercepted on proxyied interfaces +* Update X11 library for 64-bit use (wmeissner) +* Properly map arrays of char*/wchar_t* under w32 +* Allow Pointer[] as a Structure field and Function argument +* Fix some misleading Structure error messages +* Properly preserve/return GetLastError/errno after native calls +* Allocate executable memory on w32 to avoid errors with hardware-enforced data execution protection (DEP) +* Fix VM crash on w32 stdcall callbacks +* Use long offsets and sizes rather than ints (64-bit safe) +* Properly clean up references and release closure memory on JNI_Unload +* Use simpler AWT/JAWT library loading workaround +* Avoid changing array references within a Structure on read + +Release 2.5 +=========== + +Features +-------- + +* Unions +* Optimized shaped windows (chris deckers & olivier chafik); instantiation time improved by about 2-3 orders of magnitude for large, mostly contiguous shapes +* Provide type mapping in callback arguments/results +* Provide access to ByteBuffer direct address as a Pointer +* Provide customization of native string encoding with jna.encoding system property + +Bug Fixes +--------- + +* Properly handle VMs with reversed Structure member storage +* Avoid making window undecorated when clearing window mask on X11 +* Fix structure alignment bug on OSX/PPC when first element is > 4 bytes in size +* Clearing OSX window mask by setting to MASK_NONE now works properly +* Avoid index exceptions if native buffers are not NUL-terminated on string conversions +* Write initialized Structure[] argument memory prior to function calls +* Fix IllegalArgumentException reading WString into a Structure +* Clear memory when allocating a structure block (fixes VM crash) +* Remove versioned JAWT dependency on OSX, allowing use on 10.3/JRE1.4. + +Release 2.4 +=========== + +Features +-------- + +* Explicitly support unaligned structures +* Auto-reallocate structure arrays +* Automatic handling of w32 UNICODE/ASCII variants +* Automatic mapping of decorated w32 stdcall function names +* Customizable, automatic type conversion of arguments and results (wmeissner) +* Support char*[] arguments as Java String[] +* Structure supports Callback members (wmeissner) +* getByteBuffer from Pointer/Memory (wmeissner) +* Allow GC of native libraries +* Facilitate use from non-Java contexts (JRuby et al.) (wmeissner) +* Improve library path searching (wmeissner) +* Handle Structure[] arguments +* Handle native long arguments and return values +* Handle direct and array-based ByteBuffer arguments (wmeissner) +* Change default w32 build to use GCC (it's free, yo) + +Bug Fixes +--------- + +* Structure.toArray failed to initialize members +* Disallow explicit free of Structure/Memory +* Ensure native libraries are only loaded once until released +* Properly handle NULL when the return value is a Structure +* Proper conversion to wchar_t on linux +* Copy full length of Java strings to C strings instead of stopping when a NUL character is encountered + +======= NOTE: as of JNA 4.0, JNA is now dual-licensed under LGPL and ASL (see LICENSE). NOTE: JNI native support is typically incompatible between minor versions, and almost always incompatible between major versions. @@ -17,11 +746,13 @@ Features * [#338](https://github.com/twall/jna/pull/338): Added `com.sun.jna.platform.mac.XAttr` and `com.sun.jna.platform.mac.XAttrUtil` JNA wrapper for `` for Mac OS X - [@rednoah](https://github.com/rednoah). * [#339](https://github.com/twall/jna/pull/339): Added `GetWindowPlacement`, `SetWindowPlacement`, `AdjustWindowRect`, `AdjustWindowRectEx`, `ExitWindowsEx`, and `LockWorkstation` to `com.sun.jna.platform.win32.User32` - [@Timeroot](https://github.com/Timeroot). * [#286](https://github.com/twall/jna/pull/286): Added in com.sun.jna.platform.win32.Kernel32: CreateRemoteThread, WritePocessMemory and ReadProcessMemory - [@sstokic-tgm](https://github.com/sstokic-tgm). +* [#350](https://github.com/twall/jna/pull/350): Object-oriented X API(jnacontrib.x11.api.X.Window) allows you to get subwindows of an X.Window - [@rm5248](https://github.com/rm5248). Bug Fixes --------- * [#319](https://github.com/twall/jna/pull/319): Fix direct-mapping type-mapped pointer result types - [@marco2357](https://github.com/marco2357). * Added Variant and TlbImp Fixes - [@wolftobias](https://github.com/wolftobias). +* [#350](https://github.com/twall/jna/pull/350): jnacontrib.x11.api.X.Window.getXXXProperty returns null if the window property is not found - [@rm5248](https://github.com/rm5248). Release 4.1 =========== @@ -723,3 +1454,4 @@ Bug Fixes * Proper conversion to wchar_t on linux * Copy full length of Java strings to C strings instead of stopping when a NUL character is encountered +>>>>>>> 254054e... fixed changes.md diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index e8a76b95e9..91974e41f2 100644 --- a/contrib/x11/src/jnacontrib/x11/api/X.java +++ b/contrib/x11/src/jnacontrib/x11/api/X.java @@ -27,6 +27,7 @@ import com.sun.jna.platform.unix.X11; import com.sun.jna.platform.unix.X11.Atom; +import com.sun.jna.platform.unix.X11.WindowByReference; /** * Object oriented X window system. @@ -51,16 +52,16 @@ public class X { private static int bytesToInt(byte[] prop) { return ((prop[3] & 0xff) << 24) - | ((prop[2] & 0xff) << 16) - | ((prop[1] & 0xff) << 8) - | ((prop[0] & 0xff)); + | ((prop[2] & 0xff) << 16) + | ((prop[1] & 0xff) << 8) + | ((prop[0] & 0xff)); } private static int bytesToInt(byte[] prop, int offset) { return ((prop[3 + offset] & 0xff) << 24) - | ((prop[2 + offset] & 0xff) << 16) - | ((prop[1 + offset] & 0xff) << 8) - | ((prop[offset] & 0xff)); + | ((prop[2 + offset] & 0xff) << 16) + | ((prop[1 + offset] & 0xff) << 8) + | ((prop[offset] & 0xff)); } @@ -303,11 +304,11 @@ public void showingDesktop(boolean state) throws X11Exception { * @param on true if auto-repeat shall be enabled */ public void setKeyAutoRepeat(boolean on) { - if (on) { - x11.XAutoRepeatOn(x11Display); - } else { - x11.XAutoRepeatOff(x11Display); - } + if (on) { + x11.XAutoRepeatOn(x11Display); + } else { + x11.XAutoRepeatOff(x11Display); + } } /** @@ -586,7 +587,7 @@ public String getWindowClass() throws X11Exception { * @return PID of the window * @throws X11Exception thrown if X11 window errors occurred */ - public int getPID() throws X11Exception { + public Integer getPID() throws X11Exception { return getIntProperty(X11.XA_CARDINAL, "_NET_WM_PID"); } @@ -645,10 +646,10 @@ public Geometry getGeometry() { x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, borderWidth, depth); x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); + junkY.getValue(), x, y, junkRoot); return new Geometry(x.getValue(), y.getValue(), width.getValue(), height.getValue(), - borderWidth.getValue(), depth.getValue()); + borderWidth.getValue(), depth.getValue()); } /** @@ -670,7 +671,7 @@ public Rectangle getBounds() { x11.XGetGeometry(display.x11Display, x11Window, junkRoot, junkX, junkY, width, height, border_width, depth); x11.XTranslateCoordinates(display.x11Display, x11Window, junkRoot.getValue(), junkX.getValue(), - junkY.getValue(), x, y, junkRoot); + junkY.getValue(), x, y, junkRoot); int xVal = x.getValue(); int yVal = y.getValue(); @@ -731,11 +732,15 @@ public int close() throws X11Exception { * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as integer + * @return property value as integer or null if not found * @throws X11Exception thrown if X11 window errors occurred */ - public int getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - return bytesToInt(getProperty(xa_prop_type, xa_prop_name)); + public Integer getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return bytesToInt(property); } /** @@ -746,7 +751,7 @@ public int getIntProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X * @return property value as integer * @throws X11Exception thrown if X11 window errors occurred */ - public int getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { + public Integer getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { return getIntProperty(xa_prop_type, display.getAtom(xa_prop_name)); } @@ -755,11 +760,14 @@ public int getIntProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11 * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as window + * @return property value as window, or null if not found * @throws X11Exception thrown if X11 window errors occurred */ public Window getWindowProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { - int windowId = getIntProperty(xa_prop_type, xa_prop_name); + Integer windowId = getIntProperty(xa_prop_type, xa_prop_name); + if( windowId == null ){ + return null; + } X11.Window x11Window = new X11.Window(windowId); return new Window(display, x11Window); } @@ -781,13 +789,16 @@ public Window getWindowProperty(X11.Atom xa_prop_type, String xa_prop_name) thro * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as a null terminated byte array + * @return property value as a null terminated byte array, or null if not found * @throws X11Exception thrown if X11 window errors occurred */ public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { byte[] bytesOrig = getProperty(xa_prop_type, xa_prop_name); byte[] bytesDest; + if( bytesOrig == null ){ + return null; + } // search for '\0' int i; for (i = 0; i < bytesOrig.length; i++) { @@ -821,12 +832,16 @@ public byte[] getNullTerminatedProperty(X11.Atom xa_prop_type, String xa_prop_na * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as byte array where every '\0' character is replaced by '.' + * @return property value as byte array where every '\0' character is replaced by '.'. null if the property was not found * @throws X11Exception thrown if X11 window errors occurred */ public byte[] getNullReplacedStringProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { byte[] bytes = getProperty(xa_prop_type, xa_prop_name); + if( bytes == null ){ + return null; + } + // search for '\0' int i; for (i = 0; i < bytes.length; i++) { @@ -891,11 +906,15 @@ public String[] getStringListProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_na * * @param xa_prop_type property type * @param xa_prop_name property name - * @return property value as string list + * @return property value as string list, or null if the property value does not exist * @throws X11Exception thrown if X11 window errors occurred */ public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11Exception { - return new String(getProperty(xa_prop_type, xa_prop_name)).split("\0"); + byte[] property = getProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property).split("\0"); } /** @@ -908,7 +927,11 @@ public String[] getStringListProperty(X11.Atom xa_prop_type, String xa_prop_name */ public String getUtf8Property(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X11Exception { try { - return new String(getNullReplacedStringProperty(xa_prop_type, xa_prop_name), "UTF8"); + byte[] property = getNullReplacedStringProperty(xa_prop_type, xa_prop_name); + if( property == null ){ + return null; + } + return new String(property, "UTF8"); } catch (UnsupportedEncodingException e) { throw new X11Exception(e); } @@ -973,22 +996,32 @@ public byte[] getProperty(X11.Atom xa_prop_type, X11.Atom xa_prop_name) throws X NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4); /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): - * - * long_length = Specifies the length in 32-bit multiples of the - * data to be retrieved. - */ + * + * long_length = Specifies the length in 32-bit multiples of the + * data to be retrieved. + */ if (x11.XGetWindowProperty(display.x11Display, x11Window, xa_prop_name, long_offset, long_length, false, - xa_prop_type, xa_ret_type_ref, ret_format_ref, - ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { + xa_prop_type, xa_ret_type_ref, ret_format_ref, + ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) { String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); throw new X11Exception("Cannot get " + prop_name + " property."); } X11.Atom xa_ret_type = xa_ret_type_ref.getValue(); Pointer ret_prop = ret_prop_ref.getValue(); + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } + + if( xa_ret_type == null ){ + //the specified property does not exist for the specified window + return null; + } if (xa_ret_type == null || xa_prop_type == null || - !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { + !xa_ret_type.toNative().equals(xa_prop_type.toNative())) { x11.XFree(ret_prop); String prop_name = x11.XGetAtomName(display.x11Display, xa_prop_name); throw new X11Exception("Invalid type of " + prop_name + " property"); @@ -1031,13 +1064,13 @@ public byte[] getProperty(X11.Atom xa_prop_type, String xa_prop_name) throws X11 public int clientMsg(String msg, int data0, int data1, int data2, int data3, int data4) throws X11Exception { return clientMsg( - msg, - new NativeLong(data0), - new NativeLong(data1), - new NativeLong(data2), - new NativeLong(data3), - new NativeLong(data4) - ); + msg, + new NativeLong(data0), + new NativeLong(data1), + new NativeLong(data2), + new NativeLong(data3), + new NativeLong(data4) + ); } public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong data2, NativeLong data3, NativeLong data4) throws X11Exception { @@ -1068,6 +1101,30 @@ public int clientMsg(String msg, NativeLong data0, NativeLong data1, NativeLong } } + public Window[] getSubwindows() throws X11Exception { + WindowByReference root = new WindowByReference(); + WindowByReference parent = new WindowByReference(); + PointerByReference children = new PointerByReference(); + IntByReference childCount = new IntByReference(); + + if (x11.XQueryTree(display.x11Display, x11Window, root, parent, children, childCount) == 0){ + throw new X11Exception("Can't query subwindows"); + } + + if( childCount.getValue() == 0 ){ + return null; + } + + Window[] retVal = new Window[ childCount.getValue() ]; + //Depending on if we're running on 64-bit or 32-bit systems, + //the long size may be different; we need to make sure that + //we get the data properly no matter what + if( Native.LONG_SIZE == 4 ){ + int[] windows = children.getValue().getIntArray( 0, childCount.getValue() ); + for( int x = 0; x < retVal.length; x++ ){ + X11.Window win = new X11.Window( windows [ x ] ); + retVal[ x ] = new Window( display, win ); + } public String toString() { return x11Window.toString(); } @@ -1090,7 +1147,7 @@ public Geometry(int x, int y, int width, int height, int border_width, int depth * General exception which is thrown when an X11 window error occurred. */ public static class X11Exception extends Exception { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; public X11Exception() { } diff --git a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java index f20002f832..0dc4bd861e 100644 --- a/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java +++ b/contrib/x11/src/jnacontrib/x11/demos/XDesktopDemo.java @@ -13,10 +13,12 @@ package jnacontrib.x11.demos; import jnacontrib.x11.api.X; +import jnacontrib.x11.api.X.X11Exception; import javax.swing.*; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; + import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -28,7 +30,7 @@ * @author Stefan Endrullis */ public class XDesktopDemo extends JFrame { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; public static void main(String[] args) throws X.X11Exception { new XDesktopDemo(); } @@ -43,7 +45,8 @@ public static void main(String[] args) throws X.X11Exception { private JButton closeWindowButton; private JButton goToWindowButton; private JButton showDesktop; - + private JButton showSubwindows; + public XDesktopDemo() throws X.X11Exception { super("XDesktopDemo"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -143,6 +146,176 @@ public void actionPerformed(ActionEvent event) { } } }); + showSubwindows.addActionListener(new ActionListener() { + + private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ + X.Window[] subWindows = win.getSubwindows(); + String title = win.getTitle(); + if( title != null ){ + area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); + }else{ + area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); + } + area.append( System.getProperty( "line.separator" ) ); + + if( subWindows == null ){ + return; + } + for( int x = 0; x < subWindows.length; x++ ){ + addWindowsToArea( area, depth + 4, subWindows[ x ] ); + } + } + + @Override + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + + try{ + final JDialog jd = new JDialog(); + + refreshDesktopsAndWindows(); + + pack(); + addListeners(); + setVisible(true); + + printWmInfo(); + } + + private void printWmInfo() throws X.X11Exception { + X.Window wm = display.getWindowManagerInfo(); + System.out.println("wm.getTitle() = " + wm.getTitle()); + System.out.println("wm.getWindowClass() = " + wm.getWindowClass()); + System.out.println("wm.getPID() = " + wm.getPID()); + } + + private void addListeners() { + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + refreshDesktopsAndWindows(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + goToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + int desktopNr = desktopList.getSelectedIndex(); + if (desktopNr >= 0) { + try { + display.switchDesktop(desktopNr); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + } + }); + goToWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showDesktop.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + try { + display.showingDesktop(true); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + moveWindowAndGoToDesktopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.moveToDesktop(desktopList.getSelectedIndex()); + window.activate(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + closeWindowButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + try { + window.close(); + display.flush(); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); + showSubwindows.addActionListener(new ActionListener() { + + private void addWindowsToArea( JTextArea area, int depth, X.Window win ) throws X11Exception{ + X.Window[] subWindows = win.getSubwindows(); + String title = win.getTitle(); + if( title != null ){ + area.append( String.format( "%" + depth + "s0x%08X - %s", " ", win.getID(), title ) ); + }else{ + area.append( String.format( "%" + depth + "s0x%08X", " ", win.getID() ) ); + } + area.append( System.getProperty( "line.separator" ) ); + + if( subWindows == null ){ + return; + } + for( int x = 0; x < subWindows.length; x++ ){ + addWindowsToArea( area, depth + 4, subWindows[ x ] ); + } + } + + @Override + public void actionPerformed(ActionEvent event) { + X.Window window = getSelectedWindow(); + + try{ + final JDialog jd = new JDialog(); + JPanel dialogPanel = new JPanel( new BorderLayout() ); + jd.setSize( 320, 240 ); + jd.setTitle( "Subwindows" ); + jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); + JTextArea area = new JTextArea(); + addWindowsToArea( area, 1, window ); + dialogPanel.add( area, BorderLayout.CENTER ); + JButton closeButton = new JButton( "Close" ); + closeButton.addActionListener( new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + jd.dispose(); + } + }); + dialogPanel.add( closeButton, BorderLayout.SOUTH ); + jd.add( dialogPanel ); + jd.setVisible( true ); + } catch (X.X11Exception e) { + e.printStackTrace(); + } + } + }); } private X.Window getSelectedWindow() { @@ -169,8 +342,8 @@ private void refreshDesktopsAndWindows() throws X.X11Exception { int activeWindowNumber = -1; X.Window[] windows = display.getWindows(); String[] head = new String[]{ - "ID", "Desktop", "Title", - "X", "Y", "Width", "Height" + "ID", "Desktop", "Title", + "X", "Y", "Width", "Height" }; String[][] data = new String[windows.length][head.length]; for (int i = 0; i < windows.length; i++) { @@ -298,19 +471,22 @@ private void initGui() { gbc.gridy = 0; gbc.fill = GridBagConstraints.HORIZONTAL; panel3.add(showDesktop, gbc); + showSubwindows = new JButton(); + showSubwindows.setText("show subwindows"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + panel3.add(showSubwindows, gbc); - // more attributes - desktopList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - windowTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - - setContentPane(mainPanel); - } + setContentPane(mainPanel); + } /** * A simple ListModel managing a list of objects. */ public static class SimpleListModel extends AbstractListModel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; private ArrayList list; public SimpleListModel(ArrayList list) {