1 /*
   2  * Copyright (c) 2003, 2008, 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.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.HashMap;
  31 import java.util.HashSet;
  32 import java.util.Iterator;
  33 import java.util.List;
  34 import sun.util.logging.PlatformLogger;
  35 
  36 import java.awt.Point;
  37 
  38 
  39 /**
  40  * The class responsible for registration/deregistration of drop sites.
  41  *
  42  * @since 1.5
  43  */
  44 final class XDropTargetRegistry {
  45     private static final PlatformLogger logger =
  46         PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDropTargetRegistry");
  47 
  48     private static final long DELAYED_REGISTRATION_PERIOD = 200;
  49 
  50     private static final XDropTargetRegistry theInstance =
  51         new XDropTargetRegistry();
  52 
  53     private final HashMap<Long, Runnable> delayedRegistrationMap =
  54         new HashMap<Long, Runnable>();
  55 
  56     private XDropTargetRegistry() {}
  57 
  58     static XDropTargetRegistry getRegistry() {
  59         return theInstance;
  60     }
  61 
  62     /**
  63      * Returns the XID of the topmost window with WM_STATE set in the ancestor
  64      * heirarchy of the specified window or 0 if none found.
  65      */
  66     private long getToplevelWindow(long window) {
  67         XBaseWindow candWindow = XToolkit.windowToXWindow(window);
  68         if (candWindow != null) {
  69             XWindowPeer toplevel = candWindow.getToplevelXWindow();
  70             if (toplevel != null && !(toplevel instanceof XEmbeddedFramePeer)) {
  71                 return toplevel.getWindow();
  72             }
  73         }
  74 
  75         /* Traverse the ancestor tree from window up to the root and find
  76            the top-level client window nearest to the root. */
  77         do {
  78             if (XlibUtil.isTrueToplevelWindow(window)) {
  79                 return window;
  80             }
  81 
  82             window = XlibUtil.getParentWindow(window);
  83 
  84         } while (window != 0);
  85 
  86         return window;
  87     }
  88 
  89     static final long getDnDProxyWindow() {
  90         return XWindow.getXAWTRootWindow().getWindow();
  91     }
  92 
  93     private static final class EmbeddedDropSiteEntry {
  94         private final long root;
  95         private final long event_mask;
  96         private List<XDropTargetProtocol> supportedProtocols;
  97         private final HashSet<Long> nonXEmbedClientSites = new HashSet<Long>();
  98         private final List<Long> sites = new ArrayList<Long>();
  99 
 100         public EmbeddedDropSiteEntry(long root, long event_mask,
 101                                      List<XDropTargetProtocol> supportedProtocols) {
 102             if (supportedProtocols == null) {
 103                 throw new NullPointerException("Null supportedProtocols");
 104             }
 105             this.root = root;
 106             this.event_mask = event_mask;
 107             this.supportedProtocols = supportedProtocols;
 108         }
 109 
 110         public long getRoot() {
 111             return root;
 112         }
 113         public long getEventMask() {
 114             return event_mask;
 115         }
 116         public boolean hasNonXEmbedClientSites() {
 117             return !nonXEmbedClientSites.isEmpty();
 118         }
 119         public synchronized void addSite(long window, boolean isXEmbedClient) {
 120             Long lWindow = Long.valueOf(window);
 121             if (!sites.contains(lWindow)) {
 122                 sites.add(lWindow);
 123             }
 124             if (!isXEmbedClient) {
 125                 nonXEmbedClientSites.add(lWindow);
 126             }
 127         }
 128         public synchronized void removeSite(long window) {
 129             Long lWindow = Long.valueOf(window);
 130             sites.remove(lWindow);
 131             nonXEmbedClientSites.remove(lWindow);
 132         }
 133         public void setSupportedProtocols(List<XDropTargetProtocol> list) {
 134             supportedProtocols = list;
 135         }
 136         public List<XDropTargetProtocol> getSupportedProtocols() {
 137             return supportedProtocols;
 138         }
 139         public boolean hasSites() {
 140             return !sites.isEmpty();
 141         }
 142         public long[] getSites() {
 143             long[] ret = new long[sites.size()];
 144             Iterator iter = sites.iterator();
 145             int index = 0;
 146             while (iter.hasNext()) {
 147                 Long l = (Long)iter.next();
 148                 ret[index++] = l.longValue();
 149             }
 150             return ret;
 151         }
 152         public long getSite(int x, int y) {
 153             assert XToolkit.isAWTLockHeldByCurrentThread();
 154 
 155             Iterator<Long> iter = sites.iterator();
 156             while (iter.hasNext()) {
 157                 Long l = iter.next();
 158                 long window = l.longValue();
 159 
 160                 Point p = XBaseWindow.toOtherWindow(getRoot(), window, x, y);
 161 
 162                 if (p == null) {
 163                     continue;
 164                 }
 165 
 166                 int dest_x = p.x;
 167                 int dest_y = p.y;
 168                 if (dest_x >= 0 && dest_y >= 0) {
 169                     XWindowAttributes wattr = new XWindowAttributes();
 170                     try {
 171                         XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 172                         int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 173                                                                       window, wattr.pData);
 174                         XToolkit.RESTORE_XERROR_HANDLER();
 175 
 176                         if (status == 0 ||
 177                             (XToolkit.saved_error != null &&
 178                              XToolkit.saved_error.get_error_code() != XConstants.Success)) {
 179                             continue;
 180                         }
 181 
 182                         if (wattr.get_map_state() != XConstants.IsUnmapped
 183                             && dest_x < wattr.get_width()
 184                             && dest_y < wattr.get_height()) {
 185                             return window;
 186                         }
 187                     } finally {
 188                         wattr.dispose();
 189                     }
 190                 }
 191             }
 192             return 0;
 193         }
 194     }
 195 
 196     private final HashMap<Long, EmbeddedDropSiteEntry> embeddedDropSiteRegistry =
 197         new HashMap<Long, EmbeddedDropSiteEntry>();
 198 
 199     private EmbeddedDropSiteEntry registerEmbedderDropSite(long embedder) {
 200         assert XToolkit.isAWTLockHeldByCurrentThread();
 201 
 202         Iterator dropTargetProtocols =
 203             XDragAndDropProtocols.getDropTargetProtocols();
 204         // The list of protocols supported by the embedder.
 205         List<XDropTargetProtocol> embedderProtocols = new ArrayList();
 206 
 207         while (dropTargetProtocols.hasNext()) {
 208             XDropTargetProtocol dropTargetProtocol =
 209                 (XDropTargetProtocol)dropTargetProtocols.next();
 210             if (dropTargetProtocol.isProtocolSupported(embedder)) {
 211                 embedderProtocols.add(dropTargetProtocol);
 212             }
 213         }
 214 
 215         embedderProtocols = Collections.unmodifiableList(embedderProtocols);
 216 
 217         /* Grab server, since we are working with the window that belongs to
 218            another client. */
 219         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 220         try {
 221             long root = 0;
 222             long event_mask = 0;
 223             XWindowAttributes wattr = new XWindowAttributes();
 224             try {
 225                 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 226                 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 227                                                               embedder, wattr.pData);
 228                 XToolkit.RESTORE_XERROR_HANDLER();
 229 
 230                 if (status == 0 ||
 231                     (XToolkit.saved_error != null &&
 232                      XToolkit.saved_error.get_error_code() != XConstants.Success)) {
 233                     throw new XException("XGetWindowAttributes failed");
 234                 }
 235 
 236                 event_mask = wattr.get_your_event_mask();
 237                 root = wattr.get_root();
 238             } finally {
 239                 wattr.dispose();
 240             }
 241 
 242             if ((event_mask & XConstants.PropertyChangeMask) == 0) {
 243                 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 244                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
 245                                          event_mask | XConstants.PropertyChangeMask);
 246                 XToolkit.RESTORE_XERROR_HANDLER();
 247 
 248                 if (XToolkit.saved_error != null &&
 249                     XToolkit.saved_error.get_error_code() != XConstants.Success) {
 250                     throw new XException("XSelectInput failed");
 251                 }
 252             }
 253 
 254             return new EmbeddedDropSiteEntry(root, event_mask, embedderProtocols);
 255         } finally {
 256             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 257         }
 258     }
 259 
 260     private static final boolean XEMBED_PROTOCOLS = true;
 261     private static final boolean NON_XEMBED_PROTOCOLS = false;
 262 
 263     private void registerProtocols(long embedder, boolean protocols,
 264                                    List<XDropTargetProtocol> supportedProtocols) {
 265         Iterator dropTargetProtocols = null;
 266 
 267         /*
 268          * By default, we register a drop site that supports all dnd
 269          * protocols. This approach is not appropriate in plugin
 270          * scenario if the browser supports Motif DnD and doesn't support
 271          * XDnD. If we forcibly set XdndAware on the browser toplevel, any drag
 272          * source that supports both protocols and prefers XDnD will be unable
 273          * to drop anything on the browser.
 274          * The solution for this problem is not to register XDnD drop site
 275          * if the browser supports only Motif DnD.
 276          * In general, if the browser already supports some protocols, we
 277          * register the embedded drop site only for those protocols. Otherwise
 278          * we register the embedded drop site for all protocols.
 279          */
 280         if (!supportedProtocols.isEmpty()) {
 281             dropTargetProtocols = supportedProtocols.iterator();
 282         } else {
 283             dropTargetProtocols =
 284                 XDragAndDropProtocols.getDropTargetProtocols();
 285         }
 286 
 287         /* Grab server, since we are working with the window that belongs to
 288            another client. */
 289         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 290         try {
 291             while (dropTargetProtocols.hasNext()) {
 292                 XDropTargetProtocol dropTargetProtocol =
 293                     (XDropTargetProtocol)dropTargetProtocols.next();
 294                 if ((protocols == XEMBED_PROTOCOLS) ==
 295                     dropTargetProtocol.isXEmbedSupported()) {
 296                     dropTargetProtocol.registerEmbedderDropSite(embedder);
 297                 }
 298             }
 299         } finally {
 300             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 301         }
 302     }
 303 
 304     public void updateEmbedderDropSite(long embedder) {
 305         XBaseWindow xbaseWindow = XToolkit.windowToXWindow(embedder);
 306         // No need to update our own drop sites.
 307         if (xbaseWindow != null) {
 308             return;
 309         }
 310 
 311         assert XToolkit.isAWTLockHeldByCurrentThread();
 312 
 313         Iterator dropTargetProtocols =
 314             XDragAndDropProtocols.getDropTargetProtocols();
 315         // The list of protocols supported by the embedder.
 316         List<XDropTargetProtocol> embedderProtocols = new ArrayList();
 317 
 318         while (dropTargetProtocols.hasNext()) {
 319             XDropTargetProtocol dropTargetProtocol =
 320                 (XDropTargetProtocol)dropTargetProtocols.next();
 321             if (dropTargetProtocol.isProtocolSupported(embedder)) {
 322                 embedderProtocols.add(dropTargetProtocol);
 323             }
 324         }
 325 
 326         embedderProtocols = Collections.unmodifiableList(embedderProtocols);
 327 
 328         Long lToplevel = Long.valueOf(embedder);
 329         boolean isXEmbedServer = false;
 330         synchronized (this) {
 331             EmbeddedDropSiteEntry entry =
 332                 (EmbeddedDropSiteEntry)embeddedDropSiteRegistry.get(lToplevel);
 333             if (entry == null) {
 334                 return;
 335             }
 336             entry.setSupportedProtocols(embedderProtocols);
 337             isXEmbedServer = !entry.hasNonXEmbedClientSites();
 338         }
 339 
 340         /*
 341          * By default, we register a drop site that supports all dnd
 342          * protocols. This approach is not appropriate in plugin
 343          * scenario if the browser supports Motif DnD and doesn't support
 344          * XDnD. If we forcibly set XdndAware on the browser toplevel, any drag
 345          * source that supports both protocols and prefers XDnD will be unable
 346          * to drop anything on the browser.
 347          * The solution for this problem is not to register XDnD drop site
 348          * if the browser supports only Motif DnD.
 349          * In general, if the browser already supports some protocols, we
 350          * register the embedded drop site only for those protocols. Otherwise
 351          * we register the embedded drop site for all protocols.
 352          */
 353         if (!embedderProtocols.isEmpty()) {
 354             dropTargetProtocols = embedderProtocols.iterator();
 355         } else {
 356             dropTargetProtocols =
 357                 XDragAndDropProtocols.getDropTargetProtocols();
 358         }
 359 
 360         /* Grab server, since we are working with the window that belongs to
 361            another client. */
 362         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 363         try {
 364             while (dropTargetProtocols.hasNext()) {
 365                 XDropTargetProtocol dropTargetProtocol =
 366                     (XDropTargetProtocol)dropTargetProtocols.next();
 367                 if (!isXEmbedServer || !dropTargetProtocol.isXEmbedSupported()) {
 368                     dropTargetProtocol.registerEmbedderDropSite(embedder);
 369                 }
 370             }
 371         } finally {
 372             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 373         }
 374     }
 375 
 376     private void unregisterEmbedderDropSite(long embedder,
 377                                             EmbeddedDropSiteEntry entry) {
 378         assert XToolkit.isAWTLockHeldByCurrentThread();
 379 
 380         Iterator dropTargetProtocols =
 381             XDragAndDropProtocols.getDropTargetProtocols();
 382 
 383         /* Grab server, since we are working with the window that belongs to
 384            another client. */
 385         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 386         try {
 387             while (dropTargetProtocols.hasNext()) {
 388                 XDropTargetProtocol dropTargetProtocol =
 389                     (XDropTargetProtocol)dropTargetProtocols.next();
 390                 dropTargetProtocol.unregisterEmbedderDropSite(embedder);
 391             }
 392 
 393             long event_mask = entry.getEventMask();
 394 
 395             /* Restore the original event mask for the embedder. */
 396             if ((event_mask & XConstants.PropertyChangeMask) == 0) {
 397                 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 398                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
 399                                          event_mask);
 400                 XToolkit.RESTORE_XERROR_HANDLER();
 401 
 402                 if (XToolkit.saved_error != null &&
 403                     XToolkit.saved_error.get_error_code() != XConstants.Success) {
 404                     throw new XException("XSelectInput failed");
 405                 }
 406             }
 407         } finally {
 408             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 409         }
 410     }
 411 
 412     private void registerEmbeddedDropSite(long toplevel, long window) {
 413         XBaseWindow xBaseWindow = XToolkit.windowToXWindow(window);
 414         boolean isXEmbedClient =
 415             (xBaseWindow instanceof XEmbeddedFramePeer) &&
 416             ((XEmbeddedFramePeer)xBaseWindow).isXEmbedActive();
 417 
 418         XEmbedCanvasPeer peer = null;
 419         {
 420             XBaseWindow xbaseWindow = XToolkit.windowToXWindow(toplevel);
 421             if (xbaseWindow != null) {
 422                 if (xbaseWindow instanceof XEmbedCanvasPeer) {
 423                     peer = (XEmbedCanvasPeer)xbaseWindow;
 424                 } else {
 425                     throw new UnsupportedOperationException();
 426                 }
 427             }
 428         }
 429 
 430         Long lToplevel = Long.valueOf(toplevel);
 431         EmbeddedDropSiteEntry entry = null;
 432         synchronized (this) {
 433             entry =
 434                 (EmbeddedDropSiteEntry)embeddedDropSiteRegistry.get(lToplevel);
 435             if (entry == null) {
 436                 if (peer != null) {
 437                     // Toplevel is an XEmbed server within this VM.
 438                     // Register an XEmbed drop site.
 439                     peer.setXEmbedDropTarget();
 440                     // Create a dummy entry to register the embedded site.
 441                     entry = new EmbeddedDropSiteEntry(0, 0,
 442                                                       Collections.<XDropTargetProtocol>emptyList());
 443                 } else {
 444                     // Foreign toplevel.
 445                     // Select for PropertyNotify events on the toplevel, so that
 446                     // we can track changes of the properties relevant to DnD
 447                     // protocols.
 448                     entry = registerEmbedderDropSite(toplevel);
 449                     // Register the toplevel with all DnD protocols that are not
 450                     // supported by XEmbed - actually setup a proxy, so that
 451                     // all DnD notifications sent to the toplevel are first
 452                     // routed to us.
 453                     registerProtocols(toplevel, NON_XEMBED_PROTOCOLS,
 454                                       entry.getSupportedProtocols());
 455                 }
 456                 embeddedDropSiteRegistry.put(lToplevel, entry);
 457             }
 458         }
 459 
 460         assert entry != null;
 461 
 462         synchronized (entry) {
 463             // For a foreign toplevel.
 464             if (peer == null) {
 465                 if (!isXEmbedClient) {
 466                     // Since this is not an XEmbed client we can no longer rely
 467                     // on XEmbed to route DnD notifications even for DnD
 468                     // protocols that are supported by XEmbed.
 469                     // We rollback to the XEmbed-unfriendly solution - setup
 470                     // a proxy, so that all DnD notifications sent to the
 471                     // toplevel are first routed to us.
 472                     registerProtocols(toplevel, XEMBED_PROTOCOLS,
 473                                       entry.getSupportedProtocols());
 474                 } else {
 475                     Iterator dropTargetProtocols =
 476                         XDragAndDropProtocols.getDropTargetProtocols();
 477 
 478                     // Register the embedded window as a plain drop site with
 479                     // all DnD protocols that are supported by XEmbed.
 480                     while (dropTargetProtocols.hasNext()) {
 481                         XDropTargetProtocol dropTargetProtocol =
 482                             (XDropTargetProtocol)dropTargetProtocols.next();
 483                         if (dropTargetProtocol.isXEmbedSupported()) {
 484                             dropTargetProtocol.registerEmbedderDropSite(window);
 485                         }
 486                     }
 487                 }
 488             }
 489 
 490             entry.addSite(window, isXEmbedClient);
 491         }
 492     }
 493 
 494     private void unregisterEmbeddedDropSite(long toplevel, long window) {
 495         Long lToplevel = Long.valueOf(toplevel);
 496         EmbeddedDropSiteEntry entry = null;
 497         synchronized (this) {
 498             entry =
 499                 (EmbeddedDropSiteEntry)embeddedDropSiteRegistry.get(lToplevel);
 500             if (entry == null) {
 501                 return;
 502             }
 503             entry.removeSite(window);
 504             if (!entry.hasSites()) {
 505                 embeddedDropSiteRegistry.remove(lToplevel);
 506 
 507                 XBaseWindow xbaseWindow = XToolkit.windowToXWindow(toplevel);
 508                 if (xbaseWindow != null) {
 509                     if (xbaseWindow instanceof XEmbedCanvasPeer) {
 510                         XEmbedCanvasPeer peer = (XEmbedCanvasPeer)xbaseWindow;
 511                         // Unregister an XEmbed drop site.
 512                         peer.removeXEmbedDropTarget();
 513                     } else {
 514                         throw new UnsupportedOperationException();
 515                     }
 516                 } else {
 517                     unregisterEmbedderDropSite(toplevel, entry);
 518                 }
 519             }
 520         }
 521     }
 522 
 523     /*
 524      * Returns a drop site that is embedded in the specified embedder window and
 525      * contains the point with the specified root coordinates.
 526      */
 527     public long getEmbeddedDropSite(long embedder, int x, int y) {
 528         Long lToplevel = Long.valueOf(embedder);
 529         EmbeddedDropSiteEntry entry =
 530             (EmbeddedDropSiteEntry)embeddedDropSiteRegistry.get(lToplevel);
 531         if (entry == null) {
 532             return 0;
 533         }
 534         return entry.getSite(x, y);
 535     }
 536 
 537     /*
 538      * Note: this method should be called under AWT lock.
 539      */
 540     public void registerDropSite(long window) {
 541         assert XToolkit.isAWTLockHeldByCurrentThread();
 542 
 543         if (window == 0) {
 544             throw new IllegalArgumentException();
 545         }
 546 
 547         XDropTargetEventProcessor.activate();
 548 
 549         long toplevel = getToplevelWindow(window);
 550 
 551         /*
 552          * No window with WM_STATE property is found.
 553          * Since the window can be a plugin window reparented to the browser
 554          * toplevel, we cannot determine which window will eventually have
 555          * WM_STATE property set. So we schedule a timer callback that will
 556          * periodically attempt to find an ancestor with WM_STATE and
 557          * register the drop site appropriately.
 558          */
 559         if (toplevel == 0) {
 560             addDelayedRegistrationEntry(window);
 561             return;
 562         }
 563 
 564         if (toplevel == window) {
 565             Iterator dropTargetProtocols =
 566                 XDragAndDropProtocols.getDropTargetProtocols();
 567 
 568             while (dropTargetProtocols.hasNext()) {
 569                 XDropTargetProtocol dropTargetProtocol =
 570                     (XDropTargetProtocol)dropTargetProtocols.next();
 571                 dropTargetProtocol.registerDropTarget(toplevel);
 572             }
 573         } else {
 574             registerEmbeddedDropSite(toplevel, window);
 575         }
 576     }
 577 
 578     /*
 579      * Note: this method should be called under AWT lock.
 580      */
 581     public void unregisterDropSite(long window) {
 582         assert XToolkit.isAWTLockHeldByCurrentThread();
 583 
 584         if (window == 0) {
 585             throw new IllegalArgumentException();
 586         }
 587 
 588         long toplevel = getToplevelWindow(window);
 589 
 590         if (toplevel == window) {
 591             Iterator dropProtocols =
 592                 XDragAndDropProtocols.getDropTargetProtocols();
 593 
 594             removeDelayedRegistrationEntry(window);
 595 
 596             while (dropProtocols.hasNext()) {
 597                 XDropTargetProtocol dropProtocol = (XDropTargetProtocol)dropProtocols.next();
 598                 dropProtocol.unregisterDropTarget(window);
 599             }
 600         } else {
 601             unregisterEmbeddedDropSite(toplevel, window);
 602         }
 603     }
 604 
 605     public void registerXEmbedClient(long canvasWindow, long clientWindow) {
 606         // If the client has an associated XDnD drop site, add a drop target
 607         // to the XEmbedCanvasPeer's target to route drag notifications to the
 608         // client.
 609 
 610         XDragSourceProtocol xdndDragProtocol =
 611             XDragAndDropProtocols.getDragSourceProtocol(XDragAndDropProtocols.XDnD);
 612         XDragSourceProtocol.TargetWindowInfo info =
 613             xdndDragProtocol.getTargetWindowInfo(clientWindow);
 614         if (info != null &&
 615             info.getProtocolVersion() >= XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {
 616 
 617             if (logger.isLoggable(PlatformLogger.FINE)) {
 618                 logger.fine("        XEmbed drop site will be registered for " + Long.toHexString(clientWindow));
 619             }
 620             registerEmbeddedDropSite(canvasWindow, clientWindow);
 621 
 622             Iterator dropTargetProtocols =
 623                 XDragAndDropProtocols.getDropTargetProtocols();
 624 
 625             while (dropTargetProtocols.hasNext()) {
 626                 XDropTargetProtocol dropTargetProtocol =
 627                     (XDropTargetProtocol)dropTargetProtocols.next();
 628                 dropTargetProtocol.registerEmbeddedDropSite(clientWindow);
 629             }
 630 
 631             if (logger.isLoggable(PlatformLogger.FINE)) {
 632                 logger.fine("        XEmbed drop site has been registered for " + Long.toHexString(clientWindow));
 633             }
 634         }
 635     }
 636 
 637     public void unregisterXEmbedClient(long canvasWindow, long clientWindow) {
 638         if (logger.isLoggable(PlatformLogger.FINE)) {
 639             logger.fine("        XEmbed drop site will be unregistered for " + Long.toHexString(clientWindow));
 640         }
 641         Iterator dropTargetProtocols =
 642             XDragAndDropProtocols.getDropTargetProtocols();
 643 
 644         while (dropTargetProtocols.hasNext()) {
 645             XDropTargetProtocol dropTargetProtocol =
 646                 (XDropTargetProtocol)dropTargetProtocols.next();
 647             dropTargetProtocol.unregisterEmbeddedDropSite(clientWindow);
 648         }
 649 
 650         unregisterEmbeddedDropSite(canvasWindow, clientWindow);
 651 
 652         if (logger.isLoggable(PlatformLogger.FINE)) {
 653             logger.fine("        XEmbed drop site has beed unregistered for " + Long.toHexString(clientWindow));
 654         }
 655     }
 656 
 657     /**************** Delayed drop site registration *******************************/
 658 
 659     private void addDelayedRegistrationEntry(final long window) {
 660         Long lWindow = Long.valueOf(window);
 661         Runnable runnable = new Runnable() {
 662                 public void run() {
 663                     removeDelayedRegistrationEntry(window);
 664                     registerDropSite(window);
 665                 }
 666             };
 667 
 668         XToolkit.awtLock();
 669         try {
 670             removeDelayedRegistrationEntry(window);
 671             delayedRegistrationMap.put(lWindow, runnable);
 672             XToolkit.schedule(runnable, DELAYED_REGISTRATION_PERIOD);
 673         } finally {
 674             XToolkit.awtUnlock();
 675         }
 676     }
 677 
 678     private void removeDelayedRegistrationEntry(long window) {
 679         Long lWindow = Long.valueOf(window);
 680 
 681         XToolkit.awtLock();
 682         try {
 683             Runnable runnable = delayedRegistrationMap.remove(lWindow);
 684             if (runnable != null) {
 685                 XToolkit.remove(runnable);
 686             }
 687         } finally {
 688             XToolkit.awtUnlock();
 689         }
 690     }
 691     /*******************************************************************************/
 692 }