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