1 /* 2 * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package sun.awt.X11; 27 28 import java.awt.AWTKeyStroke; 29 import java.util.logging.*; 30 import sun.awt.SunToolkit; 31 import java.awt.Component; 32 import java.awt.Container; 33 34 import sun.awt.X11GraphicsConfig; 35 import sun.awt.X11GraphicsDevice; 36 37 /** 38 * Helper class implementing XEmbed protocol handling routines(client side) 39 * Window which wants to participate in a protocol should create an instance, 40 * call install and forward all XClientMessageEvents to it. 41 */ 42 public class XEmbedClientHelper extends XEmbedHelper implements XEventDispatcher { 43 private static final Logger xembedLog = Logger.getLogger("sun.awt.X11.xembed.XEmbedClientHelper"); 44 45 private XEmbeddedFramePeer embedded; // XEmbed client 46 private long server; // XEmbed server 47 48 private boolean active; 49 private boolean applicationActive; 50 51 XEmbedClientHelper() { 52 super(); 53 } 54 55 void setClient(XEmbeddedFramePeer client) { 56 if (xembedLog.isLoggable(Level.FINE)) { 57 xembedLog.fine("XEmbed client: " + client); 58 } 59 if (embedded != null) { 60 XToolkit.removeEventDispatcher(embedded.getWindow(), this); 61 active = false; 62 } 63 embedded = client; 64 if (embedded != null) { 65 XToolkit.addEventDispatcher(embedded.getWindow(), this); 66 } 67 } 68 69 void install() { 70 if (xembedLog.isLoggable(Level.FINE)) { 71 xembedLog.fine("Installing xembedder on " + embedded); 72 } 73 long[] info = new long[] { XEMBED_VERSION, XEMBED_MAPPED }; 74 long data = Native.card32ToData(info); 75 try { 76 XEmbedInfo.setAtomData(embedded.getWindow(), data, 2); 77 } finally { 78 unsafe.freeMemory(data); 79 } 80 // XEmbeddedFrame is initially created with a null parent.. 81 // Here it is reparented to the proper parent window. 82 long parentWindow = embedded.getParentWindowHandle(); 83 if (parentWindow != 0) { 84 XToolkit.awtLock(); 85 try { 86 XlibWrapper.XReparentWindow(XToolkit.getDisplay(), 87 embedded.getWindow(), 88 parentWindow, 89 0, 0); 90 } finally { 91 XToolkit.awtUnlock(); 92 } 93 } 94 } 95 96 void handleClientMessage(XEvent xev) { 97 XClientMessageEvent msg = xev.get_xclient(); 98 if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine(msg.toString()); 99 if (msg.get_message_type() == XEmbed.getAtom()) { 100 if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Embedded message: " + msgidToString((int)msg.get_data(1))); 101 switch ((int)msg.get_data(1)) { 102 case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start 103 active = true; 104 server = getEmbedder(embedded, msg); 105 // Check if window is reparented. If not - it was created with 106 // parent and so we should update it here. 107 if (!embedded.isParented()) { 108 embedded.setNativeParent(server); 109 embedded.updateSizeHints(); 110 } 111 embedded.notifyStarted(); 112 break; 113 case XEMBED_WINDOW_ACTIVATE: 114 applicationActive = true; 115 break; 116 case XEMBED_WINDOW_DEACTIVATE: 117 if (applicationActive) { 118 applicationActive = false; 119 handleWindowFocusOut(); 120 } 121 break; 122 case XEMBED_FOCUS_IN: // We got focus! 123 // Check for direction 124 handleFocusIn((int)msg.get_data(2)); 125 break; 126 case XEMBED_FOCUS_OUT: 127 if (applicationActive) { 128 handleWindowFocusOut(); 129 } 130 break; 131 } 132 } 133 } 134 void handleFocusIn(int detail) { 135 if (embedded.focusAllowedFor()) { 136 embedded.handleWindowFocusInSync(0); 137 } 138 switch(detail) { 139 case XEMBED_FOCUS_CURRENT: 140 // Do nothing - just restore to the current value 141 break; 142 case XEMBED_FOCUS_FIRST: 143 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { 144 public void run() { 145 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getFirstComponent((Container)embedded.target); 146 if (comp != null) { 147 comp.requestFocusInWindow(); 148 } 149 }}); 150 break; 151 case XEMBED_FOCUS_LAST: 152 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { 153 public void run() { 154 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getLastComponent((Container)embedded.target); 155 if (comp != null) { 156 comp.requestFocusInWindow(); 157 } 158 }}); 159 break; 160 } 161 } 162 163 public void dispatchEvent(XEvent xev) { 164 switch(xev.get_type()) { 165 case XConstants.ClientMessage: 166 handleClientMessage(xev); 167 break; 168 case XConstants.ReparentNotify: 169 handleReparentNotify(xev); 170 break; 171 } 172 } 173 public void handleReparentNotify(XEvent xev) { 174 XReparentEvent re = xev.get_xreparent(); 175 long newParent = re.get_parent(); 176 if (active) { 177 // unregister accelerators, etc. for old parent 178 embedded.notifyStopped(); 179 // check if newParent is a root window 180 X11GraphicsConfig gc = (X11GraphicsConfig)embedded.getGraphicsConfiguration(); 181 X11GraphicsDevice gd = (X11GraphicsDevice)gc.getDevice(); 182 if ((newParent == XlibUtil.getRootWindow(gd.getScreen())) || 183 (newParent == XToolkit.getDefaultRootWindow())) 184 { 185 // reparenting to root means XEmbed termination 186 active = false; 187 } else { 188 // continue XEmbed with a new parent 189 server = newParent; 190 embedded.notifyStarted(); 191 } 192 } 193 } 194 boolean requestFocus() { 195 if (active && embedded.focusAllowedFor()) { 196 sendMessage(server, XEMBED_REQUEST_FOCUS); 197 return true; 198 } 199 return false; 200 } 201 void handleWindowFocusOut() { 202 // fix for 6269309: it is possible that we call this method twice 203 // (for example, when receiving XEMBED_WINDOW_DEACTIVATE and then 204 // XEMBED_FOCUS_OUT client messages), so we first need to check if 205 // embedded is an active window before sending WINDOW_LOST_FOCUS 206 // to shared code 207 if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == embedded.target) { 208 embedded.handleWindowFocusOutSync(null, 0); 209 } 210 } 211 212 long getEmbedder(XWindowPeer embedded, XClientMessageEvent info) { 213 // Embedder is the parent of embedded. 214 return XlibUtil.getParentWindow(embedded.getWindow()); 215 } 216 217 boolean isApplicationActive() { 218 return applicationActive; 219 } 220 221 boolean isActive() { 222 return active; 223 } 224 225 void traverseOutForward() { 226 if (active) { 227 sendMessage(server, XEMBED_FOCUS_NEXT); 228 } 229 } 230 231 void traverseOutBackward() { 232 if (active) { 233 sendMessage(server, XEMBED_FOCUS_PREV); 234 } 235 } 236 237 void registerAccelerator(AWTKeyStroke stroke, int id) { 238 if (active) { 239 long sym = getX11KeySym(stroke); 240 long mods = getX11Mods(stroke); 241 sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods); 242 } 243 } 244 void unregisterAccelerator(int id) { 245 if (active) { 246 sendMessage(server, XEMBED_UNREGISTER_ACCELERATOR, id, 0, 0); 247 } 248 } 249 250 long getX11KeySym(AWTKeyStroke stroke) { 251 XToolkit.awtLock(); 252 try { 253 return XWindow.getKeySymForAWTKeyCode(stroke.getKeyCode()); 254 } finally { 255 XToolkit.awtUnlock(); 256 } 257 } 258 259 long getX11Mods(AWTKeyStroke stroke) { 260 return XWindow.getXModifiers(stroke); 261 } 262 }