1 /*
   2  * Copyright (c) 2003, 2014, 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      * hierarchy 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                         XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 172                         int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 173                                                                       window, wattr.pData);
 174                         XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 175 
 176                         if ((status == 0) ||
 177                             ((XErrorHandlerUtil.saved_error != null) &&
 178                             (XErrorHandlerUtil.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                 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 226                 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 227                                                               embedder, wattr.pData);
 228                 XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 229 
 230                 if ((status == 0) ||
 231                     ((XErrorHandlerUtil.saved_error != null) &&
 232                     (XErrorHandlerUtil.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                 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 244                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
 245                                          event_mask | XConstants.PropertyChangeMask);
 246                 XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 247 
 248                 if ((XErrorHandlerUtil.saved_error != null) &&
 249                     (XErrorHandlerUtil.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 = embeddedDropSiteRegistry.get(lToplevel);
 332             if (entry == null) {
 333                 return;
 334             }
 335             entry.setSupportedProtocols(embedderProtocols);
 336             isXEmbedServer = !entry.hasNonXEmbedClientSites();
 337         }
 338 
 339         /*
 340          * By default, we register a drop site that supports all dnd
 341          * protocols. This approach is not appropriate in plugin
 342          * scenario if the browser supports Motif DnD and doesn't support
 343          * XDnD. If we forcibly set XdndAware on the browser toplevel, any drag
 344          * source that supports both protocols and prefers XDnD will be unable
 345          * to drop anything on the browser.
 346          * The solution for this problem is not to register XDnD drop site
 347          * if the browser supports only Motif DnD.
 348          * In general, if the browser already supports some protocols, we
 349          * register the embedded drop site only for those protocols. Otherwise
 350          * we register the embedded drop site for all protocols.
 351          */
 352         if (!embedderProtocols.isEmpty()) {
 353             dropTargetProtocols = embedderProtocols.iterator();
 354         } else {
 355             dropTargetProtocols =
 356                 XDragAndDropProtocols.getDropTargetProtocols();
 357         }
 358 
 359         /* Grab server, since we are working with the window that belongs to
 360            another client. */
 361         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 362         try {
 363             while (dropTargetProtocols.hasNext()) {
 364                 XDropTargetProtocol dropTargetProtocol =
 365                     (XDropTargetProtocol)dropTargetProtocols.next();
 366                 if (!isXEmbedServer || !dropTargetProtocol.isXEmbedSupported()) {
 367                     dropTargetProtocol.registerEmbedderDropSite(embedder);
 368                 }
 369             }
 370         } finally {
 371             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 372         }
 373     }
 374 
 375     private void unregisterEmbedderDropSite(long embedder,
 376                                             EmbeddedDropSiteEntry entry) {
 377         assert XToolkit.isAWTLockHeldByCurrentThread();
 378 
 379         Iterator dropTargetProtocols =
 380             XDragAndDropProtocols.getDropTargetProtocols();
 381 
 382         /* Grab server, since we are working with the window that belongs to
 383            another client. */
 384         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 385         try {
 386             while (dropTargetProtocols.hasNext()) {
 387                 XDropTargetProtocol dropTargetProtocol =
 388                     (XDropTargetProtocol)dropTargetProtocols.next();
 389                 dropTargetProtocol.unregisterEmbedderDropSite(embedder);
 390             }
 391 
 392             long event_mask = entry.getEventMask();
 393 
 394             /* Restore the original event mask for the embedder. */
 395             if ((event_mask & XConstants.PropertyChangeMask) == 0) {
 396                 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 397                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
 398                                          event_mask);
 399                 XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 400 
 401                 if ((XErrorHandlerUtil.saved_error != null) &&
 402                     (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
 403                     throw new XException("XSelectInput failed");
 404                 }
 405             }
 406         } finally {
 407             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 408         }
 409     }
 410 
 411     private void registerEmbeddedDropSite(long toplevel, long window) {
 412         XBaseWindow xBaseWindow = XToolkit.windowToXWindow(window);
 413         boolean isXEmbedClient =
 414             (xBaseWindow instanceof XEmbeddedFramePeer) &&
 415             ((XEmbeddedFramePeer)xBaseWindow).isXEmbedActive();
 416 
 417         XEmbedCanvasPeer peer = null;
 418         {
 419             XBaseWindow xbaseWindow = XToolkit.windowToXWindow(toplevel);
 420             if (xbaseWindow != null) {
 421                 if (xbaseWindow instanceof XEmbedCanvasPeer) {
 422                     peer = (XEmbedCanvasPeer)xbaseWindow;
 423                 } else {
 424                     throw new UnsupportedOperationException();
 425                 }
 426             }
 427         }
 428 
 429         Long lToplevel = Long.valueOf(toplevel);
 430         EmbeddedDropSiteEntry entry = null;
 431         synchronized (this) {
 432             entry = embeddedDropSiteRegistry.get(lToplevel);
 433             if (entry == null) {
 434                 if (peer != null) {
 435                     // Toplevel is an XEmbed server within this VM.
 436                     // Register an XEmbed drop site.
 437                     peer.setXEmbedDropTarget();
 438                     // Create a dummy entry to register the embedded site.
 439                     entry = new EmbeddedDropSiteEntry(0, 0,
 440                                                       Collections.<XDropTargetProtocol>emptyList());
 441                 } else {
 442                     // Foreign toplevel.
 443                     // Select for PropertyNotify events on the toplevel, so that
 444                     // we can track changes of the properties relevant to DnD
 445                     // protocols.
 446                     entry = registerEmbedderDropSite(toplevel);
 447                     // Register the toplevel with all DnD protocols that are not
 448                     // supported by XEmbed - actually setup a proxy, so that
 449                     // all DnD notifications sent to the toplevel are first
 450                     // routed to us.
 451                     registerProtocols(toplevel, NON_XEMBED_PROTOCOLS,
 452                                       entry.getSupportedProtocols());
 453                 }
 454                 embeddedDropSiteRegistry.put(lToplevel, entry);
 455             }
 456         }
 457 
 458         assert entry != null;
 459 
 460         synchronized (entry) {
 461             // For a foreign toplevel.
 462             if (peer == null) {
 463                 if (!isXEmbedClient) {
 464                     // Since this is not an XEmbed client we can no longer rely
 465                     // on XEmbed to route DnD notifications even for DnD
 466                     // protocols that are supported by XEmbed.
 467                     // We rollback to the XEmbed-unfriendly solution - setup
 468                     // a proxy, so that all DnD notifications sent to the
 469                     // toplevel are first routed to us.
 470                     registerProtocols(toplevel, XEMBED_PROTOCOLS,
 471                                       entry.getSupportedProtocols());
 472                 } else {
 473                     Iterator dropTargetProtocols =
 474                         XDragAndDropProtocols.getDropTargetProtocols();
 475 
 476                     // Register the embedded window as a plain drop site with
 477                     // all DnD protocols that are supported by XEmbed.
 478                     while (dropTargetProtocols.hasNext()) {
 479                         XDropTargetProtocol dropTargetProtocol =
 480                             (XDropTargetProtocol)dropTargetProtocols.next();
 481                         if (dropTargetProtocol.isXEmbedSupported()) {
 482                             dropTargetProtocol.registerEmbedderDropSite(window);
 483                         }
 484                     }
 485                 }
 486             }
 487 
 488             entry.addSite(window, isXEmbedClient);
 489         }
 490     }
 491 
 492     private void unregisterEmbeddedDropSite(long toplevel, long window) {
 493         Long lToplevel = Long.valueOf(toplevel);
 494         EmbeddedDropSiteEntry entry = null;
 495         synchronized (this) {
 496             entry = embeddedDropSiteRegistry.get(lToplevel);
 497             if (entry == null) {
 498                 return;
 499             }
 500             entry.removeSite(window);
 501             if (!entry.hasSites()) {
 502                 embeddedDropSiteRegistry.remove(lToplevel);
 503 
 504                 XBaseWindow xbaseWindow = XToolkit.windowToXWindow(toplevel);
 505                 if (xbaseWindow != null) {
 506                     if (xbaseWindow instanceof XEmbedCanvasPeer) {
 507                         XEmbedCanvasPeer peer = (XEmbedCanvasPeer)xbaseWindow;
 508                         // Unregister an XEmbed drop site.
 509                         peer.removeXEmbedDropTarget();
 510                     } else {
 511                         throw new UnsupportedOperationException();
 512                     }
 513                 } else {
 514                     unregisterEmbedderDropSite(toplevel, entry);
 515                 }
 516             }
 517         }
 518     }
 519 
 520     /*
 521      * Returns a drop site that is embedded in the specified embedder window and
 522      * contains the point with the specified root coordinates.
 523      */
 524     public long getEmbeddedDropSite(long embedder, int x, int y) {
 525         Long lToplevel = Long.valueOf(embedder);
 526         EmbeddedDropSiteEntry entry = embeddedDropSiteRegistry.get(lToplevel);
 527         if (entry == null) {
 528             return 0;
 529         }
 530         return entry.getSite(x, y);
 531     }
 532 
 533     /*
 534      * Note: this method should be called under AWT lock.
 535      */
 536     public void registerDropSite(long window) {
 537         assert XToolkit.isAWTLockHeldByCurrentThread();
 538 
 539         if (window == 0) {
 540             throw new IllegalArgumentException();
 541         }
 542 
 543         XDropTargetEventProcessor.activate();
 544 
 545         long toplevel = getToplevelWindow(window);
 546 
 547         /*
 548          * No window with WM_STATE property is found.
 549          * Since the window can be a plugin window reparented to the browser
 550          * toplevel, we cannot determine which window will eventually have
 551          * WM_STATE property set. So we schedule a timer callback that will
 552          * periodically attempt to find an ancestor with WM_STATE and
 553          * register the drop site appropriately.
 554          */
 555         if (toplevel == 0) {
 556             addDelayedRegistrationEntry(window);
 557             return;
 558         }
 559 
 560         if (toplevel == window) {
 561             Iterator dropTargetProtocols =
 562                 XDragAndDropProtocols.getDropTargetProtocols();
 563 
 564             while (dropTargetProtocols.hasNext()) {
 565                 XDropTargetProtocol dropTargetProtocol =
 566                     (XDropTargetProtocol)dropTargetProtocols.next();
 567                 dropTargetProtocol.registerDropTarget(toplevel);
 568             }
 569         } else {
 570             registerEmbeddedDropSite(toplevel, window);
 571         }
 572     }
 573 
 574     /*
 575      * Note: this method should be called under AWT lock.
 576      */
 577     public void unregisterDropSite(long window) {
 578         assert XToolkit.isAWTLockHeldByCurrentThread();
 579 
 580         if (window == 0) {
 581             throw new IllegalArgumentException();
 582         }
 583 
 584         long toplevel = getToplevelWindow(window);
 585 
 586         if (toplevel == window) {
 587             Iterator dropProtocols =
 588                 XDragAndDropProtocols.getDropTargetProtocols();
 589 
 590             removeDelayedRegistrationEntry(window);
 591 
 592             while (dropProtocols.hasNext()) {
 593                 XDropTargetProtocol dropProtocol = (XDropTargetProtocol)dropProtocols.next();
 594                 dropProtocol.unregisterDropTarget(window);
 595             }
 596         } else {
 597             unregisterEmbeddedDropSite(toplevel, window);
 598         }
 599     }
 600 
 601     public void registerXEmbedClient(long canvasWindow, long clientWindow) {
 602         // If the client has an associated XDnD drop site, add a drop target
 603         // to the XEmbedCanvasPeer's target to route drag notifications to the
 604         // client.
 605 
 606         XDragSourceProtocol xdndDragProtocol =
 607             XDragAndDropProtocols.getDragSourceProtocol(XDragAndDropProtocols.XDnD);
 608         XDragSourceProtocol.TargetWindowInfo info =
 609             xdndDragProtocol.getTargetWindowInfo(clientWindow);
 610         if (info != null &&
 611             info.getProtocolVersion() >= XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {
 612 
 613             if (logger.isLoggable(PlatformLogger.Level.FINE)) {
 614                 logger.fine("        XEmbed drop site will be registered for " + Long.toHexString(clientWindow));
 615             }
 616             registerEmbeddedDropSite(canvasWindow, clientWindow);
 617 
 618             Iterator dropTargetProtocols =
 619                 XDragAndDropProtocols.getDropTargetProtocols();
 620 
 621             while (dropTargetProtocols.hasNext()) {
 622                 XDropTargetProtocol dropTargetProtocol =
 623                     (XDropTargetProtocol)dropTargetProtocols.next();
 624                 dropTargetProtocol.registerEmbeddedDropSite(clientWindow);
 625             }
 626 
 627             if (logger.isLoggable(PlatformLogger.Level.FINE)) {
 628                 logger.fine("        XEmbed drop site has been registered for " + Long.toHexString(clientWindow));
 629             }
 630         }
 631     }
 632 
 633     public void unregisterXEmbedClient(long canvasWindow, long clientWindow) {
 634         if (logger.isLoggable(PlatformLogger.Level.FINE)) {
 635             logger.fine("        XEmbed drop site will be unregistered for " + Long.toHexString(clientWindow));
 636         }
 637         Iterator dropTargetProtocols =
 638             XDragAndDropProtocols.getDropTargetProtocols();
 639 
 640         while (dropTargetProtocols.hasNext()) {
 641             XDropTargetProtocol dropTargetProtocol =
 642                 (XDropTargetProtocol)dropTargetProtocols.next();
 643             dropTargetProtocol.unregisterEmbeddedDropSite(clientWindow);
 644         }
 645 
 646         unregisterEmbeddedDropSite(canvasWindow, clientWindow);
 647 
 648         if (logger.isLoggable(PlatformLogger.Level.FINE)) {
 649             logger.fine("        XEmbed drop site has beed unregistered for " + Long.toHexString(clientWindow));
 650         }
 651     }
 652 
 653     /**************** Delayed drop site registration *******************************/
 654 
 655     private void addDelayedRegistrationEntry(final long window) {
 656         Long lWindow = Long.valueOf(window);
 657         Runnable runnable = new Runnable() {
 658                 public void run() {
 659                     removeDelayedRegistrationEntry(window);
 660                     registerDropSite(window);
 661                 }
 662             };
 663 
 664         XToolkit.awtLock();
 665         try {
 666             removeDelayedRegistrationEntry(window);
 667             delayedRegistrationMap.put(lWindow, runnable);
 668             XToolkit.schedule(runnable, DELAYED_REGISTRATION_PERIOD);
 669         } finally {
 670             XToolkit.awtUnlock();
 671         }
 672     }
 673 
 674     private void removeDelayedRegistrationEntry(long window) {
 675         Long lWindow = Long.valueOf(window);
 676 
 677         XToolkit.awtLock();
 678         try {
 679             Runnable runnable = delayedRegistrationMap.remove(lWindow);
 680             if (runnable != null) {
 681                 XToolkit.remove(runnable);
 682             }
 683         } finally {
 684             XToolkit.awtUnlock();
 685         }
 686     }
 687     /*******************************************************************************/
 688 }