jdk/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java
changeset 2 90ce3da70b43
child 120 98296a9fc072
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.awt.X11;
+
+import java.awt.AWTKeyStroke;
+import java.util.logging.*;
+import sun.awt.SunToolkit;
+import java.awt.Component;
+import java.awt.Container;
+
+/**
+ * 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 Logger xembedLog = Logger.getLogger("sun.awt.X11.xembed.XEmbedClientHelper");
+
+    private XEmbeddedFramePeer embedded;
+    private boolean active;
+    private long server;
+    private boolean applicationActive;
+
+    XEmbedClientHelper() {
+        super();
+    }
+
+    void install(XEmbeddedFramePeer embedded) {
+        this.embedded = embedded;
+
+        if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Installing xembedder on " + embedded);
+        XToolkit.addEventDispatcher(embedded.getWindow(), this);
+        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();
+            }
+        }
+        notifyReady();
+    }
+
+    void handleClientMessage(XEvent xev) {
+        XClientMessageEvent msg = xev.get_xclient();
+        if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine(msg.toString());
+        if (msg.get_message_type() == XEmbed.getAtom()) {
+            if (xembedLog.isLoggable(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
+                  // NOTE: May be called two times because we send _SUN_XEMBED_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.handleWindowFocusInSync(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 XlibWrapper.ClientMessage:
+              handleClientMessage(xev);
+              break;
+          case XlibWrapper.ReparentNotify:
+              handleReparentNotify(xev);
+              break;
+        }
+    }
+    public void handleReparentNotify(XEvent xev) {
+        XReparentEvent re = xev.get_xreparent();
+        server = re.get_parent();
+    }
+    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.getCurrentNativeFocusedWindow() == embedded.target) {
+            embedded.handleWindowFocusOutSync(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) {
+        long sym = getX11KeySym(stroke);
+        long mods = getX11Mods(stroke);
+        sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods);
+    }
+    void unregisterAccelerator(int id) {
+        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);
+    }
+
+    void notifyReady() {
+        long wnd = server;
+        if (wnd == 0) {
+            // Server is still 0, get the parent
+            wnd = embedded.getParentWindowHandle();
+        }
+        sendMessage(wnd, _SUN_XEMBED_START);
+    }
+}