com.openfin.desktop.win32.EmbeddedWindow Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openfin-desktop-java-adapter Show documentation
Show all versions of openfin-desktop-java-adapter Show documentation
The Java API for OpenFin Runtime
package com.openfin.desktop.win32;
import com.openfin.desktop.*;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class EmbeddedWindow {
private final static Logger logger = LoggerFactory.getLogger(EmbeddedWindow.class.getName());
private long parentHwnd, childHwnd;
private WindowBounds embedBounds;
private Window window;
private int previousStyle; // Window style before embedding
private WinDef.HWND prevParent; // parent before embedding
private boolean embedded;
public EmbeddedWindow(Window window) {
this.window = window;
this.embedded = false;
this.childHwnd = -1;
}
public void embed(long parentHwndId, WindowBounds embedBounds, AckListener callback) {
this.parentHwnd = parentHwndId;
this.embedBounds = embedBounds;
this.window.getNativeId(new AckListener() {
public void onSuccess(Ack ack) {
if (EmbeddedWindow.this.childHwnd == -1) {
String data = ack.getJsonObject().getString("data");
EmbeddedWindow.this.childHwnd = Long.decode(data);
WinDef.HWND childHwnd = toHwnd(EmbeddedWindow.this.childHwnd);
EmbeddedWindow.this.previousStyle = User32.INSTANCE.GetWindowLong(childHwnd, User32.GWL_EXSTYLE);
}
embedInto(new AckListener() {
public void onSuccess(Ack ack) {
try {
JSONObject targetObject = new JSONObject();
targetObject.put("uuid", EmbeddedWindow.this.window.getUuid());
targetObject.put("name", EmbeddedWindow.this.window.getName());
targetObject.put("parentHwnd", Long.toHexString(EmbeddedWindow.this.parentHwnd));
EmbeddedWindow.this.window.getConnection().sendAction("window-embedded", targetObject);
EmbeddedWindow.this.window.show();
EmbeddedWindow.this.window.focus();
if (callback != null) {
callback.onSuccess(ack);
}
} catch (Exception ex) {
logger.error("Error registering embedded window", ex);
}
}
public void onError(Ack ack) {
if (callback != null) {
callback.onError(ack);
}
}
});
}
public void onError(Ack ack) {
if (callback != null) {
callback.onError(ack);
}
}
});
}
/**
* Embeds a window in a target hWin
*
* @param callback callback for each message
*/
private void embedInto(AckListener callback) {
try {
if (!this.embedded) {
WinDef.HWND childHwnd = toHwnd(this.childHwnd);
WinDef.HWND parentHwnd = toHwnd(this.parentHwnd);
User32.INSTANCE.ShowWindow(childHwnd, User32.SW_HIDE);
int style = this.previousStyle;
style = style & ~(User32.WS_POPUP | User32.WS_VISIBLE); // add WS_VISIBLE here to avoid flash when moving the window
style = style | User32.WS_CLIPCHILDREN;
logger.debug(String.format("set embedded style %x from %x ", style, this.previousStyle));
User32.INSTANCE.SetWindowLong(childHwnd, User32.GWL_EXSTYLE, style);
logger.debug(String.format("SetParent %s to parent %s", formatHwnd(childHwnd), formatHwnd(parentHwnd)));
this.prevParent = User32.INSTANCE.SetParent(childHwnd, parentHwnd);
logger.debug(String.format("Prev parent %s", formatHwnd(this.prevParent)));
logger.debug("MoveWindow " + " (" + embedBounds.getWidth() + "," + embedBounds.getHeight() + ")");
User32.INSTANCE.MoveWindow(childHwnd, embedBounds.getLeft(), embedBounds.getTop(), embedBounds.getWidth(), embedBounds.getHeight(), true);
installMessageHandlers();
this.embedded = true;
} else {
logger.debug(String.format("already embedded %x", this.childHwnd));
}
if (callback != null) {
JSONObject msg = new JSONObject();
msg.put("success", Boolean.TRUE);
msg.put("hWndPreviousParent", Pointer.nativeValue(prevParent.getPointer()));
DesktopUtils.successAck(callback, new Ack(msg, childHwnd));
}
} catch (Exception e) {
logger.error("Error embedding window", e);
if (callback != null) {
JSONObject msg = new JSONObject();
msg.put("success", Boolean.FALSE);
DesktopUtils.errorAck(callback, new Ack(msg, this.childHwnd));
}
}
}
private void unembed() {
try {
if (this.embedded) {
WinMessageHelper.unhookWndProc(toHwnd(this.parentHwnd));
// Reset the normal WndProc
logger.debug("unembed " + this.childHwnd);
WinDef.HWND childHwnd = toHwnd(this.childHwnd);
User32.INSTANCE.ShowWindow(childHwnd, User32.SW_HIDE); // hide during not embedded
logger.debug(String.format("SetParent %s to %s", formatHwnd(childHwnd), formatHwnd(this.prevParent)));
WinDef.HWND prevParent = User32.INSTANCE.SetParent(childHwnd, this.prevParent);
logger.debug(String.format("Prev parent %s", formatHwnd(prevParent)));
this.embedded = false;
} else {
logger.debug(String.format("already unembedded %x", this.childHwnd));
}
} catch (Exception e) {
logger.error("Error unembedding window", e);
}
}
public void embedComponentSizeChange(int left, int top, int width, int height) {
logger.debug("MoveWindow " + " (" + left + "," + top + "," + width + "," + height + ")");
Pointer p = Pointer.createConstant(this.childHwnd);
WinDef.HWND childHwnd = new WinDef.HWND(p);
User32.INSTANCE.MoveWindow(childHwnd, left, top, width, height, true);
}
private WinDef.HWND toHwnd(long hwnd) {
return new WinDef.HWND(Pointer.createConstant(hwnd));
}
private static String formatHwnd(WinDef.HWND hwnd) {
return String.format("%x", Pointer.nativeValue(hwnd.getPointer()));
}
private void installMessageHandlers() {
WindowProcCallback windowProcCallback = new WindowProcCallback() {
@Override
public boolean callback(WinDef.HWND hwnd, int msg, WinDef.WPARAM wp, Pointer lp) {
boolean handled = false;
try {
switch (msg) {
case WinMessageHelper.WM_DESTROY:
onWMDestroy(msg);
break;
}
} catch (Exception e) {
logger.error("Error processing callback", e);
}
return handled;
}
};
try {
logger.debug(String.format("hookWndProc %x", this.parentHwnd));
WinMessageHelper.hookWndProc(toHwnd(this.parentHwnd), windowProcCallback);
} catch (Throwable e) {
logger.error("Error initializing", e);
}
}
private void onWMDestroy(int msg) {
logger.debug("onWMDestroy");
cleanup();
}
private void cleanup() {
logger.debug("cleaning up");
try {
this.unembed();
} catch (Exception ex) {
logger.info("Error cleaning up", ex);
}
}
}