All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.openfin.desktop.win32.EmbeddedWindow Maven / Gradle / Ivy

There is a newer version: 11.0.2
Show newest version
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);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy