/* * Copyright (c) 2003, 2015, 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.*; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetListener; import java.awt.event.*; import sun.awt.*; import sun.awt.AWTAccessor; import sun.util.logging.PlatformLogger; import java.util.*; import static sun.awt.X11.XEmbedHelper.*; import java.security.AccessController; import sun.security.action.GetBooleanAction; public class XEmbedCanvasPeer extends XCanvasPeer implements WindowFocusListener, KeyEventPostProcessor, ModalityListener, WindowIDProvider { private static final PlatformLogger xembedLog = PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbedCanvasPeer"); boolean applicationActive; // Whether the application is active(has focus) XEmbedServer xembed = new XEmbedServer(); // Helper object, contains XEmbed intrinsics Map accelerators = new HashMap(); // Maps accelerator ID into AWTKeyStroke Map accel_lookup = new HashMap(); // Maps AWTKeyStroke into accelerator ID Set grabbed_keys = new HashSet(); // A set of keys grabbed by client Object ACCEL_LOCK = accelerators; // Lock object for working with accelerators; Object GRAB_LOCK = grabbed_keys; // Lock object for working with keys grabbed by client XEmbedCanvasPeer() {} XEmbedCanvasPeer(XCreateWindowParams params) { super(params); } XEmbedCanvasPeer(Component target) { super(target); } protected void postInit(XCreateWindowParams params) { super.postInit(params); installActivateListener(); installAcceleratorListener(); installModalityListener(); // XEmbed canvas should be non-traversable. // FIXME: Probably should be removed and enforced setting of it by the users target.setFocusTraversalKeysEnabled(false); } protected void preInit(XCreateWindowParams params) { super.preInit(params); params.put(EVENT_MASK, XConstants.KeyPressMask | XConstants.KeyReleaseMask | XConstants.FocusChangeMask | XConstants.ButtonPressMask | XConstants.ButtonReleaseMask | XConstants.EnterWindowMask | XConstants.LeaveWindowMask | XConstants.PointerMotionMask | XConstants.ButtonMotionMask | XConstants.ExposureMask | XConstants.StructureNotifyMask | XConstants.SubstructureNotifyMask); } void installModalityListener() { ((SunToolkit)Toolkit.getDefaultToolkit()).addModalityListener(this); } void deinstallModalityListener() { ((SunToolkit)Toolkit.getDefaultToolkit()).removeModalityListener(this); } void installAcceleratorListener() { KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this); } void deinstallAcceleratorListener() { KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(this); } void installActivateListener() { // FIXME: should watch for hierarchy changes Window toplevel = getTopLevel(target); if (toplevel != null) { toplevel.addWindowFocusListener(this); applicationActive = toplevel.isFocused(); } } void deinstallActivateListener() { Window toplevel = getTopLevel(target); if (toplevel != null) { toplevel.removeWindowFocusListener(this); } } boolean isXEmbedActive() { return xembed.handle != 0; } boolean isApplicationActive() { return applicationActive; } void initDispatching() { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Init embedding for " + Long.toHexString(xembed.handle)); } XToolkit.awtLock(); try { XToolkit.addEventDispatcher(xembed.handle, xembed); XlibWrapper.XSelectInput(XToolkit.getDisplay(), xembed.handle, XConstants.StructureNotifyMask | XConstants.PropertyChangeMask); XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(), xembed.handle); } finally { XToolkit.awtUnlock(); } xembed.processXEmbedInfo(); notifyChildEmbedded(); } void endDispatching() { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("End dispatching for " + Long.toHexString(xembed.handle)); } XToolkit.awtLock(); try { XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(), xembed.handle); // We can't deselect input since someone else might be interested in it XToolkit.removeEventDispatcher(xembed.handle, xembed); } finally { XToolkit.awtUnlock(); } } void embedChild(long child) { if (xembed.handle != 0) { detachChild(); } xembed.handle = child; initDispatching(); } void childDestroyed() { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Child " + Long.toHexString(xembed.handle) + " has self-destroyed."); } endDispatching(); xembed.handle = 0; } public void handleEvent(AWTEvent e) { super.handleEvent(e); if (isXEmbedActive()) { switch (e.getID()) { case FocusEvent.FOCUS_GAINED: canvasFocusGained((FocusEvent)e); break; case FocusEvent.FOCUS_LOST: canvasFocusLost((FocusEvent)e); break; case KeyEvent.KEY_PRESSED: case KeyEvent.KEY_RELEASED: if (!((InputEvent)e).isConsumed()) { forwardKeyEvent((KeyEvent)e); } break; } } } public void dispatchEvent(XEvent ev) { super.dispatchEvent(ev); switch (ev.get_type()) { case XConstants.CreateNotify: XCreateWindowEvent cr = ev.get_xcreatewindow(); if (xembedLog.isLoggable(PlatformLogger.Level.FINEST)) { xembedLog.finest("Message on embedder: " + cr); } if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Create notify for parent " + Long.toHexString(cr.get_parent()) + ", window " + Long.toHexString(cr.get_window())); } embedChild(cr.get_window()); break; case XConstants.DestroyNotify: XDestroyWindowEvent dn = ev.get_xdestroywindow(); if (xembedLog.isLoggable(PlatformLogger.Level.FINEST)) { xembedLog.finest("Message on embedder: " + dn); } if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Destroy notify for parent: " + dn); } childDestroyed(); break; case XConstants.ReparentNotify: XReparentEvent rep = ev.get_xreparent(); if (xembedLog.isLoggable(PlatformLogger.Level.FINEST)) { xembedLog.finest("Message on embedder: " + rep); } if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Reparent notify for parent " + Long.toHexString(rep.get_parent()) + ", window " + Long.toHexString(rep.get_window()) + ", event " + Long.toHexString(rep.get_event())); } if (rep.get_parent() == getWindow()) { // Reparented into us - embed it embedChild(rep.get_window()); } else { // Reparented out of us - detach it childDestroyed(); } break; } } public Dimension getPreferredSize() { if (isXEmbedActive()) { XToolkit.awtLock(); try { long p_hints = XlibWrapper.XAllocSizeHints(); XSizeHints hints = new XSizeHints(p_hints); XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), xembed.handle, p_hints, XlibWrapper.larg1); Dimension res = new Dimension(hints.get_width(), hints.get_height()); XlibWrapper.XFree(p_hints); return res; } finally { XToolkit.awtUnlock(); } } else { return super.getPreferredSize(); } } public Dimension getMinimumSize() { if (isXEmbedActive()) { XToolkit.awtLock(); try { long p_hints = XlibWrapper.XAllocSizeHints(); XSizeHints hints = new XSizeHints(p_hints); XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), xembed.handle, p_hints, XlibWrapper.larg1); Dimension res = new Dimension(hints.get_min_width(), hints.get_min_height()); XlibWrapper.XFree(p_hints); return res; } finally { XToolkit.awtUnlock(); } } else { return super.getMinimumSize(); } } public void dispose() { if (isXEmbedActive()) { detachChild(); } deinstallActivateListener(); deinstallModalityListener(); deinstallAcceleratorListener(); // BUG: Focus traversal doesn't become enabled after the one round of embedding //target.setFocusTraversalKeysEnabled(true); super.dispose(); } // Focusable is true in order to enable focus traversal through this Canvas public boolean isFocusable() { return true; } Window getTopLevel(Component comp) { while (comp != null && !(comp instanceof Window)) { comp = comp.getParent(); } return (Window)comp; } Rectangle getClientBounds() { XToolkit.awtLock(); try { XWindowAttributes wattr = new XWindowAttributes(); try { XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), xembed.handle, wattr.pData); XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); if ((status == 0) || ((XErrorHandlerUtil.saved_error != null) && (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) { return null; } return new Rectangle(wattr.get_x(), wattr.get_y(), wattr.get_width(), wattr.get_height()); } finally { wattr.dispose(); } } finally { XToolkit.awtUnlock(); } } void childResized() { if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { Rectangle bounds = getClientBounds(); xembedLog.finer("Child resized: " + bounds); // It is not required to update embedder's size when client size changes // However, since there is no any means to get client size it seems to be the // only way to provide it. However, it contradicts with Java layout concept - // so it is disabled for now. // Rectangle my_bounds = getBounds(); // setBounds(my_bounds.x, my_bounds.y, bounds.width, bounds.height, SET_BOUNDS); } XToolkit.postEvent(XToolkit.targetToAppContext(target), new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED)); } void focusNext() { if (isXEmbedActive()) { xembedLog.fine("Requesting focus for the next component after embedder"); postEvent(new InvocationEvent(target, new Runnable() { public void run() { KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(target); } })); } else { xembedLog.fine("XEmbed is not active - denying focus next"); } } void focusPrev() { if (isXEmbedActive()) { xembedLog.fine("Requesting focus for the next component after embedder"); postEvent(new InvocationEvent(target, new Runnable() { public void run() { KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(target); } })); } else { xembedLog.fine("XEmbed is not active - denying focus prev"); } } void requestXEmbedFocus() { if (isXEmbedActive()) { xembedLog.fine("Requesting focus for client"); postEvent(new InvocationEvent(target, new Runnable() { public void run() { target.requestFocus(); } })); } else { xembedLog.fine("XEmbed is not active - denying request focus"); } } void notifyChildEmbedded() { xembed.sendMessage(xembed.handle, XEMBED_EMBEDDED_NOTIFY, getWindow(), Math.min(xembed.version, XEMBED_VERSION), 0); if (isApplicationActive()) { xembedLog.fine("Sending WINDOW_ACTIVATE during initialization"); xembed.sendMessage(xembed.handle, XEMBED_WINDOW_ACTIVATE); if (hasFocus()) { xembedLog.fine("Sending FOCUS_GAINED during initialization"); xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0); } } } void detachChild() { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Detaching child " + Long.toHexString(xembed.handle)); } /** * XEmbed specification: * "The embedder can unmap the client and reparent the client window to the root window. If the * client receives an ReparentNotify event, it should check the parent field of the XReparentEvent * structure. If this is the root window of the window's screen, then the protocol is finished and * there is no further interaction. If it is a window other than the root window, then the protocol * continues with the new parent acting as the embedder window." */ XToolkit.awtLock(); try { XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), xembed.handle); XlibWrapper.XReparentWindow(XToolkit.getDisplay(), xembed.handle, XToolkit.getDefaultRootWindow(), 0, 0); } finally { XToolkit.awtUnlock(); } endDispatching(); xembed.handle = 0; } public void windowGainedFocus(WindowEvent e) { applicationActive = true; if (isXEmbedActive()) { xembedLog.fine("Sending WINDOW_ACTIVATE"); xembed.sendMessage(xembed.handle, XEMBED_WINDOW_ACTIVATE); } } public void windowLostFocus(WindowEvent e) { applicationActive = false; if (isXEmbedActive()) { xembedLog.fine("Sending WINDOW_DEACTIVATE"); xembed.sendMessage(xembed.handle, XEMBED_WINDOW_DEACTIVATE); } } void canvasFocusGained(FocusEvent e) { if (isXEmbedActive()) { xembedLog.fine("Forwarding FOCUS_GAINED"); int flavor = XEMBED_FOCUS_CURRENT; if (e.getCause() == FocusEvent.Cause.TRAVERSAL_FORWARD) { flavor = XEMBED_FOCUS_FIRST; } else if (e.getCause() == FocusEvent.Cause.TRAVERSAL_BACKWARD) { flavor = XEMBED_FOCUS_LAST; } xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, flavor, 0, 0); } } void canvasFocusLost(FocusEvent e) { if (isXEmbedActive() && !e.isTemporary()) { xembedLog.fine("Forwarding FOCUS_LOST"); int num = 0; if (AccessController.doPrivileged(new GetBooleanAction("sun.awt.xembed.testing"))) { Component opp = e.getOppositeComponent(); try { num = Integer.parseInt(opp.getName()); } catch (NumberFormatException nfe) { } } xembed.sendMessage(xembed.handle, XEMBED_FOCUS_OUT, num, 0, 0); } } static byte[] getBData(KeyEvent e) { return AWTAccessor.getAWTEventAccessor().getBData(e); } void forwardKeyEvent(KeyEvent e) { xembedLog.fine("Try to forward key event"); byte[] bdata = getBData(e); long data = Native.toData(bdata); if (data == 0) { return; } try { XKeyEvent ke = new XKeyEvent(data); ke.set_window(xembed.handle); if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Forwarding native key event: " + ke); } XToolkit.awtLock(); try { XlibWrapper.XSendEvent(XToolkit.getDisplay(), xembed.handle, false, XConstants.NoEventMask, data); } finally { XToolkit.awtUnlock(); } } finally { XlibWrapper.unsafe.freeMemory(data); } } /** * Grab/ungrab key functionality is an unofficial API supported by * GTK. Unfortunately, it doesn't support accelerator API, so, * since this is the ONLY shortcut-processing API available, we * must support it. See XEmbed.NON_STANDARD_XEMBED_GTK_* * messages. The format of these messages is as follows: * - request from client: * data[1] = NON_STANDARD_XEMBED_GTK_GRAB_KEY or NON_STANDARD_XEMBED_GTK_UNGRAB_KEY * data[3] = X keysym * data[4] = X modifiers * * - response from server (in case the grabbed key has been pressed): * forwarded XKeyEvent that matches keysym/modifiers pair */ void grabKey(final long keysym, final long modifiers) { postEvent(new InvocationEvent(target, new Runnable() { public void run() { GrabbedKey grab = new GrabbedKey(keysym, modifiers); if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Grabbing key: " + grab); } synchronized(GRAB_LOCK) { grabbed_keys.add(grab); } } })); } void ungrabKey(final long keysym, final long modifiers) { postEvent(new InvocationEvent(target, new Runnable() { public void run() { GrabbedKey grab = new GrabbedKey(keysym, modifiers); if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("UnGrabbing key: " + grab); } synchronized(GRAB_LOCK) { grabbed_keys.remove(grab); } } })); } void registerAccelerator(final long accel_id, final long keysym, final long modifiers) { postEvent(new InvocationEvent(target, new Runnable() { public void run() { AWTKeyStroke stroke = xembed.getKeyStrokeForKeySym(keysym, modifiers); if (stroke != null) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Registering accelerator " + accel_id + " for " + stroke); } synchronized(ACCEL_LOCK) { accelerators.put(accel_id, stroke); accel_lookup.put(stroke, accel_id); } } propogateRegisterAccelerator(stroke); } })); } void unregisterAccelerator(final long accel_id) { postEvent(new InvocationEvent(target, new Runnable() { public void run() { AWTKeyStroke stroke = null; synchronized(ACCEL_LOCK) { stroke = accelerators.get(accel_id); if (stroke != null) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Unregistering accelerator: " + accel_id); } accelerators.remove(accel_id); accel_lookup.remove(stroke); // FIXME: How about several accelerators with the same stroke? } } propogateUnRegisterAccelerator(stroke); } })); } void propogateRegisterAccelerator(AWTKeyStroke stroke) { // Find the top-level and see if it is XEmbed client. If so, ask him to // register the accelerator XWindowPeer parent = getToplevelXWindow(); if (parent != null && parent instanceof XEmbeddedFramePeer) { XEmbeddedFramePeer embedded = (XEmbeddedFramePeer)parent; embedded.registerAccelerator(stroke); } } void propogateUnRegisterAccelerator(AWTKeyStroke stroke) { // Find the top-level and see if it is XEmbed client. If so, ask him to // register the accelerator XWindowPeer parent = getToplevelXWindow(); if (parent != null && parent instanceof XEmbeddedFramePeer) { XEmbeddedFramePeer embedded = (XEmbeddedFramePeer)parent; embedded.unregisterAccelerator(stroke); } } public boolean postProcessKeyEvent(KeyEvent e) { // Processing events only if we are in the focused window but // we are not focus owner since otherwise we will get // duplicate shortcut events in the client - one is from // activate_accelerator, another from forwarded event // FIXME: This is probably an incompatibility, protocol // doesn't say anything about disable accelerators when client // is focused. XWindowPeer parent = getToplevelXWindow(); if (parent == null || !((Window)parent.getTarget()).isFocused() || target.isFocusOwner()) { return false; } boolean result = false; if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Post-processing event " + e); } // Process ACCELERATORS AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e); long accel_id = 0; boolean exists = false; synchronized(ACCEL_LOCK) { exists = accel_lookup.containsKey(stroke); if (exists) { accel_id = accel_lookup.get(stroke).longValue(); } } if (exists) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Activating accelerator " + accel_id); } xembed.sendMessage(xembed.handle, XEMBED_ACTIVATE_ACCELERATOR, accel_id, 0, 0); // FIXME: How about overloaded? result = true; } // Process Grabs, unofficial GTK feature exists = false; GrabbedKey key = new GrabbedKey(e); synchronized(GRAB_LOCK) { exists = grabbed_keys.contains(key); } if (exists) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine("Forwarding grabbed key " + e); } forwardKeyEvent(e); result = true; } return result; } public void modalityPushed(ModalityEvent ev) { xembed.sendMessage(xembed.handle, XEMBED_MODALITY_ON); } public void modalityPopped(ModalityEvent ev) { xembed.sendMessage(xembed.handle, XEMBED_MODALITY_OFF); } public void handleClientMessage(XEvent xev) { super.handleClientMessage(xev); XClientMessageEvent msg = xev.get_xclient(); if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Client message to embedder: " + msg); } if (msg.get_message_type() == XEmbedHelper.XEmbed.getAtom()) { if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) { xembedLog.fine(XEmbedHelper.XEmbedMessageToString(msg)); } } if (isXEmbedActive()) { switch ((int)msg.get_data(1)) { case XEMBED_REQUEST_FOCUS: requestXEmbedFocus(); break; case XEMBED_FOCUS_NEXT: focusNext(); break; case XEMBED_FOCUS_PREV: focusPrev(); break; case XEMBED_REGISTER_ACCELERATOR: registerAccelerator(msg.get_data(2), msg.get_data(3), msg.get_data(4)); break; case XEMBED_UNREGISTER_ACCELERATOR: unregisterAccelerator(msg.get_data(2)); break; case NON_STANDARD_XEMBED_GTK_GRAB_KEY: grabKey(msg.get_data(3), msg.get_data(4)); break; case NON_STANDARD_XEMBED_GTK_UNGRAB_KEY: ungrabKey(msg.get_data(3), msg.get_data(4)); break; } } else { xembedLog.finer("But XEmbed is not Active!"); } } @SuppressWarnings("serial") // JDK-implementation class private static class XEmbedDropTarget extends DropTarget { public void addDropTargetListener(DropTargetListener dtl) throws TooManyListenersException { // Drop target listeners registered with this target will never be // notified, since all drag notifications are routed to the XEmbed // client. To avoid confusion we prohibit listeners registration // by throwing TooManyListenersException as if there is a listener // registered with this target already. throw new TooManyListenersException(); } } public void setXEmbedDropTarget() { // Register a drop site on the top level. Runnable r = new Runnable() { public void run() { target.setDropTarget(new XEmbedDropTarget()); } }; SunToolkit.executeOnEventHandlerThread(target, r); } public void removeXEmbedDropTarget() { // Unregister a drop site on the top level. Runnable r = new Runnable() { public void run() { if (target.getDropTarget() instanceof XEmbedDropTarget) { target.setDropTarget(null); } } }; SunToolkit.executeOnEventHandlerThread(target, r); } public boolean processXEmbedDnDEvent(long ctxt, int eventID) { if (xembedLog.isLoggable(PlatformLogger.Level.FINEST)) { xembedLog.finest(" Drop target=" + target.getDropTarget()); } if (target.getDropTarget() instanceof XEmbedDropTarget) { AppContext appContext = XToolkit.targetToAppContext(getTarget()); XDropTargetContextPeer peer = XDropTargetContextPeer.getPeer(appContext); peer.forwardEventToEmbedded(xembed.handle, ctxt, eventID); return true; } else { return false; } } class XEmbedServer extends XEmbedHelper implements XEventDispatcher { long handle; // Handle to XEmbed client long version; long flags; boolean processXEmbedInfo() { long xembed_info_data = Native.allocateLongArray(2); try { if (!XEmbedInfo.getAtomData(handle, xembed_info_data, 2)) { // No more XEMBED_INFO? This is not XEmbed client! // Unfortunately this is the initial state of the most clients // FIXME: add 5-state processing //childDestroyed(); xembedLog.finer("Unable to get XEMBED_INFO atom data"); return false; } version = Native.getCard32(xembed_info_data, 0); flags = Native.getCard32(xembed_info_data, 1); boolean new_mapped = (flags & XEMBED_MAPPED) != 0; boolean currently_mapped = XlibUtil.getWindowMapState(handle) != XConstants.IsUnmapped; if (new_mapped != currently_mapped) { if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Mapping state of the client has changed, old state: " + currently_mapped + ", new state: " + new_mapped); } if (new_mapped) { XToolkit.awtLock(); try { XlibWrapper.XMapWindow(XToolkit.getDisplay(), handle); } finally { XToolkit.awtUnlock(); } } else { XToolkit.awtLock(); try { XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), handle); } finally { XToolkit.awtUnlock(); } } } else { if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Mapping state didn't change, mapped: " + currently_mapped); } } return true; } finally { XlibWrapper.unsafe.freeMemory(xembed_info_data); } } public void handlePropertyNotify(XEvent xev) { if (isXEmbedActive()) { XPropertyEvent ev = xev.get_xproperty(); if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Property change on client: " + ev); } if (ev.get_atom() == XAtom.XA_WM_NORMAL_HINTS) { childResized(); } else if (ev.get_atom() == XEmbedInfo.getAtom()) { processXEmbedInfo(); } else if (ev.get_atom() == XDnDConstants.XA_XdndAware.getAtom()) { XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(), xembed.handle); if (ev.get_state() == XConstants.PropertyNewValue) { XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(), xembed.handle); } } } else { xembedLog.finer("XEmbed is not active"); } } void handleConfigureNotify(XEvent xev) { if (isXEmbedActive()) { XConfigureEvent ev = xev.get_xconfigure(); if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) { xembedLog.finer("Bounds change on client: " + ev); } if (xev.get_xany().get_window() == handle) { childResized(); } } } public void dispatchEvent(XEvent xev) { int type = xev.get_type(); switch (type) { case XConstants.PropertyNotify: handlePropertyNotify(xev); break; case XConstants.ConfigureNotify: handleConfigureNotify(xev); break; case XConstants.ClientMessage: handleClientMessage(xev); break; } } } static class GrabbedKey { long keysym; long modifiers; GrabbedKey(long keysym, long modifiers) { this.keysym = keysym; this.modifiers = modifiers; } GrabbedKey(KeyEvent ev) { init(ev); } private void init(KeyEvent e) { byte[] bdata = getBData(e); long data = Native.toData(bdata); if (data == 0) { return; } try { XToolkit.awtLock(); try { keysym = XWindow.getKeySymForAWTKeyCode(e.getKeyCode()); } finally { XToolkit.awtUnlock(); } XKeyEvent ke = new XKeyEvent(data); // We recognize only these masks modifiers = ke.get_state() & (XConstants.ShiftMask | XConstants.ControlMask | XConstants.LockMask); if (xembedLog.isLoggable(PlatformLogger.Level.FINEST)) { xembedLog.finest("Mapped " + e + " to " + this); } } finally { XlibWrapper.unsafe.freeMemory(data); } } public int hashCode() { return (int)keysym & 0xFFFFFFFF; } public boolean equals(Object o) { if (!(o instanceof GrabbedKey)) { return false; } GrabbedKey key = (GrabbedKey)o; return (keysym == key.keysym && modifiers == key.modifiers); } public String toString() { return "Key combination[keysym=" + keysym + ", mods=" + modifiers + "]"; } } }