jdk/src/solaris/classes/sun/awt/motif/MEmbedCanvasPeer.java
changeset 1192 715cf9378c53
parent 1051 90cf935adb35
parent 1191 f142c1da78c2
child 1193 41afb8ee8f45
equal deleted inserted replaced
1051:90cf935adb35 1192:715cf9378c53
     1 /*
       
     2  * Copyright 2003-2005 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.motif;
       
    27 
       
    28 import java.awt.*;
       
    29 import java.awt.dnd.DropTarget;
       
    30 import java.awt.dnd.DropTargetListener;
       
    31 import java.awt.event.*;
       
    32 import java.awt.image.ColorModel;
       
    33 import java.awt.image.ImageObserver;
       
    34 import java.awt.image.ImageProducer;
       
    35 import java.awt.image.VolatileImage;
       
    36 import java.awt.peer.*;
       
    37 import sun.awt.*;
       
    38 import sun.awt.motif.X11FontMetrics;
       
    39 import java.lang.reflect.*;
       
    40 import java.util.logging.*;
       
    41 import java.util.*;
       
    42 
       
    43 // FIXME: Add X errors handling
       
    44 // FIXME: Add chaining of parameters to XEmbed-client if we are both(accelerators; XDND; focus already automatically)
       
    45 public class MEmbedCanvasPeer extends MCanvasPeer implements WindowFocusListener, KeyEventPostProcessor, ModalityListener, WindowIDProvider {
       
    46     private static final Logger xembedLog = Logger.getLogger("sun.awt.motif.xembed.MEmbedCanvasPeer");
       
    47 
       
    48     final static int XEMBED_VERSION = 0,
       
    49         XEMBED_MAPPED = (1 << 0);
       
    50 /* XEMBED messages */
       
    51     final static int XEMBED_EMBEDDED_NOTIFY     =       0;
       
    52     final static int XEMBED_WINDOW_ACTIVATE  =  1;
       
    53     final static int XEMBED_WINDOW_DEACTIVATE =         2;
       
    54     final static int XEMBED_REQUEST_FOCUS               =3;
       
    55     final static int XEMBED_FOCUS_IN    =       4;
       
    56     final static int XEMBED_FOCUS_OUT   =       5;
       
    57     final static int XEMBED_FOCUS_NEXT  =       6;
       
    58     final static int XEMBED_FOCUS_PREV  =       7;
       
    59 /* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
       
    60     final static int XEMBED_GRAB_KEY = 8;
       
    61     final static int XEMBED_UNGRAB_KEY = 9;
       
    62     final static int XEMBED_MODALITY_ON         =       10;
       
    63     final static int XEMBED_MODALITY_OFF        =       11;
       
    64     final static int XEMBED_REGISTER_ACCELERATOR =    12;
       
    65     final static int XEMBED_UNREGISTER_ACCELERATOR=   13;
       
    66     final static int XEMBED_ACTIVATE_ACCELERATOR  =   14;
       
    67 
       
    68     final static int NON_STANDARD_XEMBED_GTK_GRAB_KEY = 108;
       
    69     final static int NON_STANDARD_XEMBED_GTK_UNGRAB_KEY = 109;
       
    70 
       
    71 //     A detail code is required for XEMBED_FOCUS_IN. The following values are valid:
       
    72 /* Details for  XEMBED_FOCUS_IN: */
       
    73     final static int XEMBED_FOCUS_CURRENT       =       0;
       
    74     final static int XEMBED_FOCUS_FIRST         =       1;
       
    75     final static int XEMBED_FOCUS_LAST  =       2;
       
    76 
       
    77 // Modifiers bits
       
    78     final static int XEMBED_MODIFIER_SHIFT   = (1 << 0);
       
    79     final static int XEMBED_MODIFIER_CONTROL = (1 << 1);
       
    80     final static int XEMBED_MODIFIER_ALT     = (1 << 2);
       
    81     final static int XEMBED_MODIFIER_SUPER   = (1 << 3);
       
    82     final static int XEMBED_MODIFIER_HYPER   = (1 << 4);
       
    83 
       
    84     boolean applicationActive; // Whether the application is active(has focus)
       
    85     Map<Long, AWTKeyStroke> accelerators = new HashMap<Long, AWTKeyStroke>(); // Maps accelerator ID into AWTKeyStroke
       
    86     Map<AWTKeyStroke, Long> accel_lookup = new HashMap<AWTKeyStroke, Long>(); // Maps AWTKeyStroke into accelerator ID
       
    87     Set<GrabbedKey> grabbed_keys = new HashSet<GrabbedKey>(); // A set of keys grabbed by client
       
    88     Object ACCEL_LOCK = accelerators; // Lock object for working with accelerators;
       
    89     Object GRAB_LOCK = grabbed_keys; // Lock object for working with keys grabbed by client
       
    90 
       
    91     MEmbedCanvasPeer() {}
       
    92 
       
    93     MEmbedCanvasPeer(Component target) {
       
    94         super(target);
       
    95     }
       
    96 
       
    97     void initialize() {
       
    98         super.initialize();
       
    99 
       
   100         installActivateListener();
       
   101         installAcceleratorListener();
       
   102         installModalityListener();
       
   103 
       
   104         // XEmbed canvas should be non-traversable.
       
   105         // FIXME: Probably should be removed and enforced setting of it by the users
       
   106         target.setFocusTraversalKeysEnabled(false);
       
   107 
       
   108         initXEmbedServer();
       
   109     }
       
   110 
       
   111     void installModalityListener() {
       
   112         ((SunToolkit)Toolkit.getDefaultToolkit()).addModalityListener(this);
       
   113     }
       
   114 
       
   115     void deinstallModalityListener() {
       
   116         ((SunToolkit)Toolkit.getDefaultToolkit()).removeModalityListener(this);
       
   117     }
       
   118 
       
   119     void installAcceleratorListener() {
       
   120         KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this);
       
   121     }
       
   122 
       
   123     void deinstallAcceleratorListener() {
       
   124         KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(this);
       
   125     }
       
   126 
       
   127     void installActivateListener() {
       
   128         // FIXME: should watch for hierarchy changes
       
   129         Window toplevel = getTopLevel(target);
       
   130         if (toplevel != null) {
       
   131             toplevel.addWindowFocusListener(this);
       
   132             applicationActive = toplevel.isFocused();
       
   133         }
       
   134     }
       
   135 
       
   136     void deinstallActivateListener() {
       
   137         Window toplevel = getTopLevel(target);
       
   138         if (toplevel != null) {
       
   139             toplevel.removeWindowFocusListener(this);
       
   140         }
       
   141     }
       
   142 
       
   143     native boolean isXEmbedActive();
       
   144 
       
   145     boolean isApplicationActive() {
       
   146         return applicationActive;
       
   147     }
       
   148 
       
   149     native void initDispatching();
       
   150 
       
   151     native void endDispatching();
       
   152 
       
   153     native void embedChild(long child);
       
   154 
       
   155     native void childDestroyed();
       
   156 
       
   157     public void handleEvent(AWTEvent e) {
       
   158         super.handleEvent(e);
       
   159         if (isXEmbedActive()) {
       
   160             switch (e.getID()) {
       
   161               case FocusEvent.FOCUS_GAINED:
       
   162                   canvasFocusGained((FocusEvent)e);
       
   163                   break;
       
   164               case FocusEvent.FOCUS_LOST:
       
   165                   canvasFocusLost((FocusEvent)e);
       
   166                   break;
       
   167               case KeyEvent.KEY_PRESSED:
       
   168               case KeyEvent.KEY_RELEASED:
       
   169                   if (!((InputEvent)e).isConsumed()) {
       
   170                       forwardKeyEvent((KeyEvent)e);
       
   171                   }
       
   172                   break;
       
   173             }
       
   174         }
       
   175     }
       
   176 
       
   177     public Dimension getPreferredSize() {
       
   178         if (isXEmbedActive()) {
       
   179             Dimension dim = getEmbedPreferredSize();
       
   180             if (dim == null) {
       
   181                 return super.getPreferredSize();
       
   182             } else {
       
   183                 return dim;
       
   184             }
       
   185         } else {
       
   186             return super.getPreferredSize();
       
   187         }
       
   188     }
       
   189     native Dimension getEmbedPreferredSize();
       
   190     public Dimension getMinimumSize() {
       
   191         if (isXEmbedActive()) {
       
   192             Dimension dim = getEmbedMinimumSize();
       
   193             if (dim == null) {
       
   194                 return super.getMinimumSize();
       
   195             } else {
       
   196                 return dim;
       
   197             }
       
   198         } else {
       
   199             return super.getMinimumSize();
       
   200         }
       
   201     }
       
   202     native Dimension getEmbedMinimumSize();
       
   203     protected void disposeImpl() {
       
   204         if (isXEmbedActive()) {
       
   205             detachChild();
       
   206         }
       
   207         deinstallActivateListener();
       
   208         deinstallModalityListener();
       
   209         deinstallAcceleratorListener();
       
   210 
       
   211         destroyXEmbedServer();
       
   212         super.disposeImpl();
       
   213     }
       
   214 
       
   215     public boolean isFocusable() {
       
   216         return true;
       
   217     }
       
   218 
       
   219     Window getTopLevel(Component comp) {
       
   220         while (comp != null && !(comp instanceof Window)) {
       
   221             comp = comp.getParent();
       
   222         }
       
   223         return (Window)comp;
       
   224     }
       
   225 
       
   226     native Rectangle getClientBounds();
       
   227 
       
   228     void childResized() {
       
   229         if (xembedLog.isLoggable(Level.FINER)) {
       
   230             Rectangle bounds = getClientBounds();
       
   231             xembedLog.finer("Child resized: " + bounds);
       
   232             // It is not required to update embedder's size when client size changes
       
   233             // However, since there is no any means to get client size it seems to be the
       
   234             // only way to provide it. However, it contradicts with Java layout concept -
       
   235             // so it is disabled for now.
       
   236 //             Rectangle my_bounds = getBounds();
       
   237 //             setBounds(my_bounds.x, my_bounds.y, bounds.width, bounds.height, SET_BOUNDS);
       
   238         }
       
   239         postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED));
       
   240     }
       
   241 
       
   242     void focusNext() {
       
   243         if (isXEmbedActive()) {
       
   244             xembedLog.fine("Requesting focus for the next component after embedder");
       
   245             postEvent(new InvocationEvent(target, new Runnable() {
       
   246                     public void run() {
       
   247                         KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(target);
       
   248                     }
       
   249                 }));
       
   250         } else {
       
   251             xembedLog.fine("Application is not active - denying focus next");
       
   252         }
       
   253     }
       
   254 
       
   255     void focusPrev() {
       
   256         if (isXEmbedActive()) {
       
   257             xembedLog.fine("Requesting focus for the next component after embedder");
       
   258             postEvent(new InvocationEvent(target, new Runnable() {
       
   259                     public void run() {
       
   260                         KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(target);
       
   261                     }
       
   262                 }));
       
   263         } else {
       
   264             xembedLog.fine("Application is not active - denying focus prev");
       
   265         }
       
   266     }
       
   267 
       
   268     void requestXEmbedFocus() {
       
   269         if (isXEmbedActive()) {
       
   270             xembedLog.fine("Requesting focus for client");
       
   271             postEvent(new InvocationEvent(target, new Runnable() {
       
   272                     public void run() {
       
   273                         target.requestFocusInWindow();
       
   274                     }
       
   275                 }));
       
   276         } else {
       
   277             xembedLog.fine("Application is not active - denying request focus");
       
   278         }
       
   279     }
       
   280 
       
   281     native void notifyChildEmbedded();
       
   282 
       
   283     native void detachChild();
       
   284 
       
   285     public void windowGainedFocus(WindowEvent e) {
       
   286         applicationActive = true;
       
   287         if (isXEmbedActive()) {
       
   288             xembedLog.fine("Sending WINDOW_ACTIVATE");
       
   289             sendMessage(XEMBED_WINDOW_ACTIVATE);
       
   290         }
       
   291     }
       
   292 
       
   293     public void windowLostFocus(WindowEvent e) {
       
   294         applicationActive = false;
       
   295         if (isXEmbedActive()) {
       
   296             xembedLog.fine("Sending WINDOW_DEACTIVATE");
       
   297             sendMessage(XEMBED_WINDOW_DEACTIVATE);
       
   298         }
       
   299     }
       
   300 
       
   301     void canvasFocusGained(FocusEvent e) {
       
   302         if (isXEmbedActive()) {
       
   303             xembedLog.fine("Forwarding FOCUS_GAINED");
       
   304             int flavor = XEMBED_FOCUS_CURRENT;
       
   305             if (e instanceof CausedFocusEvent) {
       
   306                 CausedFocusEvent ce = (CausedFocusEvent)e;
       
   307                 if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_FORWARD) {
       
   308                     flavor = XEMBED_FOCUS_FIRST;
       
   309                 } else if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_BACKWARD) {
       
   310                     flavor = XEMBED_FOCUS_LAST;
       
   311                 }
       
   312             }
       
   313             sendMessage(XEMBED_FOCUS_IN, flavor, 0, 0);
       
   314         }
       
   315     }
       
   316 
       
   317     void canvasFocusLost(FocusEvent e) {
       
   318         if (isXEmbedActive() && !e.isTemporary()) {
       
   319             xembedLog.fine("Forwarding FOCUS_LOST");
       
   320             Component opp = e.getOppositeComponent();
       
   321             int num = 0;
       
   322             try {
       
   323                 num = Integer.parseInt(opp.getName());
       
   324             } catch (NumberFormatException nfe) {
       
   325             }
       
   326             sendMessage(XEMBED_FOCUS_OUT, num, 0, 0);
       
   327         }
       
   328     }
       
   329 
       
   330     native void forwardKeyEvent(KeyEvent e);
       
   331 
       
   332     void grabKey(final long keysym, final long modifiers) {
       
   333         postEvent(new InvocationEvent(target, new Runnable() {
       
   334                 public void run() {
       
   335                     GrabbedKey grab = new GrabbedKey(keysym, modifiers);
       
   336                     if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Grabbing key: " + grab);
       
   337                     synchronized(GRAB_LOCK) {
       
   338                         grabbed_keys.add(grab);
       
   339                     }
       
   340                 }
       
   341             }));
       
   342     }
       
   343 
       
   344     void ungrabKey(final long keysym, final long modifiers) {
       
   345         postEvent(new InvocationEvent(target, new Runnable() {
       
   346                 public void run() {
       
   347                     GrabbedKey grab = new GrabbedKey(keysym, modifiers);
       
   348                     if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("UnGrabbing key: " + grab);
       
   349                     synchronized(GRAB_LOCK) {
       
   350                         grabbed_keys.remove(grab);
       
   351                     }
       
   352                 }
       
   353             }));
       
   354     }
       
   355 
       
   356     void registerAccelerator(final long accel_id, final long keysym, final long modifiers) {
       
   357         postEvent(new InvocationEvent(target, new Runnable() {
       
   358                 public void run() {
       
   359                     AWTKeyStroke stroke = getKeyStrokeForKeySym(keysym, modifiers);
       
   360                     if (stroke != null) {
       
   361                         if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Registering accelerator " + accel_id + " for " + stroke);
       
   362                         synchronized(ACCEL_LOCK) {
       
   363                             accelerators.put(accel_id, stroke);
       
   364                             accel_lookup.put(stroke, accel_id);
       
   365                         }
       
   366                     }
       
   367                     // Propogate accelerators to the another embedder
       
   368                     propogateRegisterAccelerator(stroke);
       
   369                 }
       
   370             }));
       
   371     }
       
   372 
       
   373     void unregisterAccelerator(final long accel_id) {
       
   374         postEvent(new InvocationEvent(target, new Runnable() {
       
   375                 public void run() {
       
   376                     AWTKeyStroke stroke = null;
       
   377                     synchronized(ACCEL_LOCK) {
       
   378                         stroke = accelerators.get(accel_id);
       
   379                         if (stroke != null) {
       
   380                             if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Unregistering accelerator: " + accel_id);
       
   381                             accelerators.remove(accel_id);
       
   382                             accel_lookup.remove(stroke); // FIXME: How about several accelerators with the same stroke?
       
   383                         }
       
   384                     }
       
   385                     // Propogate accelerators to the another embedder
       
   386                     propogateUnRegisterAccelerator(stroke);
       
   387                 }
       
   388             }));
       
   389     }
       
   390 
       
   391     void propogateRegisterAccelerator(AWTKeyStroke stroke) {
       
   392         // Find the top-level and see if it is XEmbed client. If so, ask him to
       
   393         // register the accelerator
       
   394         MWindowPeer parent = getParentWindow();
       
   395         if (parent != null && parent instanceof MEmbeddedFramePeer) {
       
   396             MEmbeddedFramePeer embedded = (MEmbeddedFramePeer)parent;
       
   397             embedded.registerAccelerator(stroke);
       
   398         }
       
   399     }
       
   400 
       
   401     void propogateUnRegisterAccelerator(AWTKeyStroke stroke) {
       
   402         // Find the top-level and see if it is XEmbed client. If so, ask him to
       
   403         // register the accelerator
       
   404         MWindowPeer parent = getParentWindow();
       
   405         if (parent != null && parent instanceof MEmbeddedFramePeer) {
       
   406             MEmbeddedFramePeer embedded = (MEmbeddedFramePeer)parent;
       
   407             embedded.unregisterAccelerator(stroke);
       
   408         }
       
   409     }
       
   410 
       
   411     public boolean postProcessKeyEvent(KeyEvent e) {
       
   412         // Processing events only if we are in the focused window.
       
   413         MWindowPeer parent = getParentWindow();
       
   414         if (parent == null || !((Window)parent.target).isFocused() || target.isFocusOwner()) {
       
   415             return false;
       
   416         }
       
   417 
       
   418         boolean result = false;
       
   419 
       
   420         if (xembedLog.isLoggable(Level.FINER)) xembedLog.finer("Post-processing event " + e);
       
   421 
       
   422         // Process ACCELERATORS
       
   423         AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e);
       
   424         long accel_id = 0;
       
   425         boolean exists = false;
       
   426         synchronized(ACCEL_LOCK) {
       
   427             exists = accel_lookup.containsKey(stroke);
       
   428             if (exists) {
       
   429                 accel_id = accel_lookup.get(stroke).longValue();
       
   430             }
       
   431         }
       
   432         if (exists) {
       
   433             if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Activating accelerator " + accel_id);
       
   434             sendMessage(XEMBED_ACTIVATE_ACCELERATOR, accel_id, 0, 0); // FIXME: How about overloaded?
       
   435             result = true;
       
   436         }
       
   437 
       
   438         // Process Grabs, unofficial GTK feature
       
   439         exists = false;
       
   440         GrabbedKey key = new GrabbedKey(e);
       
   441         synchronized(GRAB_LOCK) {
       
   442             exists = grabbed_keys.contains(key);
       
   443         }
       
   444         if (exists) {
       
   445             if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Forwarding grabbed key " + e);
       
   446             forwardKeyEvent(e);
       
   447             result = true;
       
   448         }
       
   449 
       
   450         return result;
       
   451     }
       
   452 
       
   453     public void modalityPushed(ModalityEvent ev) {
       
   454         sendMessage(XEMBED_MODALITY_ON);
       
   455     }
       
   456 
       
   457     public void modalityPopped(ModalityEvent ev) {
       
   458         sendMessage(XEMBED_MODALITY_OFF);
       
   459     }
       
   460 
       
   461     int getModifiers(int state) {
       
   462         int mods = 0;
       
   463         if ((state & XEMBED_MODIFIER_SHIFT) != 0) {
       
   464             mods |= InputEvent.SHIFT_DOWN_MASK;
       
   465         }
       
   466         if ((state & XEMBED_MODIFIER_CONTROL) != 0) {
       
   467             mods |= InputEvent.CTRL_DOWN_MASK;
       
   468         }
       
   469         if ((state & XEMBED_MODIFIER_ALT) != 0) {
       
   470             mods |= InputEvent.ALT_DOWN_MASK;
       
   471         }
       
   472         // FIXME: What is super/hyper?
       
   473         // FIXME: Experiments show that SUPER is ALT. So what is Alt then?
       
   474         if ((state & XEMBED_MODIFIER_SUPER) != 0) {
       
   475             mods |= InputEvent.ALT_DOWN_MASK;
       
   476         }
       
   477 //         if ((state & XEMBED_MODIFIER_HYPER) != 0) {
       
   478 //             mods |= InputEvent.DOWN_MASK;
       
   479 //         }
       
   480         return mods;
       
   481     }
       
   482 
       
   483     // Shouldn't be called on Toolkit thread.
       
   484     AWTKeyStroke getKeyStrokeForKeySym(long keysym, long state) {
       
   485 
       
   486         int keycode = getAWTKeyCodeForKeySym((int)keysym);
       
   487         int modifiers = getModifiers((int)state);
       
   488         return AWTKeyStroke.getAWTKeyStroke(keycode, modifiers);
       
   489     }
       
   490     native int getAWTKeyCodeForKeySym(int keysym);
       
   491     native void sendMessage(int msg);
       
   492     native void sendMessage(int msg, long detail, long data1, long data2);
       
   493     MWindowPeer getParentWindow() {
       
   494         Component parent = target.getParent();
       
   495         synchronized(target.getTreeLock()) {
       
   496             while (parent != null && !(parent.getPeer() instanceof MWindowPeer)) {
       
   497                 parent = parent.getParent();
       
   498             }
       
   499             return (parent != null)?(MWindowPeer)parent.getPeer():null;
       
   500         }
       
   501     }
       
   502 
       
   503     private static class XEmbedDropTarget extends DropTarget {
       
   504         public void addDropTargetListener(DropTargetListener dtl)
       
   505           throws TooManyListenersException {
       
   506             // Drop target listeners registered with this target will never be
       
   507             // notified, since all drag notifications are routed to the XEmbed
       
   508             // client. To avoid confusion we prohibit listeners registration
       
   509             // by throwing TooManyListenersException as if there is a listener
       
   510             // registered with this target already.
       
   511             throw new TooManyListenersException();
       
   512         }
       
   513     }
       
   514 
       
   515     public void setXEmbedDropTarget() {
       
   516         // Register a drop site on the top level.
       
   517         Runnable r = new Runnable() {
       
   518                 public void run() {
       
   519                     target.setDropTarget(new XEmbedDropTarget());
       
   520                 }
       
   521             };
       
   522         SunToolkit.executeOnEventHandlerThread(target, r);
       
   523     }
       
   524 
       
   525     public void removeXEmbedDropTarget() {
       
   526         // Unregister a drop site on the top level.
       
   527         Runnable r = new Runnable() {
       
   528                 public void run() {
       
   529                     if (target.getDropTarget() instanceof XEmbedDropTarget) {
       
   530                         target.setDropTarget(null);
       
   531                     }
       
   532                 }
       
   533             };
       
   534         SunToolkit.executeOnEventHandlerThread(target, r);
       
   535     }
       
   536 
       
   537     public boolean processXEmbedDnDEvent(long ctxt, int eventID) {
       
   538         if (target.getDropTarget() instanceof XEmbedDropTarget) {
       
   539             forwardEventToEmbedded(ctxt, eventID);
       
   540             return true;
       
   541         } else {
       
   542             return false;
       
   543         }
       
   544     }
       
   545 
       
   546     native void forwardEventToEmbedded(long ctxt, int eventID);
       
   547     native void initXEmbedServer();
       
   548     native void destroyXEmbedServer();
       
   549     public native long getWindow();
       
   550 }
       
   551 class GrabbedKey {
       
   552     long keysym;
       
   553     long modifiers;
       
   554     GrabbedKey(long keysym, long modifiers) {
       
   555         this.keysym = keysym;
       
   556         this.modifiers = modifiers;
       
   557     }
       
   558 
       
   559     GrabbedKey(KeyEvent ev) {
       
   560         init(ev);
       
   561     }
       
   562 
       
   563     native void initKeySymAndModifiers(KeyEvent e);
       
   564 
       
   565     private void init(KeyEvent e) {
       
   566         initKeySymAndModifiers(e);
       
   567     }
       
   568 
       
   569     public int hashCode() {
       
   570         return (int)keysym & 0xFFFFFFFF;
       
   571     }
       
   572 
       
   573     public boolean equals(Object o) {
       
   574         if (!(o instanceof GrabbedKey)) {
       
   575             return false;
       
   576         }
       
   577         GrabbedKey key = (GrabbedKey)o;
       
   578         return (keysym == key.keysym && modifiers == key.modifiers);
       
   579     }
       
   580 
       
   581     public String toString() {
       
   582         return "Key combination[keysym=" + keysym + ", mods=" + modifiers + "]";
       
   583     }
       
   584 }