1 /* 2 * Copyright (c) 2003, 2007, 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 java.util.logging.*; 30 import sun.awt.SunToolkit; 31 import java.awt.Component; 32 import java.awt.Container; 33 34 /** 35 * Helper class implementing XEmbed protocol handling routines(client side) 36 * Window which wants to participate in a protocol should create an instance, 37 * call install and forward all XClientMessageEvents to it. 38 */ 39 public class XEmbedClientHelper extends XEmbedHelper implements XEventDispatcher { 40 private static final Logger xembedLog = Logger.getLogger("sun.awt.X11.xembed.XEmbedClientHelper"); 41 42 private XEmbeddedFramePeer embedded; 43 private boolean active; 44 private long server; 45 private boolean applicationActive; 46 47 XEmbedClientHelper() { 48 super(); 49 } 50 51 void install(XEmbeddedFramePeer embedded) { 52 this.embedded = embedded; 53 54 if (xembedLog.isLoggable(Level.FINE)) { 55 xembedLog.fine("Installing xembedder on " + embedded); 56 } 57 XToolkit.addEventDispatcher(embedded.getWindow(), this); 58 long[] info = new long[] { XEMBED_VERSION, XEMBED_MAPPED }; 59 long data = Native.card32ToData(info); 60 try { 61 XEmbedInfo.setAtomData(embedded.getWindow(), data, 2); 62 } finally { 63 unsafe.freeMemory(data); 64 } 65 // XEmbeddedFrame is initially created with a null parent.. 66 // Here it is reparented to the proper parent window. 67 long parentWindow = embedded.getParentWindowHandle(); 68 if (parentWindow != 0) { 69 XToolkit.awtLock(); 70 try { 71 XlibWrapper.XReparentWindow(XToolkit.getDisplay(), 72 embedded.getWindow(), 73 parentWindow, 74 0, 0); 75 } finally { 76 XToolkit.awtUnlock(); 77 } 78 } 79 notifyReady(); 80 } 81 82 void handleClientMessage(XEvent xev) { 83 XClientMessageEvent msg = xev.get_xclient(); 84 if (xembedLog.isLoggable(Level.FINE)) { 85 xembedLog.fine(msg.toString()); 86 } 87 if (msg.get_message_type() == XEmbed.getAtom()) { 88 if (xembedLog.isLoggable(Level.FINE)) { 89 xembedLog.fine("Embedded message: " + msgidToString((int)msg.get_data(1))); 90 } 91 switch ((int)msg.get_data(1)) { 92 case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start 93 // NOTE: May be called two times because we send _SUN_XEMBED_START 94 active = true; 95 server = getEmbedder(embedded, msg); 96 // Check if window is reparented. If not - it was created with 97 // parent and so we should update it here. 98 if (!embedded.isReparented()) { 99 embedded.setReparented(true); 100 embedded.updateSizeHints(); 101 } 102 embedded.notifyStarted(); 103 break; 104 case XEMBED_WINDOW_ACTIVATE: 105 applicationActive = true; 106 break; 107 case XEMBED_WINDOW_DEACTIVATE: 108 if (applicationActive) { 109 applicationActive = false; 110 handleWindowFocusOut(); 111 } 112 break; 113 case XEMBED_FOCUS_IN: // We got focus! 114 // Check for direction 115 handleFocusIn((int)msg.get_data(2)); 116 break; 117 case XEMBED_FOCUS_OUT: 118 if (applicationActive) { 119 handleWindowFocusOut(); 120 } 121 break; 122 } 123 } 124 } 125 void handleFocusIn(int detail) { 126 if (embedded.focusAllowedFor()) { 127 embedded.handleWindowFocusInSync(0); 128 } 129 switch(detail) { 130 case XEMBED_FOCUS_CURRENT: 131 // Do nothing - just restore to the current value 132 break; 133 case XEMBED_FOCUS_FIRST: 134 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { 135 public void run() { 136 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getFirstComponent((Container)embedded.target); 137 if (comp != null) { 138 comp.requestFocusInWindow(); 139 } 140 }}); 141 break; 142 case XEMBED_FOCUS_LAST: 143 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() { 144 public void run() { 145 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getLastComponent((Container)embedded.target); 146 if (comp != null) { 147 comp.requestFocusInWindow(); 148 } 149 }}); 150 break; 151 } 152 } 153 154 public void dispatchEvent(XEvent xev) { 155 switch(xev.get_type()) { 156 case XlibWrapper.ClientMessage: 157 handleClientMessage(xev); 158 break; 159 case XlibWrapper.ReparentNotify: 160 handleReparentNotify(xev); 161 break; 162 } 163 } 164 public void handleReparentNotify(XEvent xev) { 165 XReparentEvent re = xev.get_xreparent(); 166 server = re.get_parent(); 167 } 168 boolean requestFocus() { 169 if (active && embedded.focusAllowedFor()) { 170 sendMessage(server, XEMBED_REQUEST_FOCUS); 171 return true; 172 } 173 return false; 174 } 175 void handleWindowFocusOut() { 176 // fix for 6269309: it is possible that we call this method twice 177 // (for example, when receiving XEMBED_WINDOW_DEACTIVATE and then 178 // XEMBED_FOCUS_OUT client messages), so we first need to check if 179 // embedded is an active window before sending WINDOW_LOST_FOCUS 180 // to shared code 181 if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == embedded.target) { 182 embedded.handleWindowFocusOutSync(null, 0); 183 } 184 } 185 186 long getEmbedder(XWindowPeer embedded, XClientMessageEvent info) { 187 // Embedder is the parent of embedded. 188 return XlibUtil.getParentWindow(embedded.getWindow()); 189 } 190 191 boolean isApplicationActive() { 192 return applicationActive; 193 } 194 195 boolean isActive() { 196 return active; 197 } 198 199 void traverseOutForward() { 200 if (active) { 201 sendMessage(server, XEMBED_FOCUS_NEXT); 202 } 203 } 204 205 void traverseOutBackward() { 206 if (active) { 207 sendMessage(server, XEMBED_FOCUS_PREV); 208 } 209 } 210 211 void registerAccelerator(AWTKeyStroke stroke, int id) { 212 long sym = getX11KeySym(stroke); 213 long mods = getX11Mods(stroke); 214 sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods); 215 } 216 void unregisterAccelerator(int id) { 217 sendMessage(server, XEMBED_UNREGISTER_ACCELERATOR, id, 0, 0); 218 } 219 220 long getX11KeySym(AWTKeyStroke stroke) { 221 XToolkit.awtLock(); 222 try { 223 return XWindow.getKeySymForAWTKeyCode(stroke.getKeyCode()); 224 } finally { 225 XToolkit.awtUnlock(); 226 } 227 } 228 229 long getX11Mods(AWTKeyStroke stroke) { 230 return XWindow.getXModifiers(stroke); 231 } 232 233 void notifyReady() { 234 long wnd = server; 235 if (wnd == 0) { 236 // Server is still 0, get the parent 237 wnd = embedded.getParentWindowHandle(); 238 } 239 sendMessage(wnd, _SUN_XEMBED_START); 240 } 241 }