From 80d4c1355faa7a361e96940178b748b467b81a0e Mon Sep 17 00:00:00 2001 From: rm5248 Date: Thu, 24 Jul 2014 09:19:25 -0400 Subject: [PATCH] Added jnacontrib.x11.api.X.Window.getSubwindows and fixed jnacontrib.x11.api.X.Window.getXXXProperty, returns null if the window property is not found. --- CHANGES.md | 34 +-- contrib/x11/src/jnacontrib/x11/api/X.java | 144 +++++++++---- .../jnacontrib/x11/demos/XDesktopDemo.java | 198 +++++++++++++++++- 3 files changed, 308 insertions(+), 68 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0cd59ccf9b..0b4b1cf453 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,17 +11,19 @@ Features * [#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): Added `jnacontrib.x11.api.X.Window.getSubwindows` - [@rm5248](https://github.com/rm5248). +* Improved `contrib/msoffice` sample - [@wolftobias](https://github.com/wolftobias). 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): Fix `jnacontrib.x11.api.X.Window.getXXXProperty`, returns `null` if the window property is not found - [@rm5248](https://github.com/rm5248). +* Fixed `com.sun.jna.platform.win32.Variant` and `TlbImp` - [@wolftobias](https://github.com/wolftobias). Release 4.1 =========== @@ -182,7 +184,7 @@ Bug Fixes * 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 ============= @@ -218,7 +220,7 @@ threads. * 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). +* 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`. @@ -367,7 +369,7 @@ 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). +* 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. @@ -387,7 +389,7 @@ 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. +* 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). @@ -417,7 +419,7 @@ 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. +* 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. @@ -435,7 +437,7 @@ 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 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) @@ -449,7 +451,7 @@ Features Bug Fixes --------- -* Run tests with libjsig.so, if available, which fixes some crashes when running tests on 64-bit platforms. +* 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). @@ -510,7 +512,7 @@ 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). +* 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. @@ -567,7 +569,7 @@ 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). +* Allow Structure.read to overwrite final fields (may not work on some 1.4 VMs). Bug Fixes --------- @@ -581,7 +583,7 @@ Bug Fixes * 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. +* Fix NPE calling Structure.read/write with uninitialized NativeMapped fields. Release 3.0.2 ============= @@ -628,7 +630,7 @@ 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 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 @@ -643,7 +645,7 @@ Features * 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 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 @@ -676,7 +678,7 @@ Features * 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 +* Provide customization of native string encoding with jna.encoding system property Bug Fixes --------- @@ -702,7 +704,7 @@ Features * 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[] +* Support char*[] arguments as Java String[] * Structure supports Callback members (wmeissner) * getByteBuffer from Pointer/Memory (wmeissner) * Allow GC of native libraries diff --git a/contrib/x11/src/jnacontrib/x11/api/X.java b/contrib/x11/src/jnacontrib/x11/api/X.java index e8a76b95e9..bce75192fa 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,37 @@ 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 ){ + //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 +1069,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 +1106,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 +1152,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) {