1 /* 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.X11; 27 28 import java.awt.AWTKeyStroke; 29 import sun.awt.SunToolkit; 30 import java.awt.Component; 31 import java.awt.Container; 32 import sun.util.logging.PlatformLogger; 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 PlatformLogger xembedLog = PlatformLogger.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(PlatformLogger.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(PlatformLogger.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(PlatformLogger.Level.FINE)) { 99 xembedLog.fine(msg.toString()); 100 } 101 if (msg.get_message_type() == XEmbed.getAtom()) { 102 if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { 103 xembedLog.fine("Embedded message: " + msgidToString((int)msg.get_data(1))); 104 } 105 switch ((int)msg.get_data(1)) { 106 case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start 107 active = true; 108 server = getEmbedder(embedded, msg); 109 // Check if window is reparented. If not - it was created with 110 // parent and so we should update it here. 111 if (!embedded.isReparented()) { 112 embedded.setReparented(true); 113 embedded.updateSizeHints(); 114 } 115 embedded.notifyStarted(); 116 break; 117 case XEMBED_WINDOW_ACTIVATE: 118 applicationActive = true; 119 break; 120 case XEMBED_WINDOW_DEACTIVATE: 121 if (applicationActive) { 122 applicationActive = false; 123 handleWindowFocusOut(); 124 } 125 break; 126 case XEMBED_FOCUS_IN: // We got focus! 127 // Check for direction 128 handleFocusIn((int)msg.get_data(2)); 129 break; 130 case XEMBED_FOCUS_OUT: 131 if (applicationActive) { 132 handleWindowFocusOut(); 133 } 134 break; 135 } 136 } 137 } 138 void handleFocusIn(int detail) { 139 if (embedded.focusAllowedFor()) { 140 embedded.handleWindowFocusIn(0); 141 } 142 switch(detail) { 143 case XEMBED_FOCUS_CURRENT: 144 // Do nothing - just restore to the current value 145 break; 146 case XEMBED_FOCUS_FIRST: 147 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { 148 public void run() { 149 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getFirstComponent((Container)embedded.target); 150 if (comp != null) { 151 comp.requestFocusInWindow(); 152 } 153 }}); 154 break; 155 case XEMBED_FOCUS_LAST: 156 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { 157 public void run() { 158 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getLastComponent((Container)embedded.target); 159 if (comp != null) { 160 comp.requestFocusInWindow(); 161 } 162 }}); 163 break; 164 } 165 } 166 167 public void dispatchEvent(XEvent xev) { 168 switch(xev.get_type()) { 169 case XConstants.ClientMessage: 170 handleClientMessage(xev); 171 break; 172 case XConstants.ReparentNotify: 173 handleReparentNotify(xev); 174 break; 175 } 176 } 177 public void handleReparentNotify(XEvent xev) { 178 XReparentEvent re = xev.get_xreparent(); 179 long newParent = re.get_parent(); 180 if (active) { 181 // unregister accelerators, etc. for old parent 182 embedded.notifyStopped(); 183 // check if newParent is a root window 184 X11GraphicsConfig gc = (X11GraphicsConfig)embedded.getGraphicsConfiguration(); 185 X11GraphicsDevice gd = (X11GraphicsDevice)gc.getDevice(); 186 if ((newParent == XlibUtil.getRootWindow(gd.getScreen())) || 187 (newParent == XToolkit.getDefaultRootWindow())) 188 { 189 // reparenting to root means XEmbed termination 190 active = false; 191 } else { 192 // continue XEmbed with a new parent 193 server = newParent; 194 embedded.notifyStarted(); 195 } 196 } 197 } 198 boolean requestFocus() { 199 if (active && embedded.focusAllowedFor()) { 200 sendMessage(server, XEMBED_REQUEST_FOCUS); 201 return true; 202 } 203 return false; 204 } 205 void handleWindowFocusOut() { 206 // fix for 6269309: it is possible that we call this method twice 207 // (for example, when receiving XEMBED_WINDOW_DEACTIVATE and then 208 // XEMBED_FOCUS_OUT client messages), so we first need to check if 209 // embedded is an active window before sending WINDOW_LOST_FOCUS 210 // to shared code 211 if (XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == embedded.target) { 212 embedded.handleWindowFocusOut(null, 0); 213 } 214 } 215 216 long getEmbedder(XWindowPeer embedded, XClientMessageEvent info) { 217 // Embedder is the parent of embedded. 218 return XlibUtil.getParentWindow(embedded.getWindow()); 219 } 220 221 boolean isApplicationActive() { 222 return applicationActive; 223 } 224 225 boolean isActive() { 226 return active; 227 } 228 229 void traverseOutForward() { 230 if (active) { 231 sendMessage(server, XEMBED_FOCUS_NEXT); 232 } 233 } 234 235 void traverseOutBackward() { 236 if (active) { 237 sendMessage(server, XEMBED_FOCUS_PREV); 238 } 239 } 240 241 void registerAccelerator(AWTKeyStroke stroke, int id) { 242 if (active) { 243 long sym = getX11KeySym(stroke); 244 long mods = getX11Mods(stroke); 245 sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods); 246 } 247 } 248 void unregisterAccelerator(int id) { 249 if (active) { 250 sendMessage(server, XEMBED_UNREGISTER_ACCELERATOR, id, 0, 0); 251 } 252 } 253 254 long getX11KeySym(AWTKeyStroke stroke) { 255 XToolkit.awtLock(); 256 try { 257 return XWindow.getKeySymForAWTKeyCode(stroke.getKeyCode()); 258 } finally { 259 XToolkit.awtUnlock(); 260 } 261 } 262 263 long getX11Mods(AWTKeyStroke stroke) { 264 return XWindow.getXModifiers(stroke); 265 } 266 }