private boolean processProxyModeEvent(XEvent ev) {
    if (getProxyModeSourceWindow() == 0) {
      return false;
    }

    if (ev.get_type() != (int) XConstants.ClientMessage) {
      return false;
    }

    if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
      logger.finest("        proxyModeSourceWindow=" + getProxyModeSourceWindow() + " ev=" + ev);
    }

    XClientMessageEvent xclient = ev.get_xclient();

    Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
    while (dragProtocols.hasNext()) {
      XDragSourceProtocol dragProtocol = (XDragSourceProtocol) dragProtocols.next();
      if (dragProtocol.processProxyModeEvent(xclient, getProxyModeSourceWindow())) {
        return true;
      }
    }

    return false;
  }
  private void doUpdateTargetWindow(long subwindow, long time) {
    long clientWindow = 0;
    long proxyWindow = 0;
    XDragSourceProtocol protocol = null;
    boolean isReceiver = false;

    if (subwindow != 0) {
      clientWindow = findClientWindow(subwindow);
    }

    if (clientWindow != 0) {
      Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
      while (dragProtocols.hasNext()) {
        XDragSourceProtocol dragProtocol = (XDragSourceProtocol) dragProtocols.next();
        if (dragProtocol.attachTargetWindow(clientWindow, time)) {
          protocol = dragProtocol;
          break;
        }
      }
    }

    /* Update the global state. */
    dragProtocol = protocol;
    targetAction = DnDConstants.ACTION_NONE;
    targetRootSubwindow = subwindow;
  }
  private void updateTargetWindow(XMotionEvent xmotion) {
    assert XToolkit.isAWTLockHeldByCurrentThread();

    int x = xmotion.get_x_root();
    int y = xmotion.get_y_root();
    long time = xmotion.get_time();
    long subwindow = xmotion.get_subwindow();

    /*
     * If this event had occurred before the pointer was grabbed,
     * query the server for the current root subwindow.
     */
    if (xmotion.get_window() != xmotion.get_root()) {
      XlibWrapper.XQueryPointer(
          XToolkit.getDisplay(),
          xmotion.get_root(),
          XlibWrapper.larg1, // root
          XlibWrapper.larg2, // subwindow
          XlibWrapper.larg3, // x_root
          XlibWrapper.larg4, // y_root
          XlibWrapper.larg5, // x
          XlibWrapper.larg6, // y
          XlibWrapper.larg7); // modifiers
      subwindow = Native.getLong(XlibWrapper.larg2);
    }

    if (targetRootSubwindow != subwindow) {
      if (dragProtocol != null) {
        dragProtocol.sendLeaveMessage(time);

        /*
         * Neither Motif DnD nor XDnD provide a mean for the target
         * to notify the source that the pointer exits the drop site
         * that occupies the whole top level.
         * We detect this situation and post dragExit.
         */
        if (targetAction != DnDConstants.ACTION_NONE) {
          dragExit(x, y);
        }
      }

      /* Update the global state. */
      doUpdateTargetWindow(subwindow, time);

      if (dragProtocol != null) {
        dragProtocol.sendEnterMessage(sourceFormats, sourceAction, sourceActions, time);
      }
    }
  }
 private void processDrop(XButtonEvent xbutton) {
   try {
     dragProtocol.initiateDrop(
         xbutton.get_x_root(),
         xbutton.get_y_root(),
         sourceAction,
         sourceActions,
         xbutton.get_time());
   } catch (XException e) {
     cleanup(xbutton.get_time());
   }
 }
  /** The caller must own awtLock. */
  public void cleanup(long time) {
    if (dndInProgress) {
      if (dragProtocol != null) {
        dragProtocol.sendLeaveMessage(time);
      }

      if (targetAction != DnDConstants.ACTION_NONE) {
        dragExit(xRoot, yRoot);
      }

      dragDropFinished(false, DnDConstants.ACTION_NONE, xRoot, yRoot);
    }

    Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
    while (dragProtocols.hasNext()) {
      XDragSourceProtocol dragProtocol = (XDragSourceProtocol) dragProtocols.next();
      try {
        dragProtocol.cleanup();
      } catch (XException xe) {
        // Ignore the exception.
      }
    }

    dndInProgress = false;
    dragInProgress = false;
    dragRootWindow = 0;
    sourceFormats = null;
    sourceActions = DnDConstants.ACTION_NONE;
    sourceAction = DnDConstants.ACTION_NONE;
    eventState = 0;
    xRoot = 0;
    yRoot = 0;

    cleanupTargetInfo();

    removeDnDGrab(time);
  }
  /*
   * DO NOT USE is_hint field of xmotion since it could not be set when we
   * convert XKeyEvent or XButtonRelease to XMotionEvent.
   */
  private void processMouseMove(XMotionEvent xmotion) {
    if (!dragInProgress) {
      return;
    }
    if (xRoot != xmotion.get_x_root() || yRoot != xmotion.get_y_root()) {
      xRoot = xmotion.get_x_root();
      yRoot = xmotion.get_y_root();

      postDragSourceDragEvent(
          targetAction,
          XWindow.getModifiers(xmotion.get_state(), 0, 0),
          xRoot,
          yRoot,
          DISPATCH_MOUSE_MOVED);
    }

    if (eventState != xmotion.get_state()) {
      if (updateSourceAction(xmotion.get_state()) && dragProtocol != null) {
        postDragSourceDragEvent(
            targetAction,
            XWindow.getModifiers(xmotion.get_state(), 0, 0),
            xRoot,
            yRoot,
            DISPATCH_CHANGED);
      }
      eventState = xmotion.get_state();
    }

    updateTargetWindow(xmotion);

    if (dragProtocol != null) {
      dragProtocol.sendMoveMessage(
          xmotion.get_x_root(),
          xmotion.get_y_root(),
          sourceAction,
          sourceActions,
          xmotion.get_time());
    }
  }
  /**
   * The caller must own awtLock.
   *
   * @returns true if the even was processed and shouldn't be passed along.
   */
  private boolean doProcessEvent(XEvent ev) {
    assert XToolkit.isAWTLockHeldByCurrentThread();

    if (processProxyModeEvent(ev)) {
      return true;
    }

    if (!dndInProgress) {
      return false;
    }

    switch (ev.get_type()) {
      case XConstants.ClientMessage:
        {
          XClientMessageEvent xclient = ev.get_xclient();
          return processClientMessage(xclient);
        }
      case XConstants.DestroyNotify:
        {
          XDestroyWindowEvent xde = ev.get_xdestroywindow();

          /* Target crashed during drop processing - cleanup. */
          if (!dragInProgress
              && dragProtocol != null
              && xde.get_window() == dragProtocol.getTargetWindow()) {
            cleanup(XConstants.CurrentTime);
            return true;
          }
          /* Pass along */
          return false;
        }
    }

    if (!dragInProgress) {
      return false;
    }

    /* Process drag-only messages. */
    switch (ev.get_type()) {
      case XConstants.KeyRelease:
      case XConstants.KeyPress:
        {
          XKeyEvent xkey = ev.get_xkey();
          long keysym = XlibWrapper.XKeycodeToKeysym(XToolkit.getDisplay(), xkey.get_keycode(), 0);
          switch ((int) keysym) {
            case (int) XKeySymConstants.XK_Escape:
              {
                if (ev.get_type() == (int) XConstants.KeyRelease) {
                  cleanup(xkey.get_time());
                }
                break;
              }
            case (int) XKeySymConstants.XK_Control_R:
            case (int) XKeySymConstants.XK_Control_L:
            case (int) XKeySymConstants.XK_Shift_R:
            case (int) XKeySymConstants.XK_Shift_L:
              {
                XlibWrapper.XQueryPointer(
                    XToolkit.getDisplay(),
                    xkey.get_root(),
                    XlibWrapper.larg1, // root
                    XlibWrapper.larg2, // subwindow
                    XlibWrapper.larg3, // x_root
                    XlibWrapper.larg4, // y_root
                    XlibWrapper.larg5, // x
                    XlibWrapper.larg6, // y
                    XlibWrapper.larg7); // modifiers
                XMotionEvent xmotion = new XMotionEvent();
                try {
                  xmotion.set_type(XConstants.MotionNotify);
                  xmotion.set_serial(xkey.get_serial());
                  xmotion.set_send_event(xkey.get_send_event());
                  xmotion.set_display(xkey.get_display());
                  xmotion.set_window(xkey.get_window());
                  xmotion.set_root(xkey.get_root());
                  xmotion.set_subwindow(xkey.get_subwindow());
                  xmotion.set_time(xkey.get_time());
                  xmotion.set_x(xkey.get_x());
                  xmotion.set_y(xkey.get_y());
                  xmotion.set_x_root(xkey.get_x_root());
                  xmotion.set_y_root(xkey.get_y_root());
                  xmotion.set_state((int) Native.getLong(XlibWrapper.larg7));
                  // we do not use this field, so it's unset for now
                  // xmotion.set_is_hint(???);
                  xmotion.set_same_screen(xkey.get_same_screen());

                  // It's safe to use key event as motion event since we use only their common
                  // fields.
                  processMouseMove(xmotion);
                } finally {
                  xmotion.dispose();
                }
                break;
              }
          }
          return true;
        }
      case XConstants.ButtonPress:
        return true;
      case XConstants.MotionNotify:
        processMouseMove(ev.get_xmotion());
        return true;
      case XConstants.ButtonRelease:
        {
          XButtonEvent xbutton = ev.get_xbutton();
          /*
           * Ignore the buttons above 20 due to the bit limit for
           * InputEvent.BUTTON_DOWN_MASK.
           * One more bit is reserved for FIRST_HIGH_BIT.
           */
          if (xbutton.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
            return true;
          }

          /*
           * On some X servers it could happen that ButtonRelease coordinates
           * differ from the latest MotionNotify coordinates, so we need to
           * process it as a mouse motion.
           */
          XMotionEvent xmotion = new XMotionEvent();
          try {
            xmotion.set_type(XConstants.MotionNotify);
            xmotion.set_serial(xbutton.get_serial());
            xmotion.set_send_event(xbutton.get_send_event());
            xmotion.set_display(xbutton.get_display());
            xmotion.set_window(xbutton.get_window());
            xmotion.set_root(xbutton.get_root());
            xmotion.set_subwindow(xbutton.get_subwindow());
            xmotion.set_time(xbutton.get_time());
            xmotion.set_x(xbutton.get_x());
            xmotion.set_y(xbutton.get_y());
            xmotion.set_x_root(xbutton.get_x_root());
            xmotion.set_y_root(xbutton.get_y_root());
            xmotion.set_state(xbutton.get_state());
            // we do not use this field, so it's unset for now
            // xmotion.set_is_hint(???);
            xmotion.set_same_screen(xbutton.get_same_screen());

            // It's safe to use key event as motion event since we use only their common fields.
            processMouseMove(xmotion);
          } finally {
            xmotion.dispose();
          }
          if (xbutton.get_button() == XConstants.buttons[0]
              || xbutton.get_button() == XConstants.buttons[1]) {
            // drag is initiated with Button1 or Button2 pressed and
            // ended on release of either of these buttons (as the same
            // behavior was with our old Motif DnD-based implementation)
            removeDnDGrab(xbutton.get_time());
            dragInProgress = false;
            if (dragProtocol != null && targetAction != DnDConstants.ACTION_NONE) {
              /*
               * ACTION_NONE indicates that either the drop target rejects the
               * drop or it haven't responded yet. The latter could happen in
               * case of fast drag, slow target-server connection or slow
               * drag notifications processing on the target side.
               */
              processDrop(xbutton);
            } else {
              cleanup(xbutton.get_time());
            }
          }
          return true;
        }
    }

    return false;
  }
 private boolean processClientMessage(XClientMessageEvent xclient) {
   if (dragProtocol != null) {
     return dragProtocol.processClientMessage(xclient);
   }
   return false;
 }
  protected void startDrag(Transferable transferable, long[] formats, Map formatMap) {
    Component component = getTrigger().getComponent();
    Component c = null;
    XWindowPeer wpeer = null;

    for (c = component;
        c != null && !(c instanceof Window);
        c = AWTAccessor.getComponentAccessor().getParent(c)) ;

    if (c instanceof Window) {
      wpeer = (XWindowPeer) c.getPeer();
    }

    if (wpeer == null) {
      throw new InvalidDnDOperationException("Cannot find top-level for the drag source component");
    }

    long xcursor = 0;
    long rootWindow = 0;
    long dragWindow = 0;
    long timeStamp = 0;

    /* Retrieve the X cursor for the drag operation. */
    {
      Cursor cursor = getCursor();
      if (cursor != null) {
        xcursor = XGlobalCursorManager.getCursor(cursor);
      }
    }

    XToolkit.awtLock();
    try {
      if (proxyModeSourceWindow != 0) {
        throw new InvalidDnDOperationException("Proxy drag in progress");
      }
      if (dndInProgress) {
        throw new InvalidDnDOperationException("Drag in progress");
      }

      /* Determine the root window for the drag operation. */
      {
        long screen = XlibWrapper.XScreenNumberOfScreen(wpeer.getScreen());
        rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen);
      }

      dragWindow = XWindow.getXAWTRootWindow().getWindow();

      timeStamp = XToolkit.getCurrentServerTime();

      int dropActions = getDragSourceContext().getSourceActions();

      Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
      while (dragProtocols.hasNext()) {
        XDragSourceProtocol dragProtocol = (XDragSourceProtocol) dragProtocols.next();
        try {
          dragProtocol.initializeDrag(
              dropActions, transferable,
              formatMap, formats);
        } catch (XException xe) {
          throw (InvalidDnDOperationException) new InvalidDnDOperationException().initCause(xe);
        }
      }

      /* Install X grabs. */
      {
        int status;
        XWindowAttributes wattr = new XWindowAttributes();
        try {
          status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), rootWindow, wattr.pData);

          if (status == 0) {
            throw new InvalidDnDOperationException("XGetWindowAttributes failed");
          }

          rootEventMask = wattr.get_your_event_mask();

          XlibWrapper.XSelectInput(
              XToolkit.getDisplay(), rootWindow, rootEventMask | ROOT_EVENT_MASK);
        } finally {
          wattr.dispose();
        }

        XBaseWindow.ungrabInput();

        status =
            XlibWrapper.XGrabPointer(
                XToolkit.getDisplay(),
                rootWindow,
                0,
                GRAB_EVENT_MASK,
                XConstants.GrabModeAsync,
                XConstants.GrabModeAsync,
                XConstants.None,
                xcursor,
                timeStamp);

        if (status != XConstants.GrabSuccess) {
          cleanup(timeStamp);
          throwGrabFailureException("Cannot grab pointer", status);
          return;
        }

        status =
            XlibWrapper.XGrabKeyboard(
                XToolkit.getDisplay(),
                rootWindow,
                0,
                XConstants.GrabModeAsync,
                XConstants.GrabModeAsync,
                timeStamp);

        if (status != XConstants.GrabSuccess) {
          cleanup(timeStamp);
          throwGrabFailureException("Cannot grab keyboard", status);
          return;
        }
      }

      /* Update the global state. */
      dndInProgress = true;
      dragInProgress = true;
      dragRootWindow = rootWindow;
      sourceActions = dropActions;
      sourceFormats = formats;
    } finally {
      XToolkit.awtUnlock();
    }

    /* This implementation doesn't use native context */
    setNativeContext(0);

    SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(transferable);
  }