1 /*
2  * Copyright (c) 2003, 2013, 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 
XDropTargetRegistry()56     private XDropTargetRegistry() {}
57 
getRegistry()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      */
getToplevelWindow(long window)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 
getDnDProxyWindow()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 
EmbeddedDropSiteEntry(long root, long event_mask, List<XDropTargetProtocol> supportedProtocols)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 
getRoot()110         public long getRoot() {
111             return root;
112         }
getEventMask()113         public long getEventMask() {
114             return event_mask;
115         }
hasNonXEmbedClientSites()116         public boolean hasNonXEmbedClientSites() {
117             return !nonXEmbedClientSites.isEmpty();
118         }
addSite(long window, boolean isXEmbedClient)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         }
removeSite(long window)128         public synchronized void removeSite(long window) {
129             Long lWindow = Long.valueOf(window);
130             sites.remove(lWindow);
131             nonXEmbedClientSites.remove(lWindow);
132         }
setSupportedProtocols(List<XDropTargetProtocol> list)133         public void setSupportedProtocols(List<XDropTargetProtocol> list) {
134             supportedProtocols = list;
135         }
getSupportedProtocols()136         public List<XDropTargetProtocol> getSupportedProtocols() {
137             return supportedProtocols;
138         }
hasSites()139         public boolean hasSites() {
140             return !sites.isEmpty();
141         }
getSites()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         }
getSite(int x, int y)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 
registerEmbedderDropSite(long embedder)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 
registerProtocols(long embedder, boolean protocols, List<XDropTargetProtocol> supportedProtocols)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 
updateEmbedderDropSite(long embedder)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 
unregisterEmbedderDropSite(long embedder, EmbeddedDropSiteEntry entry)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                 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
398                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
399                                          event_mask);
400                 XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
401 
402                 if ((XErrorHandlerUtil.saved_error != null) &&
403                     (XErrorHandlerUtil.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 
registerEmbeddedDropSite(long toplevel, long window)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 
unregisterEmbeddedDropSite(long toplevel, long window)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      */
getEmbeddedDropSite(long embedder, int x, int y)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      */
registerDropSite(long window)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      */
unregisterDropSite(long window)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 
registerXEmbedClient(long canvasWindow, long clientWindow)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.Level.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.Level.FINE)) {
632                 logger.fine("        XEmbed drop site has been registered for " + Long.toHexString(clientWindow));
633             }
634         }
635     }
636 
unregisterXEmbedClient(long canvasWindow, long clientWindow)637     public void unregisterXEmbedClient(long canvasWindow, long clientWindow) {
638         if (logger.isLoggable(PlatformLogger.Level.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.Level.FINE)) {
653             logger.fine("        XEmbed drop site has beed unregistered for " + Long.toHexString(clientWindow));
654         }
655     }
656 
657     /**************** Delayed drop site registration *******************************/
658 
addDelayedRegistrationEntry(final long window)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 
removeDelayedRegistrationEntry(long window)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 }
693