Window ID from Java SWT - java

I would like to find the window ID of my SWT program.
I start up my SWT shell in the standard way. How do I then find the ID of the window that's been created? The program is executing on Fedora 10 using the Compiz-Fusion window manager (if that makes a difference).
Code to help explain what I mean:
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell();
// find window ID here??
shell.open();
while (!shell.isDisposed()) {
if(!display.readAndDispatch()) {
display.sleep();
}
}
}
Update 6 Mar 2009
After looking at and trying out a whole range of things (thanks to VonC for the suggestions below), I came across something that's worked so far. It's supremely dodgy but at least allows me to get on with some other work for the moment.
The ID returned from Control.embeddedHandle is close to the window ID. It's different by a predictable offset. So my code is:
public static void main(String[] args) {
...
Shell shell = new shell(display, SWT.NONE);
Composite e = new Composite(shell, SWT.EMBEDDED);
long windowID = e.embeddedHandle - WINDOW_ID_MAGIC_NUMBER;
e.dispose();
....
WINDOW_ID_MAGIC_NUMBER is 5+(number of widgets added to shell before the embedded composite).
It seems reliable on my system so far. I have yet to see if it falls over in a different environment.

If you create a Composite with the style SWT.EMBEDDED style, then under SWT/GTK+ Composite.embeddedHandle will be an X window ID you can use for parenting an XEMBED child.
Composite embed = new Composite(shell, SWT.EMBEDDED);
System.out.println ("X window ID: " + embed.embeddedHandle);
int hwndChild = OS.GetWindow ( c.handle, OS.GW_CHILD);
This supports embedding using the XEMBED protocol.
This is similar to the JNI code used to get the window ID from its handle
GtkWidget *widget = (GtkWidget *) handle;
GdkWindow *window = widget->window;
xwinid = GDK_WINDOW_XWINDOW(window);
Example of code here.
Example of class using OS:
org.eclipse.swt.widgets.Tree, org.eclipse.swt.widgets.CoolItem,
OS I can find is indeed org.eclipse.swt.internal.win32.OS, not gtk, and it is not a perfect solution because you would access an internal package, but that can give you an idea where to look.
In your case, org.eclipse.swt.internal.gtk.OS is the right class, and you should look in Tree or CoolItem sources how they are using the GetWindow function.
Some other function need to be called in GTK, like may be gtk_container_get_children(int container);
It is said in an answer to the message I was referring at the beginning
If you need the X window, there's no way to do this from the public SWT API (even going through internals), and furthermore even if there was a way I don't think you could guarantee it for all controls. I'm not sure if this works but the closest you could get might be to:
make Control.fixedHandle public
Use OS.GTK_WIDGET_WINDOW (control.fixedHandle) to get a GdkWindow
Use OS.gdk_x11_drawable_get_xid (gdkWindow) to translate that to an X window
I guess the other way might be to take Control.handle, and then call GTK_WIDGET_WINDOW() on it, or if that's null keep calling it on its parents until you find one with a GdkWindow, and then translate that to an X window.
The difficulty here is that SWT talks to GTK+, which talks to GDK, which then talks to X. So, there's three layers between you and the X window.

Not sure if this still matters to you, 7 years later :-), but this works for me:
private static long getWindowIdFromShell(Shell shell) {
long handle = shell.handle;
long topWidget = OS._gtk_widget_get_toplevel(handle);
long topWindow = OS._gtk_widget_get_window(topWidget);
long topXid = OS._gdk_x11_window_get_xid(topWindow);
return topXid;
}
In particular, the "get_toplevel" step is what jumps to the root widget/window, and so means you don't need the "minus magic window offset" hack (which I was initially stuck doing as well).

Related

Create java applications with MacBook Pro touchbar support?

as the tile describe, I would love to have the ability to add some cool touchbar buttons to my java application for MacBook Pro 2016 users.. I've not seen yet if there is a way to implement it in java yet.
Anyone got some knowledge on that?
There is a new Java library for interacting with the NSTouchBar API called JTouchBar.
For example using SWT
Shell shell = ...
JTouchBar jTouchBar = new JTouchBar();
jTouchBar.setCustomizationIdentifier("MySWTJavaTouchBar");
// flexible space
jTouchBar.addItem(new TouchBarItem(TouchBarItem.NSTouchBarItemIdentifierFlexibleSpace));
// button
TouchBarButton touchBarButtonImg = new TouchBarButton();
touchBarButtonImg.setTitle("Button 1");
touchBarButtonImg.setAction(new TouchBarViewAction() {
#Override
public void onCall( TouchBarView view ) {
System.out.println("Clicked Button_1.");
}
});
Image image = new Image();
img.setName(ImageName.NSImageNameTouchBarColorPickerFill);
touchBarButtonImg.setImage(image);
jTouchBar.addItem(new TouchBarItem("Button_1", touchBarButtonImg, true));
// label
TouchBarTextField touchBarTextField = new TouchBarTextField();
touchBarTextField.setStringValue("TextField 1");
jTouchBar.addItem(new TouchBarItem("TextField_1", touchBarTextField, true));
// enable touchbar
jTouchBar.enableForShell(shell);
You can find the library on Github:
https://github.com/Thizzer/JTouchBar
By the looks of it, apple doesn't provide support for adding items to the touch bar, never mind doing it in java.
While going through some documentation for the touch bar, it would appear that you will also need an instance of the NSTouchBarItem class. Java doesn't have that, nor provide a way to get that. I doubt that using native methods would work as well, seeing how the instance is app specific and is passed to the application through apple.
Accessing the bar is possible, but only natively.

Get rid of Windows typical styles?

I will start developing application for Windows. But I want to get rid of the cancel button and the typical Windows format like:
And I want it to look something like that, get rid of windows format and design my application in my own way.
So, will somebody suggest me, how to do that? I searched so much but cannot find any result.
If this app. is written using the Swing GUI toolkit, it is as simple as either using a JWindow, or calling Frame.setUndecorated(true).
Hard to tell what language your question is, here is answer for C++ for WinAPI:
Create your window like that:
HWND hWnd;
WNDCLASS WndCls;
// Create the application window
WndCls.style = CS_HREDRAW | CS_VREDRAW;
WndCls.lpfnWndProc = WndProcedure;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hIcon = NULL;
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = _T("WndClassName");
WndCls.hInstance = GetModuleHandle(NULL);
// Register the window class
RegisterClass(&WndCls);
hWnd = CreateWindow(_T("MyWnd"),
_T("WndClassName"),
WS_BORDER,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
::GetModuleHandle(0),
NULL);
and then:
::ShowWindow(hWnd, SW_SHOW);
SetWindowLong(hWnd, GWL_STYLE, 0);
you will have a white rectangle app which you will be able to paint however you like.
Also, you can spy on window styles using Spy++ from Visual Studio package
It's called the Titlebar. Hide it by removing the form border style.
this.FormBorderStyle= System.Windows.Forms.FormBorderStyle.None;

JOGL javaw.exe remains running after application is closed

I have a simple java application that uses JOGL. When I run it from eclipse, and then close the application window, javaw.exe remains running. Here is the the relevant code:
public class App {
private Display mDisplay;
private Shell mShell;
private GL4 mGl;
private int mProgramId;
private int mVsId;
private int mFsId;
// ...
public void start() {
if (!initialize()) {
return;
}
while (!mShell.isDisposed()) {
if (!mDisplay.readAndDispatch()) {
mDisplay.sleep();
}
}
destroy();
}
private void initialize() {
mDisplay = new Display();
mShell = new Shell(mDisplay);
// some SWT and opengl initialization code, which is irrelevant for this issue
// (at least I think so)
// getting GLProfile, GLContext, GL4 etc.
final String vsText = ResourceManager.getShaderText(vsPath);
final String fsText = ResourceManager.getShaderText(fsPath);
mVsId = mGl.glCreateShader(GL4.GL_VERTEX_SHADER);
mFsId = mGl.glCreateShader(GL4.GL_FRAGMENT_SHADER);
mGl.glShaderSource(mVsId, 1, new String[] { vsText }, null, 0);
mGl.glCompileShader(mVsId);
mGl.glShaderSource(mFsId, 1, new String[] { fsText }, null, 0);
mGl.glCompileShader(mFsId);
mProgramId = mGl.glCreateProgram();
mGl.glAttachShader(mProgramId, mFsId);
mGl.glAttachShader(mProgramId, mVsId);
// bind a constant attribute location for positions of vertices
mGl.glBindAttribLocation(mProgramId, 0, "in_Position");
// bind another constant attribute location, this time for color
mGl.glBindAttribLocation(mProgramId, 1, "in_Color");
mGl.glLinkProgram(mProgramId);
// here error code is 0x0 (no error)
int error = mGl.glGetError();
mShell.open();
return true;
}
private void destroy() {
// here error code is 0x502 (GL_INVALID_OPERATION)
int error = mGl.glGetError();
mGl.glDetachShader(mProgramId, mFsId);
mGl.glDetachShader(mProgramId, mVsId);
mGl.glDeleteShader(mFsId);
mGl.glDeleteShader(mVsId);
mGl.glDeleteProgram(mProgramId);
mDisplay.dispose();
}
}
I commented out all rendering code and most other opengl/JOGL related calls (besides getting GLProfile, GLContext, GL4 and everything listed in this sample) and this problem persists.
Generally, the application works fine, shaders compile and link without problem (I used validation which I didn't display in this sample) and it displays what it needs to. The only problem is that javaw.exe remains running after I close the application window (by pressing the x in the corner of the window).
This issue is removed only if I comment out mGl.glCompileShader(mVsId); and subsequent lines. If I leave this line, javaw.exe will remain running, so I guess the problem is related to shader initialization/destruction code.
Also, glGetError() returns 0 (no error) at the end of initialize() and 0x502 (GL_INVALID_OPERATION) at the beginning of destroy(). There is only the main loop in between and no opengl calls that I know of, since, for testing, I commented out all rendering code.
Any ideas?
Edit 2012-10-03:
I still don't know what the problem is, but since I updated my graphic card drivers, 'javaw.exe' terminates as it should after application is closed. I have AMD Radeon HD 6870. My current driver version is 8.982 from 2012-07-27, and I can't remember what the last version was, but I believe it was from january 2011 or so.
However, glGetError() still returns 0x502 at the beginning of destroy, so I guess there is still something wrong.
Assuming you use JOGL from jogamp.org, pls use either our SWT GLCanvas
or our NEWTCanvasSWT.
The latter is preferred due to custom GLCapabilities, pls check API doc.
This given plus you are doing everything SWT related on the SWT thread (read
linked unit tests), IMHO it should work - at least our unit tests.
Since you mentioned after an update (GPU/driver) your troubles ceased to exist,
it might have been a driver problem.
Now to your GL error. Trace GL errors can be simply done by setting the system property 'jogl.debug.DebugGL', i.e. on the commandline "-Djogl.debug.DebugGL".
This will install the debug pipeline for your GL object automatically and checks for GL error, which will throw an GLException if appear.
You can also trace via the property 'jogl.debug.TraceGL'.
I don't know if this is relevant or not, but may help someone I guess so I'm gonna share it here. Keep in mind I'm just a hobbyist getting started in Java SWT.
I made a simple application in Eclipse IDE using the Java SWT library. I made a ''Quit'' button in my main Window shell that when pushed calls this :
quitBtn.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
shell.getDisplay().dispose();
System.exit(0);
}
});
After exporting the .jar file to Desktop, I converted it to a .exe file with LaunchJ4 wrapper and check the "Allow only a single instance of the application" in the Single instance tab using the singleR3XPlayer mutex.
When I would close the .exe file with the "Quit" button, everything was fine and the javaw.exe would terminates. But when I closed the shell with the X button on the top-right window, javaw.exe would remains running. I figured that out when I tried to delete the .exe file (Windows "Used file, still open in Java(TM) Platform SE binary, close the file and retry" type of error pop-up) and as I couldn't open another instance of the file after closing it with the X button (because of the Single instance mutex). Also, multiple instances of javaw.exe would remains running if I would execute a few of the .jar file (even after closing them, but only with the X and not the "Quit" button).
I figured out closing the window with the X button would only dispose of the shell and not exit the program. But pressing the "Quit" button would because it called System.exit(0). So I did this :
// SWT Event Loop
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// To make sure javaw.exe terminates when Window is closed
if (shell.isDisposed()) {
System.exit(0);
}
Hence, after my SWT Event loop is done (shell.isDisposed() == true), I made sure System.exit(0) would be called. This way, javaw.exe is terminated either way.
I don't know how SWT works and I don't know if that's the proper way to do it but it ensures javaw.exe is terminated once the application closes.
Hope that helps.

Java search for on-screen text field

I am trying to create a program that automatically searches for a text field on the screen and types a word repetitively into that text field. Is there any class that can find a text field? Or is there any way in which a text field can be found? Because I know that the Robot class can type text, I just need to either get the cursor onto the text field and use the mousePress() and mouseRelease() methods.
Thanks
I can't directly give you a solution, but I messed around with some code and may be able to point you in the right direction.
Java, as you probably know, runs in the JVM. This allows it to execute in any operating environment. Each operating environment (windows, mac, etc) has its own system for handling edit boxes and setting focus to the right window and whatnot. The following example code is designed for use on windows only, which does not follow the spirit of the Java language. As Adriaan pointed out, there are other languages for this sort of thing, but it IS possible (to an extent) to accomplish with Java alone.
In windows, you must understand how all of the active windows are managed and that everything you see (including edit boxes) are considering a "window" by the Windows OS. I don't truly understand how things work under the hood, so I can't provide much more information than that. In a native language such as C++, there are a few functions provided by the Windows OS API that would be used to accomplish your goal. Namely, EnumWindows(), EnumChildWindows(), GetClassName(), and SetForegroundWindow(). You can find documentation on how to use these functions within a native language by searching the MSDN documentation library.
So with that said, you NEED to be able to call these functions from Java. Under normal circumstances, calling these native methods is not possible. However, there is a library available to help you out: the JNA library. JNA stands for Java Native Access and lets you work with the shiny new functions I mentioned earlier.
So, to accomplish your goal in a native language, normally one would begin with a call toEnumWindows() to return a list of all Parent windows that the OS is aware of. This list will contain window handles of parent windows - windows titled "MSN", "Eclipse", "Microsoft Office", etc. Each of these windows, as a Parent, has children. It is in this list of children that you will find the "control" that you are looking for: an Edit control. Now, many applications use different libraries and non-standard things for text boxes - i.e Pidgin, a messaging application I tested some relevant code with, has every control named "gdkWindowChild" which doesn't exactly tell us which control is actually an EditBox or otherwise a place that allows us to enter text. That's the main problem with your idea; you can't always tell exactly what control you wish to have focus of so that you may enter text. Regardless of that, we'll continue:
After finding the relevant Parent window with EnumWindows(), a call to EnumChildWindows() will give us all of the sub-windows and other "controls" (including potential edit-boxes) that belong to the Parent. EnumChildWindows() calls a callback function for each sub-window it finds, so it's pretty easy to "search" through the list of child windows - using GetClassName() to find the name of a control - to potentially find the HWND (window handle) of the control you want.
Once you have found the correct HWND of the edit box (that, of course, being the difficult part given the general scope of your question) a simple call to SetForegroundWindow(targetHWND) ought to bring the control to the front and set your cursor in a ready-to-type edit box.
Here is some working example code I've written to get you started. This code will iterate through all of the active windows using EnumWindows() and then call EnumChildWindows() on each parent, printing out all of the controls that it finds. Note that this code requires the JNA library to run.
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.examples.win32.W32API.HWND;
import com.sun.jna.examples.win32.W32API.LPARAM;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
public class IterateChildWindows {
public interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);
HWND FindWindow(String lpClassName, String lpWindowName);
int GetWindowRect(HWND handle, int[] rect);
int SendMessage(HWND hWnd, int msg, int wParam, byte[] lParam);
HWND FindWindowEx(HWND parent, HWND child, String className, String window);
boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg);
boolean EnumChildWindows(HWND parent, WNDENUMPROC callback, LPARAM info);
interface WNDENUMPROC extends StdCallCallback {
boolean callback(HWND hWnd, Pointer arg);
}
int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);
long GetWindowLong(HWND hWnd, int index);
boolean SetForegroundWindow(HWND in);
int GetClassNameA(HWND in, byte[] lpString, int size);
}
public static void main(String[] args) {
User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() {
public boolean callback(HWND hWnd, Pointer userData) { // this will be called for each parent window found by EnumWindows(). the hWnd parameter is the HWND of the window that was found.
byte[] textBuffer = new byte[512];
User32.INSTANCE.GetWindowTextA(hWnd, textBuffer, 512);
String wText = Native.toString(textBuffer);
System.out.println("Window found: " + wText);
// now call EnumChildWindows() giving the previously found parent window as the first parameter
User32.INSTANCE.EnumChildWindows(hWnd, new User32.WNDENUMPROC() {
public boolean callback(HWND hWnd, Pointer userData) { // this is called for each child window that EnumChildWindows() finds - just like before with EnumWindows().
byte[] textBuffer = new byte[512];
User32.INSTANCE.GetClassNameA(hWnd, textBuffer, 512);
System.out.println(" - Found sub window / control class: " + new String(textBuffer).trim());
return true;
}
}, null);
return true;
}
}, null);
}
}
Here is an excerpt of output provided by this code:
Window found: Pidgin
- Found sub window / control class: gdkWindowChild
- Found sub window / control class: gdkWindowChild
- Found sub window / control class: gdkWindowChild
- Found sub window / control class: gdkWindowChild
Window found: Malwarebytes Anti-Malware
- Found sub window / control class: Static
- Found sub window / control class: Static
- Found sub window / control class: Button
- Found sub window / control class: Button
- Found sub window / control class: Button
Sending messages directly to the HWND of controls via PostMessage() and SendMessage(), for example to the MalwareBytes Button class, will trigger a button press in the program itself, very similarl to how SetForegroundWindow() should bring an edit-box style control to the front giving you the ability to type. Fun stuff to play with :)
If you wish to visualize what I mean when I am saying "Parent" and "children" and "control", you may find this program helpful: Control Viewer. It can show you each control and highlight it within an applications window and much more - very useful tool.
Sorry if this post left the comfort-zone that java provides, but there's really no other way to accomplish your goal in such a general scope.
I hope I have at least shown you what is necessary to accomplish your goal and pointed you in the right direction. I am no god when it comes to native windows API's, so I may be wrong in some place, however the code does work. Good luck :)
my friend, the Robot class can simulate writing text.
private static void typeOut(String s,Robot bot)
{
try
{
char [] chars = s.toCharArray();
for (char c : chars)
{
bot.keyPress((int)c);
bot.keyRelease((int)c);
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
and you can use this method by
Robot bot=new Robot();
typeOut("WWW.GOOGLE.COM", bot);
and if in any way you want to read text or write text to a textfield on a browser i would advice you to use selenium.
For this type of problems AutoIt is easier and more versatile than Java.

keyReleases are simulating keyPresses in Linux (java Swing GUI)

I have a kiosk GUI application I'm working on and it requires me to block users from being able to Alt-Tab out of the fullscreen window. I posted a question about this a while back and a member helped me with some code, which worked perfectly under a Windows environment.
Here it is:
public class TabStopper implements Runnable {
private boolean isWorking = false;
private MenuFrame parent;
public TabStopper(MenuFrame parent) {
this.parent = parent;
new Thread(this, "TabStopper").start();
}
public void run() {
this.isWorking = true;
Robot robot;
try {
robot = new Robot();
while (isWorking) {
robot.keyRelease(KeyEvent.VK_ALT);
robot.keyRelease(KeyEvent.VK_TAB);
parent.requestFocus();
Thread.sleep(10);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
this.isWorking = false;
}
public boolean isWorking() {
return this.isWorking;
}
}
However, I need this to be able to work in Linux as well. I made an executable jar from the source and brought it into Linux. Everything worked except the Alt and Tab keys were being constantly pressed. The buttons on my GUI were constantly being cycled and I was able to open a terminal (I set a backdoor in the application during testing in case something like this happens) which wouldn't let me type anything because Tab lists all the files in the current directory.
Could anyone tell me if there would be a fix that would work in both Linux and Windows environments. However, if I had to choose, I would go for Linux.
EDIT: I can also confirm that the Alt key is being "pressed". What's with this weird behaviour?
Forget grabbing Alt+Tab with hacks like this. It is a bad hack and it is error-prone. There are also so many other hotkey combinations.
For linux you have two options:
Use a minimal window manager or no window manager at all. For example, with fluxbox you can remove all key bindings alltogether and you can also make your application maximise by default, etc. You can empty the desktop menus such that the user gains no control even when your application crashes. This is a clean solution that really solves your problem instead of some parts of it. There are many ways to fiddle with the system other than Alt+Tab.
Grab input controls completely. This is what games do. For example libSDL does it for you and there are java wrappers for the functionality as well. This should also work as expected, except you use a window manager that does not allow input control grabbing per default (I don't know of any).

Categories