/*
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.awt.X11;

import java.awt.AWTKeyStroke;
import sun.awt.SunToolkit;
import java.awt.Component;
import java.awt.Container;
import sun.util.logging.PlatformLogger;

import sun.awt.X11GraphicsConfig;
import sun.awt.X11GraphicsDevice;

Helper class implementing XEmbed protocol handling routines(client side) Window which wants to participate in a protocol should create an instance, call install and forward all XClientMessageEvents to it.
/** * Helper class implementing XEmbed protocol handling routines(client side) * Window which wants to participate in a protocol should create an instance, * call install and forward all XClientMessageEvents to it. */
public class XEmbedClientHelper extends XEmbedHelper implements XEventDispatcher { private static final PlatformLogger xembedLog = PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbedClientHelper"); private XEmbeddedFramePeer embedded; // XEmbed client private long server; // XEmbed server private boolean active; private boolean applicationActive; XEmbedClientHelper() { super(); } void setClient(XEmbeddedFramePeer client) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("XEmbed client: " + client); } if (embedded != null) { XToolkit.removeEventDispatcher(embedded.getWindow(), this); active = false; } embedded = client; if (embedded != null) { XToolkit.addEventDispatcher(embedded.getWindow(), this); } } void install() { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Installing xembedder on " + embedded); } long[] info = new long[] { XEMBED_VERSION, XEMBED_MAPPED }; long data = Native.card32ToData(info); try { XEmbedInfo.setAtomData(embedded.getWindow(), data, 2); } finally { unsafe.freeMemory(data); } // XEmbeddedFrame is initially created with a null parent.. // Here it is reparented to the proper parent window. long parentWindow = embedded.getParentWindowHandle(); if (parentWindow != 0) { XToolkit.awtLock(); try { XlibWrapper.XReparentWindow(XToolkit.getDisplay(), embedded.getWindow(), parentWindow, 0, 0); } finally { XToolkit.awtUnlock(); } } } void handleClientMessage(XEvent xev) { XClientMessageEvent msg = xev.get_xclient(); if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine(msg.toString()); } if (msg.get_message_type() == XEmbed.getAtom()) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Embedded message: " + msgidToString((int)msg.get_data(1))); } switch ((int)msg.get_data(1)) { case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start active = true; server = getEmbedder(embedded, msg); // Check if window is reparented. If not - it was created with // parent and so we should update it here. if (!embedded.isReparented()) { embedded.setReparented(true); embedded.updateSizeHints(); } embedded.notifyStarted(); break; case XEMBED_WINDOW_ACTIVATE: applicationActive = true; break; case XEMBED_WINDOW_DEACTIVATE: if (applicationActive) { applicationActive = false; handleWindowFocusOut(); } break; case XEMBED_FOCUS_IN: // We got focus! // Check for direction handleFocusIn((int)msg.get_data(2)); break; case XEMBED_FOCUS_OUT: if (applicationActive) { handleWindowFocusOut(); } break; } } } void handleFocusIn(int detail) { if (embedded.focusAllowedFor()) { embedded.handleWindowFocusIn(0); } switch(detail) { case XEMBED_FOCUS_CURRENT: // Do nothing - just restore to the current value break; case XEMBED_FOCUS_FIRST: SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { public void run() { Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getFirstComponent((Container)embedded.target); if (comp != null) { comp.requestFocusInWindow(); } }}); break; case XEMBED_FOCUS_LAST: SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { public void run() { Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getLastComponent((Container)embedded.target); if (comp != null) { comp.requestFocusInWindow(); } }}); break; } } public void dispatchEvent(XEvent xev) { switch(xev.get_type()) { case XConstants.ClientMessage: handleClientMessage(xev); break; case XConstants.ReparentNotify: handleReparentNotify(xev); break; } } public void handleReparentNotify(XEvent xev) { XReparentEvent re = xev.get_xreparent(); long newParent = re.get_parent(); if (active) { // unregister accelerators, etc. for old parent embedded.notifyStopped(); // check if newParent is a root window X11GraphicsConfig gc = (X11GraphicsConfig)embedded.getGraphicsConfiguration(); X11GraphicsDevice gd = (X11GraphicsDevice)gc.getDevice(); if ((newParent == XlibUtil.getRootWindow(gd.getScreen())) || (newParent == XToolkit.getDefaultRootWindow())) { // reparenting to root means XEmbed termination active = false; } else { // continue XEmbed with a new parent server = newParent; embedded.notifyStarted(); } } } boolean requestFocus() { if (active && embedded.focusAllowedFor()) { sendMessage(server, XEMBED_REQUEST_FOCUS); return true; } return false; } void handleWindowFocusOut() { // fix for 6269309: it is possible that we call this method twice // (for example, when receiving XEMBED_WINDOW_DEACTIVATE and then // XEMBED_FOCUS_OUT client messages), so we first need to check if // embedded is an active window before sending WINDOW_LOST_FOCUS // to shared code if (XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == embedded.target) { embedded.handleWindowFocusOut(null, 0); } } long getEmbedder(XWindowPeer embedded, XClientMessageEvent info) { // Embedder is the parent of embedded. return XlibUtil.getParentWindow(embedded.getWindow()); } boolean isApplicationActive() { return applicationActive; } boolean isActive() { return active; } void traverseOutForward() { if (active) { sendMessage(server, XEMBED_FOCUS_NEXT); } } void traverseOutBackward() { if (active) { sendMessage(server, XEMBED_FOCUS_PREV); } } void registerAccelerator(AWTKeyStroke stroke, int id) { if (active) { long sym = getX11KeySym(stroke); long mods = getX11Mods(stroke); sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods); } } void unregisterAccelerator(int id) { if (active) { sendMessage(server, XEMBED_UNREGISTER_ACCELERATOR, id, 0, 0); } } long getX11KeySym(AWTKeyStroke stroke) { XToolkit.awtLock(); try { return XWindow.getKeySymForAWTKeyCode(stroke.getKeyCode()); } finally { XToolkit.awtUnlock(); } } long getX11Mods(AWTKeyStroke stroke) { return XWindow.getXModifiers(stroke); } }