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