Ejemplo n.º 1
0
  private static void writeLogRecords(PrintStream logps) throws Exception {
    PrintStream err = System.err;
    try {
      System.setErr(logps);

      Object[] params = new Object[] {new Long(1), "string"};
      PlatformLogger plog = PlatformLogger.getLogger("test.log.foo");
      plog.severe("Log message {0} {1}", (Object[]) params);

      // create a java.util.logging.Logger
      // now java.util.logging.Logger should be created for each platform
      // logger
      Logger logger = Logger.getLogger("test.log.bar");
      logger.log(Level.SEVERE, "Log message {0} {1}", params);

      plog.severe("Log message {0} {1}", (Object[]) params);
    } finally {
      logps.flush();
      logps.close();
      System.setErr(err);
    }
  }
Ejemplo n.º 2
0
public class CPlatformWindow extends CFRetainedResource implements PlatformWindow {
  private native long nativeCreateNSWindow(
      long nsViewPtr, long ownerPtr, long styleBits, double x, double y, double w, double h);

  private static native void nativeSetNSWindowStyleBits(long nsWindowPtr, int mask, int data);

  private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr);

  private static native Insets nativeGetNSWindowInsets(long nsWindowPtr);

  private static native void nativeSetNSWindowBounds(
      long nsWindowPtr, double x, double y, double w, double h);

  private static native void nativeSetNSWindowLocationByPlatform(long nsWindowPtr);

  private static native void nativeSetNSWindowStandardFrame(
      long nsWindowPtr, double x, double y, double w, double h);

  private static native void nativeSetNSWindowMinMax(
      long nsWindowPtr, double minW, double minH, double maxW, double maxH);

  private static native void nativePushNSWindowToBack(long nsWindowPtr);

  private static native void nativePushNSWindowToFront(long nsWindowPtr);

  private static native void nativeSetNSWindowTitle(long nsWindowPtr, String title);

  private static native void nativeRevalidateNSWindowShadow(long nsWindowPtr);

  private static native void nativeSetNSWindowMinimizedIcon(long nsWindowPtr, long nsImage);

  private static native void nativeSetNSWindowRepresentedFilename(
      long nsWindowPtr, String representedFilename);

  private static native void nativeSetEnabled(long nsWindowPtr, boolean isEnabled);

  private static native void nativeSynthesizeMouseEnteredExitedEvents();

  private static native void nativeSynthesizeMouseEnteredExitedEvents(
      long nsWindowPtr, int eventType);

  private static native void nativeDispose(long nsWindowPtr);

  private static native void nativeEnterFullScreenMode(long nsWindowPtr);

  private static native void nativeExitFullScreenMode(long nsWindowPtr);

  static native CPlatformWindow nativeGetTopmostPlatformWindowUnderMouse();

  // Loger to report issues happened during execution but that do not affect functionality
  private static final PlatformLogger logger =
      PlatformLogger.getLogger("sun.lwawt.macosx.CPlatformWindow");
  private static final PlatformLogger focusLogger =
      PlatformLogger.getLogger("sun.lwawt.macosx.focus.CPlatformWindow");

  // for client properties
  public static final String WINDOW_BRUSH_METAL_LOOK = "apple.awt.brushMetalLook";
  public static final String WINDOW_DRAGGABLE_BACKGROUND = "apple.awt.draggableWindowBackground";

  public static final String WINDOW_ALPHA = "Window.alpha";
  public static final String WINDOW_SHADOW = "Window.shadow";

  public static final String WINDOW_STYLE = "Window.style";
  public static final String WINDOW_SHADOW_REVALIDATE_NOW = "apple.awt.windowShadow.revalidateNow";

  public static final String WINDOW_DOCUMENT_MODIFIED = "Window.documentModified";
  public static final String WINDOW_DOCUMENT_FILE = "Window.documentFile";

  public static final String WINDOW_CLOSEABLE = "Window.closeable";
  public static final String WINDOW_MINIMIZABLE = "Window.minimizable";
  public static final String WINDOW_ZOOMABLE = "Window.zoomable";
  public static final String WINDOW_HIDES_ON_DEACTIVATE = "Window.hidesOnDeactivate";

  public static final String WINDOW_DOC_MODAL_SHEET = "apple.awt.documentModalSheet";
  public static final String WINDOW_FADE_DELEGATE = "apple.awt._windowFadeDelegate";
  public static final String WINDOW_FADE_IN = "apple.awt._windowFadeIn";
  public static final String WINDOW_FADE_OUT = "apple.awt._windowFadeOut";
  public static final String WINDOW_FULLSCREENABLE = "apple.awt.fullscreenable";

  // Yeah, I know. But it's easier to deal with ints from JNI
  static final int MODELESS = 0;
  static final int DOCUMENT_MODAL = 1;
  static final int APPLICATION_MODAL = 2;
  static final int TOOLKIT_MODAL = 3;

  // window style bits
  static final int _RESERVED_FOR_DATA = 1 << 0;

  // corresponds to native style mask bits
  static final int DECORATED = 1 << 1;
  static final int TEXTURED = 1 << 2;
  static final int UNIFIED = 1 << 3;
  static final int UTILITY = 1 << 4;
  static final int HUD = 1 << 5;
  static final int SHEET = 1 << 6;

  static final int CLOSEABLE = 1 << 7;
  static final int MINIMIZABLE = 1 << 8;

  static final int RESIZABLE = 1 << 9; // both a style bit and prop bit
  static final int NONACTIVATING = 1 << 24;
  static final int IS_DIALOG = 1 << 25;
  static final int IS_MODAL = 1 << 26;
  static final int IS_POPUP = 1 << 27;

  static final int _STYLE_PROP_BITMASK =
      DECORATED | TEXTURED | UNIFIED | UTILITY | HUD | SHEET | CLOSEABLE | MINIMIZABLE | RESIZABLE;

  // corresponds to method-based properties
  static final int HAS_SHADOW = 1 << 10;
  static final int ZOOMABLE = 1 << 11;

  static final int ALWAYS_ON_TOP = 1 << 15;
  static final int HIDES_ON_DEACTIVATE = 1 << 17;
  static final int DRAGGABLE_BACKGROUND = 1 << 19;
  static final int DOCUMENT_MODIFIED = 1 << 21;
  static final int FULLSCREENABLE = 1 << 23;

  static final int _METHOD_PROP_BITMASK =
      RESIZABLE
          | HAS_SHADOW
          | ZOOMABLE
          | ALWAYS_ON_TOP
          | HIDES_ON_DEACTIVATE
          | DRAGGABLE_BACKGROUND
          | DOCUMENT_MODIFIED
          | FULLSCREENABLE;

  // corresponds to callback-based properties
  static final int SHOULD_BECOME_KEY = 1 << 12;
  static final int SHOULD_BECOME_MAIN = 1 << 13;
  static final int MODAL_EXCLUDED = 1 << 16;

  static final int _CALLBACK_PROP_BITMASK = SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN | MODAL_EXCLUDED;

  static int SET(final int bits, final int mask, final boolean value) {
    if (value) return (bits | mask);
    return bits & ~mask;
  }

  static boolean IS(final int bits, final int mask) {
    return (bits & mask) != 0;
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  static ClientPropertyApplicator<JRootPane, CPlatformWindow> CLIENT_PROPERTY_APPLICATOR =
      new ClientPropertyApplicator<JRootPane, CPlatformWindow>(
          new Property[] {
            new Property<CPlatformWindow>(WINDOW_DOCUMENT_MODIFIED) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                c.setStyleBits(
                    DOCUMENT_MODIFIED,
                    value == null ? false : Boolean.parseBoolean(value.toString()));
              }
            },
            new Property<CPlatformWindow>(WINDOW_BRUSH_METAL_LOOK) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                c.setStyleBits(TEXTURED, Boolean.parseBoolean(value.toString()));
              }
            },
            new Property<CPlatformWindow>(WINDOW_ALPHA) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                AWTUtilities.setWindowOpacity(
                    c.target, value == null ? 1.0f : Float.parseFloat(value.toString()));
              }
            },
            new Property<CPlatformWindow>(WINDOW_SHADOW) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                c.setStyleBits(
                    HAS_SHADOW, value == null ? true : Boolean.parseBoolean(value.toString()));
              }
            },
            new Property<CPlatformWindow>(WINDOW_MINIMIZABLE) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                c.setStyleBits(MINIMIZABLE, Boolean.parseBoolean(value.toString()));
              }
            },
            new Property<CPlatformWindow>(WINDOW_CLOSEABLE) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                c.setStyleBits(CLOSEABLE, Boolean.parseBoolean(value.toString()));
              }
            },
            new Property<CPlatformWindow>(WINDOW_ZOOMABLE) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                boolean zoomable = Boolean.parseBoolean(value.toString());
                if (c.target instanceof RootPaneContainer
                    && c.getPeer().getPeerType() == PeerType.FRAME) {
                  if (c.isInFullScreen && !zoomable) {
                    c.toggleFullScreen();
                  }
                }
                c.setStyleBits(ZOOMABLE, zoomable);
              }
            },
            new Property<CPlatformWindow>(WINDOW_FULLSCREENABLE) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                boolean fullscrenable = Boolean.parseBoolean(value.toString());
                if (c.target instanceof RootPaneContainer
                    && c.getPeer().getPeerType() == PeerType.FRAME) {
                  if (c.isInFullScreen && !fullscrenable) {
                    c.toggleFullScreen();
                  }
                }
                c.setStyleBits(FULLSCREENABLE, fullscrenable);
              }
            },
            new Property<CPlatformWindow>(WINDOW_SHADOW_REVALIDATE_NOW) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                nativeRevalidateNSWindowShadow(c.getNSWindowPtr());
              }
            },
            new Property<CPlatformWindow>(WINDOW_DOCUMENT_FILE) {
              public void applyProperty(final CPlatformWindow c, final Object value) {
                if (value == null || !(value instanceof java.io.File)) {
                  nativeSetNSWindowRepresentedFilename(c.getNSWindowPtr(), null);
                  return;
                }

                final String filename = ((java.io.File) value).getAbsolutePath();
                nativeSetNSWindowRepresentedFilename(c.getNSWindowPtr(), filename);
              }
            }
          }) {
        @SuppressWarnings("deprecation")
        public CPlatformWindow convertJComponentToTarget(final JRootPane p) {
          Component root = SwingUtilities.getRoot(p);
          final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
          if (root == null || acc.getPeer(root) == null) return null;
          return (CPlatformWindow) ((LWWindowPeer) acc.getPeer(root)).getPlatformWindow();
        }
      };

  // Bounds of the native widget but in the Java coordinate system.
  // In order to keep it up-to-date we will update them on
  // 1) setting native bounds via nativeSetBounds() call
  // 2) getting notification from the native level via deliverMoveResizeEvent()
  private Rectangle nativeBounds = new Rectangle(0, 0, 0, 0);
  private volatile boolean isFullScreenMode;
  private boolean isFullScreenAnimationOn;

  private volatile boolean isInFullScreen;

  private Window target;
  private LWWindowPeer peer;
  protected CPlatformView contentView;
  protected CPlatformWindow owner;
  protected boolean visible = false; // visibility status from native perspective
  private boolean undecorated; // initialized in getInitialStyleBits()
  private Rectangle normalBounds = null; // not-null only for undecorated maximized windows
  private CPlatformResponder responder;

  public CPlatformWindow() {
    super(0, true);
  }

  /*
   * Delegate initialization (create native window and all the
   * related resources).
   */
  @Override // PlatformWindow
  public void initialize(Window _target, LWWindowPeer _peer, PlatformWindow _owner) {
    initializeBase(_target, _peer, _owner, new CPlatformView());

    final int styleBits = getInitialStyleBits();

    responder = createPlatformResponder();
    contentView = createContentView();
    contentView.initialize(peer, responder);

    final long ownerPtr = owner != null ? owner.getNSWindowPtr() : 0L;
    Rectangle bounds;
    if (!IS(DECORATED, styleBits)) {
      // For undecorated frames the move/resize event does not come if the frame is centered on the
      // screen
      // so we need to set a stub location to force an initial move/resize. Real bounds would be set
      // later.
      bounds = new Rectangle(0, 0, 1, 1);
    } else {
      bounds = _peer.constrainBounds(_target.getBounds());
    }
    final long nativeWindowPtr =
        nativeCreateNSWindow(
            contentView.getAWTView(),
            ownerPtr,
            styleBits,
            bounds.x,
            bounds.y,
            bounds.width,
            bounds.height);
    setPtr(nativeWindowPtr);

    if (target instanceof javax.swing.RootPaneContainer) {
      final javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer) target).getRootPane();
      if (rootpane != null)
        rootpane.addPropertyChangeListener(
            "ancestor",
            new PropertyChangeListener() {
              public void propertyChange(final PropertyChangeEvent evt) {
                CLIENT_PROPERTY_APPLICATOR.attachAndApplyClientProperties(rootpane);
                rootpane.removePropertyChangeListener("ancestor", this);
              }
            });
    }

    validateSurface();
  }

  protected void initializeBase(
      Window target, LWWindowPeer peer, PlatformWindow owner, CPlatformView view) {
    this.peer = peer;
    this.target = target;
    if (owner instanceof CPlatformWindow) {
      this.owner = (CPlatformWindow) owner;
    }
    this.contentView = view;
  }

  protected CPlatformResponder createPlatformResponder() {
    return new CPlatformResponder(peer, false);
  }

  protected CPlatformView createContentView() {
    return new CPlatformView();
  }

  protected int getInitialStyleBits() {
    // defaults style bits
    int styleBits = DECORATED | HAS_SHADOW | CLOSEABLE | MINIMIZABLE | ZOOMABLE | RESIZABLE;

    if (isNativelyFocusableWindow()) {
      styleBits = SET(styleBits, SHOULD_BECOME_KEY, true);
      styleBits = SET(styleBits, SHOULD_BECOME_MAIN, true);
    }

    final boolean isFrame = (target instanceof Frame);
    final boolean isDialog = (target instanceof Dialog);
    final boolean isPopup = (target.getType() == Window.Type.POPUP);
    if (isDialog) {
      styleBits = SET(styleBits, MINIMIZABLE, false);
    }

    // Either java.awt.Frame or java.awt.Dialog can be undecorated, however java.awt.Window always
    // is undecorated.
    {
      this.undecorated =
          isFrame
              ? ((Frame) target).isUndecorated()
              : (isDialog ? ((Dialog) target).isUndecorated() : true);
      if (this.undecorated) styleBits = SET(styleBits, DECORATED, false);
    }

    // Either java.awt.Frame or java.awt.Dialog can be resizable, however java.awt.Window is never
    // resizable
    {
      final boolean resizable =
          isFrame
              ? ((Frame) target).isResizable()
              : (isDialog ? ((Dialog) target).isResizable() : false);
      styleBits = SET(styleBits, RESIZABLE, resizable);
      if (!resizable) {
        styleBits = SET(styleBits, ZOOMABLE, false);
      } else {
        setCanFullscreen(true);
      }
    }

    if (target.isAlwaysOnTop()) {
      styleBits = SET(styleBits, ALWAYS_ON_TOP, true);
    }

    if (target.getModalExclusionType() == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) {
      styleBits = SET(styleBits, MODAL_EXCLUDED, true);
    }

    // If the target is a dialog, popup or tooltip we want it to ignore the brushed metal look.
    if (isPopup) {
      styleBits = SET(styleBits, TEXTURED, false);
      // Popups in applets don't activate applet's process
      styleBits = SET(styleBits, NONACTIVATING, true);
      styleBits = SET(styleBits, IS_POPUP, true);
    }

    if (Window.Type.UTILITY.equals(target.getType())) {
      styleBits = SET(styleBits, UTILITY, true);
    }

    if (target instanceof javax.swing.RootPaneContainer) {
      javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer) target).getRootPane();
      Object prop = null;

      prop = rootpane.getClientProperty(WINDOW_BRUSH_METAL_LOOK);
      if (prop != null) {
        styleBits = SET(styleBits, TEXTURED, Boolean.parseBoolean(prop.toString()));
      }

      if (isDialog && ((Dialog) target).getModalityType() == ModalityType.DOCUMENT_MODAL) {
        prop = rootpane.getClientProperty(WINDOW_DOC_MODAL_SHEET);
        if (prop != null) {
          styleBits = SET(styleBits, SHEET, Boolean.parseBoolean(prop.toString()));
        }
      }

      prop = rootpane.getClientProperty(WINDOW_STYLE);
      if (prop != null) {
        if ("small".equals(prop)) {
          styleBits = SET(styleBits, UTILITY, true);
          if (target.isAlwaysOnTop()
              && rootpane.getClientProperty(WINDOW_HIDES_ON_DEACTIVATE) == null) {
            styleBits = SET(styleBits, HIDES_ON_DEACTIVATE, true);
          }
        }
        if ("textured".equals(prop)) styleBits = SET(styleBits, TEXTURED, true);
        if ("unified".equals(prop)) styleBits = SET(styleBits, UNIFIED, true);
        if ("hud".equals(prop)) styleBits = SET(styleBits, HUD, true);
      }

      prop = rootpane.getClientProperty(WINDOW_HIDES_ON_DEACTIVATE);
      if (prop != null) {
        styleBits = SET(styleBits, HIDES_ON_DEACTIVATE, Boolean.parseBoolean(prop.toString()));
      }

      prop = rootpane.getClientProperty(WINDOW_CLOSEABLE);
      if (prop != null) {
        styleBits = SET(styleBits, CLOSEABLE, Boolean.parseBoolean(prop.toString()));
      }

      prop = rootpane.getClientProperty(WINDOW_MINIMIZABLE);
      if (prop != null) {
        styleBits = SET(styleBits, MINIMIZABLE, Boolean.parseBoolean(prop.toString()));
      }

      prop = rootpane.getClientProperty(WINDOW_ZOOMABLE);
      if (prop != null) {
        styleBits = SET(styleBits, ZOOMABLE, Boolean.parseBoolean(prop.toString()));
      }

      prop = rootpane.getClientProperty(WINDOW_FULLSCREENABLE);
      if (prop != null) {
        styleBits = SET(styleBits, FULLSCREENABLE, Boolean.parseBoolean(prop.toString()));
      }

      prop = rootpane.getClientProperty(WINDOW_SHADOW);
      if (prop != null) {
        styleBits = SET(styleBits, HAS_SHADOW, Boolean.parseBoolean(prop.toString()));
      }

      prop = rootpane.getClientProperty(WINDOW_DRAGGABLE_BACKGROUND);
      if (prop != null) {
        styleBits = SET(styleBits, DRAGGABLE_BACKGROUND, Boolean.parseBoolean(prop.toString()));
      }
    }

    if (isDialog) {
      styleBits = SET(styleBits, IS_DIALOG, true);
      if (((Dialog) target).isModal()) {
        styleBits = SET(styleBits, IS_MODAL, true);
      }
    }

    peer.setTextured(IS(TEXTURED, styleBits));

    return styleBits;
  }

  // this is the counter-point to -[CWindow _nativeSetStyleBit:]
  private void setStyleBits(final int mask, final boolean value) {
    nativeSetNSWindowStyleBits(getNSWindowPtr(), mask, value ? mask : 0);
  }

  private native void _toggleFullScreenMode(final long model);

  public void toggleFullScreen() {
    _toggleFullScreenMode(getNSWindowPtr());
  }

  @Override // PlatformWindow
  public void setMenuBar(MenuBar mb) {
    final long nsWindowPtr = getNSWindowPtr();
    CMenuBar mbPeer = (CMenuBar) LWToolkit.targetToPeer(mb);
    if (mbPeer != null) {
      nativeSetNSWindowMenuBar(nsWindowPtr, mbPeer.getModel());
    } else {
      nativeSetNSWindowMenuBar(nsWindowPtr, 0);
    }
  }

  @Override // PlatformWindow
  public void dispose() {
    contentView.dispose();
    nativeDispose(getNSWindowPtr());
    CPlatformWindow.super.dispose();
  }

  @Override // PlatformWindow
  public FontMetrics getFontMetrics(Font f) {
    // TODO: not implemented
    (new RuntimeException("unimplemented")).printStackTrace();
    return null;
  }

  @Override // PlatformWindow
  public Insets getInsets() {
    return nativeGetNSWindowInsets(getNSWindowPtr());
  }

  @Override // PlatformWindow
  public Point getLocationOnScreen() {
    return new Point(nativeBounds.x, nativeBounds.y);
  }

  @Override
  public GraphicsDevice getGraphicsDevice() {
    return contentView.getGraphicsDevice();
  }

  @Override // PlatformWindow
  public SurfaceData getScreenSurface() {
    // TODO: not implemented
    return null;
  }

  @Override // PlatformWindow
  public SurfaceData replaceSurfaceData() {
    return contentView.replaceSurfaceData();
  }

  @Override // PlatformWindow
  public void setBounds(int x, int y, int w, int h) {
    nativeSetNSWindowBounds(getNSWindowPtr(), x, y, w, h);
  }

  public void setMaximizedBounds(int x, int y, int w, int h) {
    nativeSetNSWindowStandardFrame(getNSWindowPtr(), x, y, w, h);
  }

  private boolean isMaximized() {
    return undecorated ? this.normalBounds != null : CWrapper.NSWindow.isZoomed(getNSWindowPtr());
  }

  private void maximize() {
    if (peer == null || isMaximized()) {
      return;
    }
    if (!undecorated) {
      CWrapper.NSWindow.zoom(getNSWindowPtr());
    } else {
      deliverZoom(true);

      // We need an up to date size of the peer, so we flush the native events
      // to be sure that there are no setBounds requests in the queue.
      LWCToolkit.flushNativeSelectors();
      this.normalBounds = peer.getBounds();
      Rectangle maximizedBounds = peer.getMaximizedBounds();
      setBounds(
          maximizedBounds.x, maximizedBounds.y, maximizedBounds.width, maximizedBounds.height);
    }
  }

  private void unmaximize() {
    if (!isMaximized()) {
      return;
    }
    if (!undecorated) {
      CWrapper.NSWindow.zoom(getNSWindowPtr());
    } else {
      deliverZoom(false);

      Rectangle toBounds = this.normalBounds;
      this.normalBounds = null;
      setBounds(toBounds.x, toBounds.y, toBounds.width, toBounds.height);
    }
  }

  public boolean isVisible() {
    return this.visible;
  }

  @Override // PlatformWindow
  public void setVisible(boolean visible) {
    final long nsWindowPtr = getNSWindowPtr();

    // Configure stuff
    updateIconImages();
    updateFocusabilityForAutoRequestFocus(false);

    boolean wasMaximized = isMaximized();

    if (visible && target.isLocationByPlatform()) {
      nativeSetNSWindowLocationByPlatform(getNSWindowPtr());
    }

    // Actually show or hide the window
    LWWindowPeer blocker = (peer == null) ? null : peer.getBlocker();
    if (blocker == null || !visible) {
      // If it ain't blocked, or is being hidden, go regular way
      if (visible) {
        CWrapper.NSWindow.makeFirstResponder(nsWindowPtr, contentView.getAWTView());

        boolean isPopup = (target.getType() == Window.Type.POPUP);
        if (isPopup) {
          // Popups in applets don't activate applet's process
          CWrapper.NSWindow.orderFrontRegardless(nsWindowPtr);
        } else {
          CWrapper.NSWindow.orderFront(nsWindowPtr);
        }

        boolean isKeyWindow = CWrapper.NSWindow.isKeyWindow(nsWindowPtr);
        if (!isKeyWindow) {
          CWrapper.NSWindow.makeKeyWindow(nsWindowPtr);
        }
      } else {
        // immediately hide the window
        CWrapper.NSWindow.orderOut(nsWindowPtr);
        // process the close
        CWrapper.NSWindow.close(nsWindowPtr);
      }
    } else {
      // otherwise, put it in a proper z-order
      CWrapper.NSWindow.orderWindow(
          nsWindowPtr,
          CWrapper.NSWindow.NSWindowBelow,
          ((CPlatformWindow) blocker.getPlatformWindow()).getNSWindowPtr());
    }
    this.visible = visible;

    // Manage the extended state when showing
    if (visible) {
      // Apply the extended state as expected in shared code
      if (target instanceof Frame) {
        if (!wasMaximized && isMaximized()) {
          // setVisible could have changed the native maximized state
          deliverZoom(true);
        } else {
          int frameState = ((Frame) target).getExtendedState();
          if ((frameState & Frame.ICONIFIED) != 0) {
            // Treat all state bit masks with ICONIFIED bit as ICONIFIED state.
            frameState = Frame.ICONIFIED;
          }
          switch (frameState) {
            case Frame.ICONIFIED:
              CWrapper.NSWindow.miniaturize(nsWindowPtr);
              break;
            case Frame.MAXIMIZED_BOTH:
              maximize();
              break;
            default: // NORMAL
              unmaximize(); // in case it was maximized, otherwise this is a no-op
              break;
          }
        }
      }
    }

    nativeSynthesizeMouseEnteredExitedEvents();

    // Configure stuff #2
    updateFocusabilityForAutoRequestFocus(true);

    // Manage parent-child relationship when showing
    final ComponentAccessor acc = AWTAccessor.getComponentAccessor();

    if (visible) {
      // Order myself above my parent
      if (owner != null && owner.isVisible()) {
        CWrapper.NSWindow.orderWindow(
            nsWindowPtr, CWrapper.NSWindow.NSWindowAbove, owner.getNSWindowPtr());
        applyWindowLevel(target);
      }

      // Order my own children above myself
      for (Window w : target.getOwnedWindows()) {
        final Object p = acc.getPeer(w);
        if (p instanceof LWWindowPeer) {
          CPlatformWindow pw = (CPlatformWindow) ((LWWindowPeer) p).getPlatformWindow();
          if (pw != null && pw.isVisible()) {
            CWrapper.NSWindow.orderWindow(
                pw.getNSWindowPtr(), CWrapper.NSWindow.NSWindowAbove, nsWindowPtr);
            pw.applyWindowLevel(w);
          }
        }
      }
    }

    // Deal with the blocker of the window being shown
    if (blocker != null && visible) {
      // Make sure the blocker is above its siblings
      ((CPlatformWindow) blocker.getPlatformWindow()).orderAboveSiblings();
    }
  }

  @Override // PlatformWindow
  public void setTitle(String title) {
    nativeSetNSWindowTitle(getNSWindowPtr(), title);
  }

  // Should be called on every window key property change.
  @Override // PlatformWindow
  public void updateIconImages() {
    final long nsWindowPtr = getNSWindowPtr();
    final CImage cImage = getImageForTarget();
    nativeSetNSWindowMinimizedIcon(nsWindowPtr, cImage == null ? 0L : cImage.ptr);
  }

  public long getNSWindowPtr() {
    final long nsWindowPtr = ptr;
    if (nsWindowPtr == 0L) {
      if (logger.isLoggable(PlatformLogger.Level.FINE)) {
        logger.fine(
            "NSWindow already disposed?", new Exception("Pointer to native NSWindow is invalid."));
      }
    }
    return nsWindowPtr;
  }

  public SurfaceData getSurfaceData() {
    return contentView.getSurfaceData();
  }

  @Override // PlatformWindow
  public void toBack() {
    final long nsWindowPtr = getNSWindowPtr();
    nativePushNSWindowToBack(nsWindowPtr);
  }

  @Override // PlatformWindow
  public void toFront() {
    final long nsWindowPtr = getNSWindowPtr();
    LWCToolkit lwcToolkit = (LWCToolkit) Toolkit.getDefaultToolkit();
    Window w = DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
    final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
    if (w != null
        && acc.getPeer(w) != null
        && ((LWWindowPeer) acc.getPeer(w)).getPeerType() == LWWindowPeer.PeerType.EMBEDDED_FRAME
        && !lwcToolkit.isApplicationActive()) {
      lwcToolkit.activateApplicationIgnoringOtherApps();
    }
    updateFocusabilityForAutoRequestFocus(false);
    nativePushNSWindowToFront(nsWindowPtr);
    updateFocusabilityForAutoRequestFocus(true);
  }

  private void setCanFullscreen(final boolean canFullScreen) {
    if (target instanceof RootPaneContainer && getPeer().getPeerType() == PeerType.FRAME) {

      if (isInFullScreen && !canFullScreen) {
        toggleFullScreen();
      }

      final RootPaneContainer rpc = (RootPaneContainer) target;
      rpc.getRootPane().putClientProperty(CPlatformWindow.WINDOW_FULLSCREENABLE, canFullScreen);
    }
  }

  @Override
  public void setResizable(final boolean resizable) {
    setCanFullscreen(resizable);
    setStyleBits(RESIZABLE, resizable);
    setStyleBits(ZOOMABLE, resizable);
  }

  @Override
  public void setSizeConstraints(int minW, int minH, int maxW, int maxH) {
    nativeSetNSWindowMinMax(getNSWindowPtr(), minW, minH, maxW, maxH);
  }

  @Override
  public boolean rejectFocusRequest(FocusEvent.Cause cause) {
    // Cross-app activation requests are not allowed.
    if (cause != FocusEvent.Cause.MOUSE_EVENT
        && !((LWCToolkit) Toolkit.getDefaultToolkit()).isApplicationActive()) {
      focusLogger.fine("the app is inactive, so the request is rejected");
      return true;
    }
    return false;
  }

  @Override
  public boolean requestWindowFocus() {

    long ptr = getNSWindowPtr();
    if (CWrapper.NSWindow.canBecomeMainWindow(ptr)) {
      CWrapper.NSWindow.makeMainWindow(ptr);
    }
    CWrapper.NSWindow.makeKeyAndOrderFront(ptr);
    return true;
  }

  @Override
  public boolean isActive() {
    long ptr = getNSWindowPtr();
    return CWrapper.NSWindow.isKeyWindow(ptr);
  }

  @Override
  public void updateFocusableWindowState() {
    final boolean isFocusable = isNativelyFocusableWindow();
    setStyleBits(SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN, isFocusable); // set both bits at once
  }

  @Override
  public void setAlwaysOnTop(boolean isAlwaysOnTop) {
    setStyleBits(ALWAYS_ON_TOP, isAlwaysOnTop);
  }

  @Override
  public void setOpacity(float opacity) {
    CWrapper.NSWindow.setAlphaValue(getNSWindowPtr(), opacity);
  }

  @Override
  public void setOpaque(boolean isOpaque) {
    CWrapper.NSWindow.setOpaque(getNSWindowPtr(), isOpaque);
    boolean isTextured = (peer == null) ? false : peer.isTextured();
    if (!isTextured) {
      if (!isOpaque) {
        CWrapper.NSWindow.setBackgroundColor(getNSWindowPtr(), 0);
      } else if (peer != null) {
        Color color = peer.getBackground();
        if (color != null) {
          int rgb = color.getRGB();
          CWrapper.NSWindow.setBackgroundColor(getNSWindowPtr(), rgb);
        }
      }
    }

    // This is a temporary workaround. Looks like after 7124236 will be fixed
    // the correct place for invalidateShadow() is CGLayer.drawInCGLContext.
    SwingUtilities.invokeLater(this::invalidateShadow);
  }

  @Override
  public void enterFullScreenMode() {
    isFullScreenMode = true;
    nativeEnterFullScreenMode(getNSWindowPtr());
  }

  @Override
  public void exitFullScreenMode() {
    nativeExitFullScreenMode(getNSWindowPtr());
    isFullScreenMode = false;
  }

  @Override
  public boolean isFullScreenMode() {
    return isFullScreenMode;
  }

  @Override
  public void setWindowState(int windowState) {
    if (peer == null || !peer.isVisible()) {
      // setVisible() applies the state
      return;
    }

    int prevWindowState = peer.getState();
    if (prevWindowState == windowState) return;

    final long nsWindowPtr = getNSWindowPtr();
    if ((windowState & Frame.ICONIFIED) != 0) {
      // Treat all state bit masks with ICONIFIED bit as ICONIFIED state.
      windowState = Frame.ICONIFIED;
    }
    switch (windowState) {
      case Frame.ICONIFIED:
        if (prevWindowState == Frame.MAXIMIZED_BOTH) {
          // let's return into the normal states first
          // the zoom call toggles between the normal and the max states
          unmaximize();
        }
        CWrapper.NSWindow.miniaturize(nsWindowPtr);
        break;
      case Frame.MAXIMIZED_BOTH:
        if (prevWindowState == Frame.ICONIFIED) {
          // let's return into the normal states first
          CWrapper.NSWindow.deminiaturize(nsWindowPtr);
        }
        maximize();
        break;
      case Frame.NORMAL:
        if (prevWindowState == Frame.ICONIFIED) {
          CWrapper.NSWindow.deminiaturize(nsWindowPtr);
        } else if (prevWindowState == Frame.MAXIMIZED_BOTH) {
          // the zoom call toggles between the normal and the max states
          unmaximize();
        }
        break;
      default:
        throw new RuntimeException("Unknown window state: " + windowState);
    }

    // NOTE: the SWP.windowState field gets updated to the newWindowState
    //       value when the native notification comes to us
  }

  @Override
  public void setModalBlocked(boolean blocked) {
    if (target.getModalExclusionType() == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) {
      return;
    }

    if (blocked) {
      // We are going to show a modal window. Previously displayed window will be
      // blocked/disabled. So we have to send mouse exited event to it now, since
      // all mouse events are discarded for blocked/disabled windows.
      nativeSynthesizeMouseEnteredExitedEvents(getNSWindowPtr(), CocoaConstants.NSMouseExited);
    }

    nativeSetEnabled(getNSWindowPtr(), !blocked);
    checkBlockingAndOrder();
  }

  public final void invalidateShadow() {
    nativeRevalidateNSWindowShadow(getNSWindowPtr());
  }

  // ----------------------------------------------------------------------
  //                          UTILITY METHODS
  // ----------------------------------------------------------------------

  /**
   * Find image to install into Title or into Application icon. First try icons installed for
   * toplevel. Null is returned, if there is no icon and default Duke image should be used.
   */
  private CImage getImageForTarget() {
    CImage icon = null;
    try {
      icon = CImage.getCreator().createFromImages(target.getIconImages());
    } catch (Exception ignored) {
      // Perhaps the icon passed into Java is broken. Skipping this icon.
    }
    return icon;
  }

  /*
   * Returns LWWindowPeer associated with this delegate.
   */
  @Override
  public LWWindowPeer getPeer() {
    return peer;
  }

  @Override
  public boolean isUnderMouse() {
    return contentView.isUnderMouse();
  }

  public CPlatformView getContentView() {
    return contentView;
  }

  @Override
  public long getLayerPtr() {
    return contentView.getWindowLayerPtr();
  }

  private void validateSurface() {
    SurfaceData surfaceData = getSurfaceData();
    if (surfaceData instanceof CGLSurfaceData) {
      ((CGLSurfaceData) surfaceData).validate();
    }
  }

  void flushBuffers() {
    if (isVisible() && !nativeBounds.isEmpty() && !isFullScreenMode) {
      try {
        LWCToolkit.invokeAndWait(
            new Runnable() {
              @Override
              public void run() {
                // Posting an empty to flush the EventQueue without blocking the main thread
              }
            },
            target);
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }

  /** Helper method to get a pointer to the native view from the PlatformWindow. */
  static long getNativeViewPtr(PlatformWindow platformWindow) {
    long nativePeer = 0L;
    if (platformWindow instanceof CPlatformWindow) {
      nativePeer = ((CPlatformWindow) platformWindow).getContentView().getAWTView();
    } else if (platformWindow instanceof CViewPlatformEmbeddedFrame) {
      nativePeer = ((CViewPlatformEmbeddedFrame) platformWindow).getNSViewPtr();
    }
    return nativePeer;
  }

  /**
   * *********************************************************** Callbacks from the AWTWindow and
   * AWTView objc classes. ***********************************************************
   */
  private void deliverWindowFocusEvent(boolean gained, CPlatformWindow opposite) {
    // Fix for 7150349: ingore "gained" notifications when the app is inactive.
    if (gained && !((LWCToolkit) Toolkit.getDefaultToolkit()).isApplicationActive()) {
      focusLogger.fine("the app is inactive, so the notification is ignored");
      return;
    }

    LWWindowPeer oppositePeer = (opposite == null) ? null : opposite.getPeer();
    responder.handleWindowFocusEvent(gained, oppositePeer);
  }

  protected void deliverMoveResizeEvent(int x, int y, int width, int height, boolean byUser) {
    checkZoom();

    final Rectangle oldB = nativeBounds;
    nativeBounds = new Rectangle(x, y, width, height);
    if (peer != null) {
      peer.notifyReshape(x, y, width, height);
      // System-dependent appearance optimization.
      if ((byUser && !oldB.getSize().equals(nativeBounds.getSize())) || isFullScreenAnimationOn) {
        flushBuffers();
      }
    }
  }

  private void deliverWindowClosingEvent() {
    if (peer != null && peer.getBlocker() == null) {
      peer.postEvent(new WindowEvent(target, WindowEvent.WINDOW_CLOSING));
    }
  }

  private void deliverIconify(final boolean iconify) {
    if (peer != null) {
      peer.notifyIconify(iconify);
    }
  }

  private void deliverZoom(final boolean isZoomed) {
    if (peer != null) {
      peer.notifyZoom(isZoomed);
    }
  }

  private void checkZoom() {
    if (peer != null) {
      int state = peer.getState();
      if (state != Frame.MAXIMIZED_BOTH && isMaximized()) {
        deliverZoom(true);
      } else if (state == Frame.MAXIMIZED_BOTH && !isMaximized()) {
        deliverZoom(false);
      }
    }
  }

  private void deliverNCMouseDown() {
    if (peer != null) {
      peer.notifyNCMouseDown();
    }
  }

  /*
   * Our focus model is synthetic and only non-simple window
   * may become natively focusable window.
   */
  private boolean isNativelyFocusableWindow() {
    if (peer == null) {
      return false;
    }

    return !peer.isSimpleWindow() && target.getFocusableWindowState();
  }

  /*
   * An utility method for the support of the auto request focus.
   * Updates the focusable state of the window under certain
   * circumstances.
   */
  private void updateFocusabilityForAutoRequestFocus(boolean isFocusable) {
    if (target.isAutoRequestFocus() || !isNativelyFocusableWindow()) return;
    setStyleBits(SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN, isFocusable); // set both bits at once
  }

  private boolean checkBlockingAndOrder() {
    LWWindowPeer blocker = (peer == null) ? null : peer.getBlocker();
    if (blocker == null) {
      return false;
    }

    if (blocker instanceof CPrinterDialogPeer) {
      return true;
    }

    CPlatformWindow pWindow = (CPlatformWindow) blocker.getPlatformWindow();

    pWindow.orderAboveSiblings();

    final long nsWindowPtr = pWindow.getNSWindowPtr();
    CWrapper.NSWindow.orderFrontRegardless(nsWindowPtr);
    CWrapper.NSWindow.makeKeyAndOrderFront(nsWindowPtr);
    CWrapper.NSWindow.makeMainWindow(nsWindowPtr);

    return true;
  }

  private void orderAboveSiblings() {
    if (owner == null) {
      return;
    }

    // NOTE: the logic will fail if we have a hierarchy like:
    //       visible root owner
    //          invisible owner
    //              visible dialog
    // However, this is an unlikely scenario for real life apps
    if (owner.isVisible()) {
      // Recursively pop up the windows from the very bottom so that only
      // the very top-most one becomes the main window
      owner.orderAboveSiblings();

      // Order the window to front of the stack of child windows
      final long nsWindowSelfPtr = getNSWindowPtr();
      final long nsWindowOwnerPtr = owner.getNSWindowPtr();
      CWrapper.NSWindow.orderFront(nsWindowOwnerPtr);
      CWrapper.NSWindow.orderWindow(
          nsWindowSelfPtr, CWrapper.NSWindow.NSWindowAbove, nsWindowOwnerPtr);
    }

    applyWindowLevel(target);
  }

  protected void applyWindowLevel(Window target) {
    if (target.isAlwaysOnTop() && target.getType() != Window.Type.POPUP) {
      CWrapper.NSWindow.setLevel(getNSWindowPtr(), CWrapper.NSWindow.NSFloatingWindowLevel);
    } else if (target.getType() == Window.Type.POPUP) {
      CWrapper.NSWindow.setLevel(getNSWindowPtr(), CWrapper.NSWindow.NSPopUpMenuWindowLevel);
    }
  }

  // ----------------------------------------------------------------------
  //                          NATIVE CALLBACKS
  // ----------------------------------------------------------------------

  private void windowDidBecomeMain() {
    if (checkBlockingAndOrder()) return;
    // If it's not blocked, make sure it's above its siblings
    orderAboveSiblings();
  }

  private void windowWillEnterFullScreen() {
    isFullScreenAnimationOn = true;
  }

  private void windowDidEnterFullScreen() {
    isInFullScreen = true;
    isFullScreenAnimationOn = false;
  }

  private void windowWillExitFullScreen() {
    isFullScreenAnimationOn = true;
  }

  private void windowDidExitFullScreen() {
    isInFullScreen = false;
    isFullScreenAnimationOn = false;
  }
}
 private static void warning(String msg) {
   PlatformLogger logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
   logger.warning(msg);
 }
Ejemplo n.º 4
0
final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer {
  private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XTextField");

  private String text;
  private final XAWTTextField xtext;
  private final boolean firstChangeSkipped;

  XTextFieldPeer(TextField target) {
    super(target);
    text = target.getText();
    xtext = new XAWTTextField(text, this, target.getParent());
    xtext.getDocument().addDocumentListener(xtext);
    xtext.setCursor(target.getCursor());
    XToolkit.specialPeerMap.put(xtext, this);

    initTextField();
    setText(target.getText());
    if (target.echoCharIsSet()) {
      setEchoChar(target.getEchoChar());
    } else setEchoChar((char) 0);

    int start = target.getSelectionStart();
    int end = target.getSelectionEnd();
    // Fix for 5100200
    // Restoring Motif behaviour
    // Since the end position of the selected text can be greater than the length of the text,
    // so we should set caret to max position of the text
    setCaretPosition(Math.min(end, text.length()));
    if (end > start) {
      // Should be called after setText() and setCaretPosition()
      select(start, end);
    }

    setEditable(target.isEditable());

    // After this line we should not change the component's text
    firstChangeSkipped = true;
    AWTAccessor.getComponentAccessor().setPeer(xtext, this);
  }

  @Override
  public void dispose() {
    XToolkit.specialPeerMap.remove(xtext);
    // visible caret has a timer thread which must be stopped
    xtext.getCaret().setVisible(false);
    super.dispose();
  }

  void initTextField() {
    setVisible(target.isVisible());

    setBounds(x, y, width, height, SET_BOUNDS);

    AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
    foreground = compAccessor.getForeground(target);
    if (foreground == null) foreground = SystemColor.textText;

    setForeground(foreground);

    background = compAccessor.getBackground(target);
    if (background == null) {
      if (((TextField) target).isEditable()) background = SystemColor.text;
      else background = SystemColor.control;
    }
    setBackground(background);

    if (!target.isBackgroundSet()) {
      // This is a way to set the background color of the TextArea
      // without calling setBackground - go through accessor
      compAccessor.setBackground(target, background);
    }
    if (!target.isForegroundSet()) {
      target.setForeground(SystemColor.textText);
    }

    setFont(font);
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  public void setEditable(boolean editable) {
    if (xtext != null) {
      xtext.setEditable(editable);
      xtext.repaint();
    }
  }

  /** @see java.awt.peer.ComponentPeer */
  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    if (xtext != null) {
      xtext.setEnabled(enabled);
      xtext.repaint();
    }
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  public InputMethodRequests getInputMethodRequests() {
    if (xtext != null) return xtext.getInputMethodRequests();
    else return null;
  }

  @Override
  void handleJavaInputMethodEvent(InputMethodEvent e) {
    if (xtext != null) xtext.processInputMethodEventImpl(e);
  }

  /** @see java.awt.peer.TextFieldPeer */
  @Override
  public void setEchoChar(char c) {
    if (xtext != null) {
      xtext.setEchoChar(c);
      xtext.putClientProperty(
          "JPasswordField.cutCopyAllowed", xtext.echoCharIsSet() ? Boolean.FALSE : Boolean.TRUE);
    }
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  public int getSelectionStart() {
    return xtext.getSelectionStart();
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  public int getSelectionEnd() {
    return xtext.getSelectionEnd();
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  @SuppressWarnings("deprecation")
  public String getText() {
    return xtext.getText();
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  public void setText(String text) {
    setXAWTTextField(text);
    repaint();
  }

  private void setXAWTTextField(String txt) {
    text = txt;
    if (xtext != null) {
      // JTextField.setText() posts two different events (remove & insert).
      // Since we make no differences between text events,
      // the document listener has to be disabled while
      // JTextField.setText() is called.
      xtext.getDocument().removeDocumentListener(xtext);
      xtext.setText(txt);
      if (firstChangeSkipped) {
        postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED));
      }
      xtext.getDocument().addDocumentListener(xtext);
      xtext.setCaretPosition(0);
    }
  }

  /**
   * to be implemented.
   *
   * @see java.awt.peer.TextComponentPeer
   */
  @Override
  public void setCaretPosition(int position) {
    if (xtext != null) xtext.setCaretPosition(position);
  }

  void repaintText() {
    xtext.repaintNow();
  }

  @Override
  public void setBackground(Color c) {
    if (log.isLoggable(PlatformLogger.Level.FINE)) {
      log.fine("target=" + target + ", old=" + background + ", new=" + c);
    }
    background = c;
    if (xtext != null) {
      if (xtext.getBackground() != c) {
        xtext.setBackground(c);
      }
      xtext.setSelectedTextColor(c);
    }
    repaintText();
  }

  @Override
  public void setForeground(Color c) {
    foreground = c;
    if (xtext != null) {
      if (xtext.getForeground() != c) {
        xtext.setForeground(foreground);
      }
      xtext.setSelectionColor(foreground);
      xtext.setCaretColor(foreground);
    }
    repaintText();
  }

  @Override
  public void setFont(Font f) {
    synchronized (getStateLock()) {
      font = f;
      if (xtext != null && xtext.getFont() != f) {
        xtext.setFont(font);
      }
    }
    xtext.validate();
  }

  /** Deselects the highlighted text. */
  public void deselect() {
    int selStart = xtext.getSelectionStart();
    int selEnd = xtext.getSelectionEnd();
    if (selStart != selEnd) {
      xtext.select(selStart, selStart);
    }
  }

  /**
   * to be implemented.
   *
   * @see java.awt.peer.TextComponentPeer
   */
  @Override
  public int getCaretPosition() {
    return xtext.getCaretPosition();
  }

  /** @see java.awt.peer.TextComponentPeer */
  @Override
  public void select(int s, int e) {
    xtext.select(s, e);
    // Fixed 5100806
    // We must take care that Swing components repainted correctly
    xtext.repaint();
  }

  @Override
  public Dimension getMinimumSize() {
    return xtext.getMinimumSize();
  }

  @Override
  public Dimension getPreferredSize() {
    return xtext.getPreferredSize();
  }

  @Override
  public Dimension getPreferredSize(int cols) {
    return getMinimumSize(cols);
  }

  private static final int PADDING = 16;

  @Override
  public Dimension getMinimumSize(int cols) {
    Font f = xtext.getFont();
    FontMetrics fm = xtext.getFontMetrics(f);
    return new Dimension(
        fm.charWidth('0') * cols + 10, fm.getMaxDescent() + fm.getMaxAscent() + PADDING);
  }

  @Override
  public boolean isFocusable() {
    return true;
  }

  // NOTE: This method is called by privileged threads.
  //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  public void action(final long when, final int modifiers) {
    postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, text, when, modifiers));
  }

  protected void disposeImpl() {}

  @Override
  public void repaint() {
    if (xtext != null) xtext.repaint();
  }

  @Override
  void paintPeer(final Graphics g) {
    if (xtext != null) xtext.paint(g);
  }

  @Override
  public void print(Graphics g) {
    if (xtext != null) {
      xtext.print(g);
    }
  }

  @Override
  public void focusLost(FocusEvent e) {
    super.focusLost(e);
    xtext.forwardFocusLost(e);
  }

  @Override
  public void focusGained(FocusEvent e) {
    super.focusGained(e);
    xtext.forwardFocusGained(e);
  }

  @Override
  void handleJavaKeyEvent(KeyEvent e) {
    AWTAccessor.getComponentAccessor().processEvent(xtext, e);
  }

  @Override
  public void handleJavaMouseEvent(MouseEvent mouseEvent) {
    super.handleJavaMouseEvent(mouseEvent);
    if (xtext != null) {
      mouseEvent.setSource(xtext);
      int id = mouseEvent.getID();
      if (id == MouseEvent.MOUSE_DRAGGED || id == MouseEvent.MOUSE_MOVED)
        xtext.processMouseMotionEventImpl(mouseEvent);
      else xtext.processMouseEventImpl(mouseEvent);
    }
  }

  /** DEPRECATED */
  @Override
  public Dimension minimumSize() {
    return getMinimumSize();
  }

  @Override
  public void setVisible(boolean b) {
    super.setVisible(b);
    if (xtext != null) xtext.setVisible(b);
  }

  @Override
  public void setBounds(int x, int y, int width, int height, int op) {
    super.setBounds(x, y, width, height, op);
    if (xtext != null) {
      /*
       * Fixed 6277332, 6198290:
       * the coordinates is coming (to peer): relatively to closest HW parent
       * the coordinates is setting (to textField): relatively to closest ANY parent
       * the parent of peer is target.getParent()
       * the parent of textField is the same
       * see 6277332, 6198290 for more information
       */
      int childX = x;
      int childY = y;
      Component parent = target.getParent();
      // we up to heavyweight parent in order to be sure
      // that the coordinates of the text pane is relatively to closest parent
      while (parent.isLightweight()) {
        childX -= parent.getX();
        childY -= parent.getY();
        parent = parent.getParent();
      }
      xtext.setBounds(childX, childY, width, height);
      xtext.validate();
    }
  }

  final class AWTTextFieldUI extends MotifPasswordFieldUI {

    private JTextField jtf;

    @Override
    protected String getPropertyPrefix() {
      JTextComponent comp = getComponent();
      if (comp instanceof JPasswordField && ((JPasswordField) comp).echoCharIsSet()) {
        return "PasswordField";
      } else {
        return "TextField";
      }
    }

    @Override
    public void installUI(JComponent c) {
      super.installUI(c);

      jtf = (JTextField) c;

      JTextField editor = jtf;

      UIDefaults uidefaults = XToolkit.getUIDefaults();

      String prefix = getPropertyPrefix();
      Font f = editor.getFont();
      if ((f == null) || (f instanceof UIResource)) {
        editor.setFont(uidefaults.getFont(prefix + ".font"));
      }

      Color bg = editor.getBackground();
      if ((bg == null) || (bg instanceof UIResource)) {
        editor.setBackground(uidefaults.getColor(prefix + ".background"));
      }

      Color fg = editor.getForeground();
      if ((fg == null) || (fg instanceof UIResource)) {
        editor.setForeground(uidefaults.getColor(prefix + ".foreground"));
      }

      Color color = editor.getCaretColor();
      if ((color == null) || (color instanceof UIResource)) {
        editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground"));
      }

      Color s = editor.getSelectionColor();
      if ((s == null) || (s instanceof UIResource)) {
        editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground"));
      }

      Color sfg = editor.getSelectedTextColor();
      if ((sfg == null) || (sfg instanceof UIResource)) {
        editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground"));
      }

      Color dfg = editor.getDisabledTextColor();
      if ((dfg == null) || (dfg instanceof UIResource)) {
        editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground"));
      }

      Border b = editor.getBorder();
      if ((b == null) || (b instanceof UIResource)) {
        editor.setBorder(uidefaults.getBorder(prefix + ".border"));
      }

      Insets margin = editor.getMargin();
      if (margin == null || margin instanceof UIResource) {
        editor.setMargin(uidefaults.getInsets(prefix + ".margin"));
      }
    }

    @Override
    protected void installKeyboardActions() {
      super.installKeyboardActions();

      JTextComponent comp = getComponent();

      UIDefaults uidefaults = XToolkit.getUIDefaults();

      String prefix = getPropertyPrefix();

      InputMap map = (InputMap) uidefaults.get(prefix + ".focusInputMap");

      if (map != null) {
        SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, map);
      }
    }

    @Override
    protected Caret createCaret() {
      return new XTextAreaPeer.XAWTCaret();
    }
  }

  @SuppressWarnings("serial") // JDK-implementation class
  final class XAWTTextField extends JPasswordField implements ActionListener, DocumentListener {

    private boolean isFocused = false;
    private final XComponentPeer xwin;

    XAWTTextField(String text, XComponentPeer xwin, Container parent) {
      super(text);
      this.xwin = xwin;
      setDoubleBuffered(true);
      setFocusable(false);
      AWTAccessor.getComponentAccessor().setParent(this, parent);
      setBackground(xwin.getPeerBackground());
      setForeground(xwin.getPeerForeground());
      setFont(xwin.getPeerFont());
      setCaretPosition(0);
      addActionListener(this);
      addNotify();
    }

    @Override
    @SuppressWarnings("deprecation")
    public void actionPerformed(ActionEvent actionEvent) {
      xwin.postEvent(
          new ActionEvent(
              xwin.target,
              ActionEvent.ACTION_PERFORMED,
              getText(),
              actionEvent.getWhen(),
              actionEvent.getModifiers()));
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
      if (xwin != null) {
        xwin.postEvent(new TextEvent(xwin.target, TextEvent.TEXT_VALUE_CHANGED));
      }
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
      if (xwin != null) {
        xwin.postEvent(new TextEvent(xwin.target, TextEvent.TEXT_VALUE_CHANGED));
      }
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
      if (xwin != null) {
        xwin.postEvent(new TextEvent(xwin.target, TextEvent.TEXT_VALUE_CHANGED));
      }
    }

    public void repaintNow() {
      paintImmediately(getBounds());
    }

    @Override
    public Graphics getGraphics() {
      return xwin.getGraphics();
    }

    @Override
    public void updateUI() {
      ComponentUI ui = new AWTTextFieldUI();
      setUI(ui);
    }

    void forwardFocusGained(FocusEvent e) {
      isFocused = true;
      FocusEvent fe =
          new FocusEvent(this, e.getID(), e.isTemporary(), e.getOppositeComponent(), e.getCause());
      super.processFocusEvent(fe);
    }

    void forwardFocusLost(FocusEvent e) {
      isFocused = false;
      FocusEvent fe =
          new FocusEvent(this, e.getID(), e.isTemporary(), e.getOppositeComponent(), e.getCause());
      super.processFocusEvent(fe);
    }

    @Override
    public boolean hasFocus() {
      return isFocused;
    }

    public void processInputMethodEventImpl(InputMethodEvent e) {
      processInputMethodEvent(e);
    }

    public void processMouseEventImpl(MouseEvent e) {
      processMouseEvent(e);
    }

    public void processMouseMotionEventImpl(MouseEvent e) {
      processMouseMotionEvent(e);
    }

    // Fix for 4915454 - override the default implementation to avoid
    // loading SystemFlavorMap and associated classes.
    @Override
    public void setTransferHandler(TransferHandler newHandler) {
      TransferHandler oldHandler =
          (TransferHandler)
              getClientProperty(
                  AWTAccessor.getClientPropertyKeyAccessor().getJComponent_TRANSFER_HANDLER());
      putClientProperty(
          AWTAccessor.getClientPropertyKeyAccessor().getJComponent_TRANSFER_HANDLER(), newHandler);

      firePropertyChange("transferHandler", oldHandler, newHandler);
    }

    @Override
    public void setEchoChar(char c) {
      super.setEchoChar(c);
      ((AWTTextFieldUI) ui).installKeyboardActions();
    }
  }
}
Ejemplo n.º 5
0
public class XEmbedCanvasPeer extends XCanvasPeer
    implements WindowFocusListener, KeyEventPostProcessor, ModalityListener, WindowIDProvider {
  private static final PlatformLogger xembedLog =
      PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbedCanvasPeer");

  boolean applicationActive; // Whether the application is active(has focus)
  XEmbedServer xembed = new XEmbedServer(); // Helper object, contains XEmbed intrinsics
  Map<Long, AWTKeyStroke> accelerators =
      new HashMap<Long, AWTKeyStroke>(); // Maps accelerator ID into AWTKeyStroke
  Map<AWTKeyStroke, Long> accel_lookup =
      new HashMap<AWTKeyStroke, Long>(); // Maps AWTKeyStroke into accelerator ID
  Set<GrabbedKey> grabbed_keys = new HashSet<GrabbedKey>(); // A set of keys grabbed by client
  Object ACCEL_LOCK = accelerators; // Lock object for working with accelerators;
  Object GRAB_LOCK = grabbed_keys; // Lock object for working with keys grabbed by client

  XEmbedCanvasPeer() {}

  XEmbedCanvasPeer(XCreateWindowParams params) {
    super(params);
  }

  XEmbedCanvasPeer(Component target) {
    super(target);
  }

  protected void postInit(XCreateWindowParams params) {
    super.postInit(params);

    installActivateListener();
    installAcceleratorListener();
    installModalityListener();

    // XEmbed canvas should be non-traversable.
    // FIXME: Probably should be removed and enforced setting of it by the users
    target.setFocusTraversalKeysEnabled(false);
  }

  protected void preInit(XCreateWindowParams params) {
    super.preInit(params);

    params.put(
        EVENT_MASK,
        XConstants.KeyPressMask
            | XConstants.KeyReleaseMask
            | XConstants.FocusChangeMask
            | XConstants.ButtonPressMask
            | XConstants.ButtonReleaseMask
            | XConstants.EnterWindowMask
            | XConstants.LeaveWindowMask
            | XConstants.PointerMotionMask
            | XConstants.ButtonMotionMask
            | XConstants.ExposureMask
            | XConstants.StructureNotifyMask
            | XConstants.SubstructureNotifyMask);
  }

  void installModalityListener() {
    ((SunToolkit) Toolkit.getDefaultToolkit()).addModalityListener(this);
  }

  void deinstallModalityListener() {
    ((SunToolkit) Toolkit.getDefaultToolkit()).removeModalityListener(this);
  }

  void installAcceleratorListener() {
    KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this);
  }

  void deinstallAcceleratorListener() {
    KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(this);
  }

  void installActivateListener() {
    // FIXME: should watch for hierarchy changes
    Window toplevel = getTopLevel(target);
    if (toplevel != null) {
      toplevel.addWindowFocusListener(this);
      applicationActive = toplevel.isFocused();
    }
  }

  void deinstallActivateListener() {
    Window toplevel = getTopLevel(target);
    if (toplevel != null) {
      toplevel.removeWindowFocusListener(this);
    }
  }

  boolean isXEmbedActive() {
    return xembed.handle != 0;
  }

  boolean isApplicationActive() {
    return applicationActive;
  }

  void initDispatching() {
    if (xembedLog.isLoggable(PlatformLogger.FINE))
      xembedLog.fine("Init embedding for " + Long.toHexString(xembed.handle));
    XToolkit.awtLock();
    try {
      XToolkit.addEventDispatcher(xembed.handle, xembed);
      XlibWrapper.XSelectInput(
          XToolkit.getDisplay(),
          xembed.handle,
          XConstants.StructureNotifyMask | XConstants.PropertyChangeMask);

      XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(), xembed.handle);
    } finally {
      XToolkit.awtUnlock();
    }
    xembed.processXEmbedInfo();

    notifyChildEmbedded();
  }

  void endDispatching() {
    xembedLog.fine("End dispatching for " + Long.toHexString(xembed.handle));
    XToolkit.awtLock();
    try {
      XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(), xembed.handle);
      // We can't deselect input since someone else might be interested in it
      XToolkit.removeEventDispatcher(xembed.handle, xembed);
    } finally {
      XToolkit.awtUnlock();
    }
  }

  void embedChild(long child) {
    if (xembed.handle != 0) {
      detachChild();
    }
    xembed.handle = child;
    initDispatching();
  }

  void childDestroyed() {
    xembedLog.fine("Child " + Long.toHexString(xembed.handle) + " has self-destroyed.");
    endDispatching();
    xembed.handle = 0;
  }

  public void handleEvent(AWTEvent e) {
    super.handleEvent(e);
    if (isXEmbedActive()) {
      switch (e.getID()) {
        case FocusEvent.FOCUS_GAINED:
          canvasFocusGained((FocusEvent) e);
          break;
        case FocusEvent.FOCUS_LOST:
          canvasFocusLost((FocusEvent) e);
          break;
        case KeyEvent.KEY_PRESSED:
        case KeyEvent.KEY_RELEASED:
          if (!((InputEvent) e).isConsumed()) {
            forwardKeyEvent((KeyEvent) e);
          }
          break;
      }
    }
  }

  public void dispatchEvent(XEvent ev) {
    super.dispatchEvent(ev);
    switch (ev.get_type()) {
      case XConstants.CreateNotify:
        XCreateWindowEvent cr = ev.get_xcreatewindow();
        if (xembedLog.isLoggable(PlatformLogger.FINEST)) {
          xembedLog.finest("Message on embedder: " + cr);
        }
        if (xembedLog.isLoggable(PlatformLogger.FINER)) {
          xembedLog.finer(
              "Create notify for parent "
                  + Long.toHexString(cr.get_parent())
                  + ", window "
                  + Long.toHexString(cr.get_window()));
        }
        embedChild(cr.get_window());
        break;
      case XConstants.DestroyNotify:
        XDestroyWindowEvent dn = ev.get_xdestroywindow();
        if (xembedLog.isLoggable(PlatformLogger.FINEST)) {
          xembedLog.finest("Message on embedder: " + dn);
        }
        if (xembedLog.isLoggable(PlatformLogger.FINER)) {
          xembedLog.finer("Destroy notify for parent: " + dn);
        }
        childDestroyed();
        break;
      case XConstants.ReparentNotify:
        XReparentEvent rep = ev.get_xreparent();
        if (xembedLog.isLoggable(PlatformLogger.FINEST)) {
          xembedLog.finest("Message on embedder: " + rep);
        }
        if (xembedLog.isLoggable(PlatformLogger.FINER)) {
          xembedLog.finer(
              "Reparent notify for parent "
                  + Long.toHexString(rep.get_parent())
                  + ", window "
                  + Long.toHexString(rep.get_window())
                  + ", event "
                  + Long.toHexString(rep.get_event()));
        }
        if (rep.get_parent() == getWindow()) {
          // Reparented into us - embed it
          embedChild(rep.get_window());
        } else {
          // Reparented out of us - detach it
          childDestroyed();
        }
        break;
    }
  }

  public Dimension getPreferredSize() {
    if (isXEmbedActive()) {
      XToolkit.awtLock();
      try {
        long p_hints = XlibWrapper.XAllocSizeHints();
        XSizeHints hints = new XSizeHints(p_hints);
        XlibWrapper.XGetWMNormalHints(
            XToolkit.getDisplay(), xembed.handle, p_hints, XlibWrapper.larg1);
        Dimension res = new Dimension(hints.get_width(), hints.get_height());
        XlibWrapper.XFree(p_hints);
        return res;
      } finally {
        XToolkit.awtUnlock();
      }
    } else {
      return super.getPreferredSize();
    }
  }

  public Dimension getMinimumSize() {
    if (isXEmbedActive()) {
      XToolkit.awtLock();
      try {
        long p_hints = XlibWrapper.XAllocSizeHints();
        XSizeHints hints = new XSizeHints(p_hints);
        XlibWrapper.XGetWMNormalHints(
            XToolkit.getDisplay(), xembed.handle, p_hints, XlibWrapper.larg1);
        Dimension res = new Dimension(hints.get_min_width(), hints.get_min_height());
        XlibWrapper.XFree(p_hints);
        return res;
      } finally {
        XToolkit.awtUnlock();
      }
    } else {
      return super.getMinimumSize();
    }
  }

  public void dispose() {
    if (isXEmbedActive()) {
      detachChild();
    }
    deinstallActivateListener();
    deinstallModalityListener();
    deinstallAcceleratorListener();

    // BUG: Focus traversal doesn't become enabled after the one round of embedding
    // target.setFocusTraversalKeysEnabled(true);

    super.dispose();
  }

  // Focusable is true in order to enable focus traversal through this Canvas
  public boolean isFocusable() {
    return true;
  }

  Window getTopLevel(Component comp) {
    while (comp != null && !(comp instanceof Window)) {
      comp = comp.getParent();
    }
    return (Window) comp;
  }

  Rectangle getClientBounds() {
    XToolkit.awtLock();
    try {
      XWindowAttributes wattr = new XWindowAttributes();
      try {
        XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
        int status =
            XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), xembed.handle, wattr.pData);

        XToolkit.RESTORE_XERROR_HANDLER();

        if (status == 0
            || (XToolkit.saved_error != null
                && XToolkit.saved_error.get_error_code() != XConstants.Success)) {
          return null;
        }

        return new Rectangle(wattr.get_x(), wattr.get_y(), wattr.get_width(), wattr.get_height());
      } finally {
        wattr.dispose();
      }
    } finally {
      XToolkit.awtUnlock();
    }
  }

  void childResized() {
    if (xembedLog.isLoggable(PlatformLogger.FINER)) {
      Rectangle bounds = getClientBounds();
      xembedLog.finer("Child resized: " + bounds);
      // It is not required to update embedder's size when client size changes
      // However, since there is no any means to get client size it seems to be the
      // only way to provide it. However, it contradicts with Java layout concept -
      // so it is disabled for now.
      //             Rectangle my_bounds = getBounds();
      //             setBounds(my_bounds.x, my_bounds.y, bounds.width, bounds.height, SET_BOUNDS);
    }
    XToolkit.postEvent(
        XToolkit.targetToAppContext(target),
        new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED));
  }

  void focusNext() {
    if (isXEmbedActive()) {
      xembedLog.fine("Requesting focus for the next component after embedder");
      postEvent(
          new InvocationEvent(
              target,
              new Runnable() {
                public void run() {
                  KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(target);
                }
              }));
    } else {
      xembedLog.fine("XEmbed is not active - denying focus next");
    }
  }

  void focusPrev() {
    if (isXEmbedActive()) {
      xembedLog.fine("Requesting focus for the next component after embedder");
      postEvent(
          new InvocationEvent(
              target,
              new Runnable() {
                public void run() {
                  KeyboardFocusManager.getCurrentKeyboardFocusManager()
                      .focusPreviousComponent(target);
                }
              }));
    } else {
      xembedLog.fine("XEmbed is not active - denying focus prev");
    }
  }

  void requestXEmbedFocus() {
    if (isXEmbedActive()) {
      xembedLog.fine("Requesting focus for client");
      postEvent(
          new InvocationEvent(
              target,
              new Runnable() {
                public void run() {
                  target.requestFocus();
                }
              }));
    } else {
      xembedLog.fine("XEmbed is not active - denying request focus");
    }
  }

  void notifyChildEmbedded() {
    xembed.sendMessage(
        xembed.handle,
        XEMBED_EMBEDDED_NOTIFY,
        getWindow(),
        Math.min(xembed.version, XEMBED_VERSION),
        0);
    if (isApplicationActive()) {
      xembedLog.fine("Sending WINDOW_ACTIVATE during initialization");
      xembed.sendMessage(xembed.handle, XEMBED_WINDOW_ACTIVATE);
      if (hasFocus()) {
        xembedLog.fine("Sending FOCUS_GAINED during initialization");
        xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
      }
    }
  }

  void detachChild() {
    if (xembedLog.isLoggable(PlatformLogger.FINE))
      xembedLog.fine("Detaching child " + Long.toHexString(xembed.handle));
    /**
     * XEmbed specification: "The embedder can unmap the client and reparent the client window to
     * the root window. If the client receives an ReparentNotify event, it should check the parent
     * field of the XReparentEvent structure. If this is the root window of the window's screen,
     * then the protocol is finished and there is no further interaction. If it is a window other
     * than the root window, then the protocol continues with the new parent acting as the embedder
     * window."
     */
    XToolkit.awtLock();
    try {
      XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), xembed.handle);
      XlibWrapper.XReparentWindow(
          XToolkit.getDisplay(), xembed.handle, XToolkit.getDefaultRootWindow(), 0, 0);
    } finally {
      XToolkit.awtUnlock();
    }
    endDispatching();
    xembed.handle = 0;
  }

  public void windowGainedFocus(WindowEvent e) {
    applicationActive = true;
    if (isXEmbedActive()) {
      xembedLog.fine("Sending WINDOW_ACTIVATE");
      xembed.sendMessage(xembed.handle, XEMBED_WINDOW_ACTIVATE);
    }
  }

  public void windowLostFocus(WindowEvent e) {
    applicationActive = false;
    if (isXEmbedActive()) {
      xembedLog.fine("Sending WINDOW_DEACTIVATE");
      xembed.sendMessage(xembed.handle, XEMBED_WINDOW_DEACTIVATE);
    }
  }

  void canvasFocusGained(FocusEvent e) {
    if (isXEmbedActive()) {
      xembedLog.fine("Forwarding FOCUS_GAINED");
      int flavor = XEMBED_FOCUS_CURRENT;
      if (e instanceof CausedFocusEvent) {
        CausedFocusEvent ce = (CausedFocusEvent) e;
        if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_FORWARD) {
          flavor = XEMBED_FOCUS_FIRST;
        } else if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_BACKWARD) {
          flavor = XEMBED_FOCUS_LAST;
        }
      }
      xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, flavor, 0, 0);
    }
  }

  void canvasFocusLost(FocusEvent e) {
    if (isXEmbedActive() && !e.isTemporary()) {
      xembedLog.fine("Forwarding FOCUS_LOST");
      int num = 0;
      if (AccessController.doPrivileged(new GetBooleanAction("sun.awt.xembed.testing"))) {
        Component opp = e.getOppositeComponent();
        try {
          num = Integer.parseInt(opp.getName());
        } catch (NumberFormatException nfe) {
        }
      }
      xembed.sendMessage(xembed.handle, XEMBED_FOCUS_OUT, num, 0, 0);
    }
  }

  static Field bdataField;

  static byte[] getBData(KeyEvent e) {
    try {
      if (bdataField == null) {
        bdataField = SunToolkit.getField(java.awt.AWTEvent.class, "bdata");
      }
      return (byte[]) bdataField.get(e);
    } catch (IllegalAccessException ex) {
      return null;
    }
  }

  void forwardKeyEvent(KeyEvent e) {
    xembedLog.fine("Try to forward key event");
    byte[] bdata = getBData(e);
    long data = Native.toData(bdata);
    if (data == 0) {
      return;
    }
    try {
      XKeyEvent ke = new XKeyEvent(data);
      ke.set_window(xembed.handle);
      if (xembedLog.isLoggable(PlatformLogger.FINE))
        xembedLog.fine("Forwarding native key event: " + ke);
      XToolkit.awtLock();
      try {
        XlibWrapper.XSendEvent(
            XToolkit.getDisplay(), xembed.handle, false, XConstants.NoEventMask, data);
      } finally {
        XToolkit.awtUnlock();
      }
    } finally {
      XlibWrapper.unsafe.freeMemory(data);
    }
  }

  /**
   * Grab/ungrab key functionality is an unofficial API supported by GTK. Unfortunately, it doesn't
   * support accelerator API, so, since this is the ONLY shortcut-processing API available, we must
   * support it. See XEmbed.NON_STANDARD_XEMBED_GTK_* messages. The format of these messages is as
   * follows: - request from client: data[1] = NON_STANDARD_XEMBED_GTK_GRAB_KEY or
   * NON_STANDARD_XEMBED_GTK_UNGRAB_KEY data[3] = X keysym data[4] = X modifiers
   *
   * <p>- response from server (in case the grabbed key has been pressed): forwarded XKeyEvent that
   * matches keysym/modifiers pair
   */
  void grabKey(final long keysym, final long modifiers) {
    postEvent(
        new InvocationEvent(
            target,
            new Runnable() {
              public void run() {
                GrabbedKey grab = new GrabbedKey(keysym, modifiers);
                if (xembedLog.isLoggable(PlatformLogger.FINE))
                  xembedLog.fine("Grabbing key: " + grab);
                synchronized (GRAB_LOCK) {
                  grabbed_keys.add(grab);
                }
              }
            }));
  }

  void ungrabKey(final long keysym, final long modifiers) {
    postEvent(
        new InvocationEvent(
            target,
            new Runnable() {
              public void run() {
                GrabbedKey grab = new GrabbedKey(keysym, modifiers);
                if (xembedLog.isLoggable(PlatformLogger.FINE))
                  xembedLog.fine("UnGrabbing key: " + grab);
                synchronized (GRAB_LOCK) {
                  grabbed_keys.remove(grab);
                }
              }
            }));
  }

  void registerAccelerator(final long accel_id, final long keysym, final long modifiers) {
    postEvent(
        new InvocationEvent(
            target,
            new Runnable() {
              public void run() {
                AWTKeyStroke stroke = xembed.getKeyStrokeForKeySym(keysym, modifiers);
                if (stroke != null) {
                  if (xembedLog.isLoggable(PlatformLogger.FINE))
                    xembedLog.fine("Registering accelerator " + accel_id + " for " + stroke);
                  synchronized (ACCEL_LOCK) {
                    accelerators.put(accel_id, stroke);
                    accel_lookup.put(stroke, accel_id);
                  }
                }
                propogateRegisterAccelerator(stroke);
              }
            }));
  }

  void unregisterAccelerator(final long accel_id) {
    postEvent(
        new InvocationEvent(
            target,
            new Runnable() {
              public void run() {
                AWTKeyStroke stroke = null;
                synchronized (ACCEL_LOCK) {
                  stroke = accelerators.get(accel_id);
                  if (stroke != null) {
                    if (xembedLog.isLoggable(PlatformLogger.FINE))
                      xembedLog.fine("Unregistering accelerator: " + accel_id);
                    accelerators.remove(accel_id);
                    accel_lookup.remove(
                        stroke); // FIXME: How about several accelerators with the same stroke?
                  }
                }
                propogateUnRegisterAccelerator(stroke);
              }
            }));
  }

  void propogateRegisterAccelerator(AWTKeyStroke stroke) {
    // Find the top-level and see if it is XEmbed client. If so, ask him to
    // register the accelerator
    XWindowPeer parent = getToplevelXWindow();
    if (parent != null && parent instanceof XEmbeddedFramePeer) {
      XEmbeddedFramePeer embedded = (XEmbeddedFramePeer) parent;
      embedded.registerAccelerator(stroke);
    }
  }

  void propogateUnRegisterAccelerator(AWTKeyStroke stroke) {
    // Find the top-level and see if it is XEmbed client. If so, ask him to
    // register the accelerator
    XWindowPeer parent = getToplevelXWindow();
    if (parent != null && parent instanceof XEmbeddedFramePeer) {
      XEmbeddedFramePeer embedded = (XEmbeddedFramePeer) parent;
      embedded.unregisterAccelerator(stroke);
    }
  }

  public boolean postProcessKeyEvent(KeyEvent e) {
    // Processing events only if we are in the focused window but
    // we are not focus owner since otherwise we will get
    // duplicate shortcut events in the client - one is from
    // activate_accelerator, another from forwarded event
    // FIXME: This is probably an incompatibility, protocol
    // doesn't say anything about disable accelerators when client
    // is focused.

    XWindowPeer parent = getToplevelXWindow();
    if (parent == null || !((Window) parent.getTarget()).isFocused() || target.isFocusOwner()) {
      return false;
    }

    boolean result = false;

    if (xembedLog.isLoggable(PlatformLogger.FINER)) xembedLog.finer("Post-processing event " + e);

    // Process ACCELERATORS
    AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e);
    long accel_id = 0;
    boolean exists = false;
    synchronized (ACCEL_LOCK) {
      exists = accel_lookup.containsKey(stroke);
      if (exists) {
        accel_id = accel_lookup.get(stroke).longValue();
      }
    }
    if (exists) {
      if (xembedLog.isLoggable(PlatformLogger.FINE))
        xembedLog.fine("Activating accelerator " + accel_id);
      xembed.sendMessage(
          xembed.handle,
          XEMBED_ACTIVATE_ACCELERATOR,
          accel_id,
          0,
          0); // FIXME: How about overloaded?
      result = true;
    }

    // Process Grabs, unofficial GTK feature
    exists = false;
    GrabbedKey key = new GrabbedKey(e);
    synchronized (GRAB_LOCK) {
      exists = grabbed_keys.contains(key);
    }
    if (exists) {
      if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Forwarding grabbed key " + e);
      forwardKeyEvent(e);
      result = true;
    }

    return result;
  }

  public void modalityPushed(ModalityEvent ev) {
    xembed.sendMessage(xembed.handle, XEMBED_MODALITY_ON);
  }

  public void modalityPopped(ModalityEvent ev) {
    xembed.sendMessage(xembed.handle, XEMBED_MODALITY_OFF);
  }

  public void handleClientMessage(XEvent xev) {
    super.handleClientMessage(xev);
    XClientMessageEvent msg = xev.get_xclient();
    if (xembedLog.isLoggable(PlatformLogger.FINER))
      xembedLog.finer("Client message to embedder: " + msg);
    if (msg.get_message_type() == xembed.XEmbed.getAtom()) {
      if (xembedLog.isLoggable(PlatformLogger.FINE))
        xembedLog.fine(xembed.XEmbedMessageToString(msg));
    }
    if (isXEmbedActive()) {
      switch ((int) msg.get_data(1)) {
        case XEMBED_REQUEST_FOCUS:
          requestXEmbedFocus();
          break;
        case XEMBED_FOCUS_NEXT:
          focusNext();
          break;
        case XEMBED_FOCUS_PREV:
          focusPrev();
          break;
        case XEMBED_REGISTER_ACCELERATOR:
          registerAccelerator(msg.get_data(2), msg.get_data(3), msg.get_data(4));
          break;
        case XEMBED_UNREGISTER_ACCELERATOR:
          unregisterAccelerator(msg.get_data(2));
          break;
        case NON_STANDARD_XEMBED_GTK_GRAB_KEY:
          grabKey(msg.get_data(3), msg.get_data(4));
          break;
        case NON_STANDARD_XEMBED_GTK_UNGRAB_KEY:
          ungrabKey(msg.get_data(3), msg.get_data(4));
          break;
      }
    } else {
      xembedLog.finer("But XEmbed is not Active!");
    }
  }

  private static class XEmbedDropTarget extends DropTarget {
    public void addDropTargetListener(DropTargetListener dtl) throws TooManyListenersException {
      // Drop target listeners registered with this target will never be
      // notified, since all drag notifications are routed to the XEmbed
      // client. To avoid confusion we prohibit listeners registration
      // by throwing TooManyListenersException as if there is a listener
      // registered with this target already.
      throw new TooManyListenersException();
    }
  }

  public void setXEmbedDropTarget() {
    // Register a drop site on the top level.
    Runnable r =
        new Runnable() {
          public void run() {
            target.setDropTarget(new XEmbedDropTarget());
          }
        };
    SunToolkit.executeOnEventHandlerThread(target, r);
  }

  public void removeXEmbedDropTarget() {
    // Unregister a drop site on the top level.
    Runnable r =
        new Runnable() {
          public void run() {
            if (target.getDropTarget() instanceof XEmbedDropTarget) {
              target.setDropTarget(null);
            }
          }
        };
    SunToolkit.executeOnEventHandlerThread(target, r);
  }

  public boolean processXEmbedDnDEvent(long ctxt, int eventID) {
    if (xembedLog.isLoggable(PlatformLogger.FINEST)) {
      xembedLog.finest("     Drop target=" + target.getDropTarget());
    }
    if (target.getDropTarget() instanceof XEmbedDropTarget) {
      AppContext appContext = XToolkit.targetToAppContext(getTarget());
      XDropTargetContextPeer peer = XDropTargetContextPeer.getPeer(appContext);
      peer.forwardEventToEmbedded(xembed.handle, ctxt, eventID);
      return true;
    } else {
      return false;
    }
  }

  class XEmbedServer extends XEmbedHelper implements XEventDispatcher {
    long handle; // Handle to XEmbed client
    long version;
    long flags;

    boolean processXEmbedInfo() {
      long xembed_info_data = Native.allocateLongArray(2);
      try {
        if (!XEmbedInfo.getAtomData(handle, xembed_info_data, 2)) {
          // No more XEMBED_INFO? This is not XEmbed client!
          // Unfortunately this is the initial state of the most clients
          // FIXME: add 5-state processing
          // childDestroyed();
          xembedLog.finer("Unable to get XEMBED_INFO atom data");
          return false;
        }
        version = Native.getCard32(xembed_info_data, 0);
        flags = Native.getCard32(xembed_info_data, 1);
        boolean new_mapped = (flags & XEMBED_MAPPED) != 0;
        boolean currently_mapped = XlibUtil.getWindowMapState(handle) != XConstants.IsUnmapped;
        if (new_mapped != currently_mapped) {
          if (xembedLog.isLoggable(PlatformLogger.FINER))
            xembedLog.fine(
                "Mapping state of the client has changed, old state: "
                    + currently_mapped
                    + ", new state: "
                    + new_mapped);
          if (new_mapped) {
            XToolkit.awtLock();
            try {
              XlibWrapper.XMapWindow(XToolkit.getDisplay(), handle);
            } finally {
              XToolkit.awtUnlock();
            }
          } else {
            XToolkit.awtLock();
            try {
              XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), handle);
            } finally {
              XToolkit.awtUnlock();
            }
          }
        } else {
          xembedLog.finer("Mapping state didn't change, mapped: " + currently_mapped);
        }
        return true;
      } finally {
        XlibWrapper.unsafe.freeMemory(xembed_info_data);
      }
    }

    public void handlePropertyNotify(XEvent xev) {
      if (isXEmbedActive()) {
        XPropertyEvent ev = xev.get_xproperty();
        if (xembedLog.isLoggable(PlatformLogger.FINER))
          xembedLog.finer("Property change on client: " + ev);
        if (ev.get_atom() == XAtom.XA_WM_NORMAL_HINTS) {
          childResized();
        } else if (ev.get_atom() == XEmbedInfo.getAtom()) {
          processXEmbedInfo();
        } else if (ev.get_atom() == XDnDConstants.XA_XdndAware.getAtom()) {
          XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(), xembed.handle);
          if (ev.get_state() == XConstants.PropertyNewValue) {
            XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(), xembed.handle);
          }
        }
      } else {
        xembedLog.finer("XEmbed is not active");
      }
    }

    void handleConfigureNotify(XEvent xev) {
      if (isXEmbedActive()) {
        XConfigureEvent ev = xev.get_xconfigure();
        if (xembedLog.isLoggable(PlatformLogger.FINER))
          xembedLog.finer("Bounds change on client: " + ev);
        if (xev.get_xany().get_window() == handle) {
          childResized();
        }
      }
    }

    public void dispatchEvent(XEvent xev) {
      int type = xev.get_type();
      switch (type) {
        case XConstants.PropertyNotify:
          handlePropertyNotify(xev);
          break;
        case XConstants.ConfigureNotify:
          handleConfigureNotify(xev);
          break;
        case XConstants.ClientMessage:
          handleClientMessage(xev);
          break;
      }
    }
  }

  static class GrabbedKey {
    long keysym;
    long modifiers;

    GrabbedKey(long keysym, long modifiers) {
      this.keysym = keysym;
      this.modifiers = modifiers;
    }

    GrabbedKey(KeyEvent ev) {
      init(ev);
    }

    private void init(KeyEvent e) {
      byte[] bdata = getBData(e);
      long data = Native.toData(bdata);
      if (data == 0) {
        return;
      }
      try {
        XToolkit.awtLock();
        try {
          keysym = XWindow.getKeySymForAWTKeyCode(e.getKeyCode());
        } finally {
          XToolkit.awtUnlock();
        }
        XKeyEvent ke = new XKeyEvent(data);

        // We recognize only these masks
        modifiers =
            ke.get_state() & (XConstants.ShiftMask | XConstants.ControlMask | XConstants.LockMask);
        if (xembedLog.isLoggable(PlatformLogger.FINEST))
          xembedLog.finest("Mapped " + e + " to " + this);
      } finally {
        XlibWrapper.unsafe.freeMemory(data);
      }
    }

    public int hashCode() {
      return (int) keysym & 0xFFFFFFFF;
    }

    public boolean equals(Object o) {
      if (!(o instanceof GrabbedKey)) {
        return false;
      }
      GrabbedKey key = (GrabbedKey) o;
      return (keysym == key.keysym && modifiers == key.modifiers);
    }

    public String toString() {
      return "Key combination[keysym=" + keysym + ", mods=" + modifiers + "]";
    }
  }
}
Ejemplo n.º 6
0
/**
 * The AppContext is a table referenced by ThreadGroup which stores application service instances.
 * (If you are not writing an application service, or don't know what one is, please do not use this
 * class.) The AppContext allows applet access to what would otherwise be potentially dangerous
 * services, such as the ability to peek at EventQueues or change the look-and-feel of a Swing
 * application.
 *
 * <p>Most application services use a singleton object to provide their services, either as a
 * default (such as getSystemEventQueue or getDefaultToolkit) or as static methods with class data
 * (System). The AppContext works with the former method by extending the concept of "default" to be
 * ThreadGroup-specific. Application services lookup their singleton in the AppContext.
 *
 * <p>For example, here we have a Foo service, with its pre-AppContext code:
 *
 * <p><code><pre>
 *    public class Foo {
 *        private static Foo defaultFoo = new Foo();
 *
 *        public static Foo getDefaultFoo() {
 *            return defaultFoo;
 *        }
 *
 *    ... Foo service methods
 *    }</pre></code>
 *
 * <p>The problem with the above is that the Foo service is global in scope, so that applets and
 * other untrusted code can execute methods on the single, shared Foo instance. The Foo service
 * therefore either needs to block its use by untrusted code using a SecurityManager test, or
 * restrict its capabilities so that it doesn't matter if untrusted code executes it.
 *
 * <p>Here's the Foo class written to use the AppContext:
 *
 * <p><code><pre>
 *    public class Foo {
 *        public static Foo getDefaultFoo() {
 *            Foo foo = (Foo)AppContext.getAppContext().get(Foo.class);
 *            if (foo == null) {
 *                foo = new Foo();
 *                getAppContext().put(Foo.class, foo);
 *            }
 *            return foo;
 *        }
 *
 *    ... Foo service methods
 *    }</pre></code>
 *
 * <p>Since a separate AppContext can exist for each ThreadGroup, trusted and untrusted code have
 * access to different Foo instances. This allows untrusted code access to "system-wide" services --
 * the service remains within the AppContext "sandbox". For example, say a malicious applet wants to
 * peek all of the key events on the EventQueue to listen for passwords; if separate EventQueues are
 * used for each ThreadGroup using AppContexts, the only key events that applet will be able to
 * listen to are its own. A more reasonable applet request would be to change the Swing default
 * look-and-feel; with that default stored in an AppContext, the applet's look-and-feel will change
 * without disrupting other applets or potentially the browser itself.
 *
 * <p>Because the AppContext is a facility for safely extending application service support to
 * applets, none of its methods may be blocked by a a SecurityManager check in a valid Java
 * implementation. Applets may therefore safely invoke any of its methods without worry of being
 * blocked.
 *
 * <p>Note: If a SecurityManager is installed which derives from sun.awt.AWTSecurityManager, it may
 * override the AWTSecurityManager.getAppContext() method to return the proper AppContext based on
 * the execution context, in the case where the default ThreadGroup-based AppContext indexing would
 * return the main "system" AppContext. For example, in an applet situation, if a system thread
 * calls into an applet, rather than returning the main "system" AppContext (the one corresponding
 * to the system thread), an installed AWTSecurityManager may return the applet's AppContext based
 * on the execution context.
 *
 * @author Thomas Ball
 * @author Fred Ecks
 */
public final class AppContext extends AppContextDC {
  private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.AppContext");

  /* Since the contents of an AppContext are unique to each Java
   * session, this class should never be serialized. */

  /*
   * The key to put()/get() the Java EventQueue into/from the AppContext.
   */
  public static final Object EVENT_QUEUE_KEY = new StringBuffer("EventQueue");

  /*
   * The keys to store EventQueue push/pop lock and condition.
   */
  public static final Object EVENT_QUEUE_LOCK_KEY = new StringBuilder("EventQueue.Lock");
  public static final Object EVENT_QUEUE_COND_KEY = new StringBuilder("EventQueue.Condition");

  /* A map of AppContexts, referenced by ThreadGroup.
   */
  private static final Map<ThreadGroup, AppContext> threadGroup2appContext =
      Collections.synchronizedMap(new IdentityHashMap<ThreadGroup, AppContext>());

  /** Returns a set containing all <code>AppContext</code>s. */
  public static Set<AppContext> getAppContexts() {
    synchronized (threadGroup2appContext) {
      return new HashSet<AppContext>(threadGroup2appContext.values());
    }
  }

  /* The main "system" AppContext, used by everything not otherwise
    contained in another AppContext.
  */
  private static volatile AppContext mainAppContext = null;

  /*
   * The hash map associated with this AppContext.  A private delegate
   * is used instead of subclassing HashMap so as to avoid all of
   * HashMap's potentially risky methods, such as clear(), elements(),
   * putAll(), etc.
   */
  private final HashMap table = new HashMap();

  private final ThreadGroup threadGroup;

  /**
   * If any <code>PropertyChangeListeners</code> have been registered, the <code>changeSupport
   * </code> field describes them.
   *
   * @see #addPropertyChangeListener
   * @see #removePropertyChangeListener
   * @see #firePropertyChange
   */
  private PropertyChangeSupport changeSupport = null;

  public static final String DISPOSED_PROPERTY_NAME = "disposed";
  public static final String GUI_DISPOSED = "guidisposed";

  private volatile boolean isDisposed = false; // true if AppContext is disposed

  public boolean isDisposed() {
    return isDisposed;
  }

  static {
    // On the main Thread, we get the ThreadGroup, make a corresponding
    // AppContext, and instantiate the Java EventQueue.  This way, legacy
    // code is unaffected by the move to multiple AppContext ability.
    AccessController.doPrivileged(
        new PrivilegedAction() {
          public Object run() {
            ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
            ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
            while (parentThreadGroup != null) {
              // Find the root ThreadGroup to construct our main AppContext
              currentThreadGroup = parentThreadGroup;
              parentThreadGroup = currentThreadGroup.getParent();
            }
            mainAppContext = new AppContext(currentThreadGroup);
            numAppContexts = 1;
            return mainAppContext;
          }
        });
  }

  /*
   * The total number of AppContexts, system-wide.  This number is
   * incremented at the beginning of the constructor, and decremented
   * at the end of dispose().  getAppContext() checks to see if this
   * number is 1.  If so, it returns the sole AppContext without
   * checking Thread.currentThread().
   */
  private static volatile int numAppContexts;

  /*
   * The context ClassLoader that was used to create this AppContext.
   */
  private final ClassLoader contextClassLoader;

  /**
   * Constructor for AppContext. This method is <i>not</i> public, nor should it ever be used as
   * such. The proper way to construct an AppContext is through the use of
   * SunToolkit.createNewAppContext. A ThreadGroup is created for the new AppContext, a Thread is
   * created within that ThreadGroup, and that Thread calls SunToolkit.createNewAppContext before
   * calling anything else. That creates both the new AppContext and its EventQueue.
   *
   * @param threadGroup The ThreadGroup for the new AppContext
   * @see sun.awt.SunToolkit
   * @since 1.2
   */
  AppContext(ThreadGroup threadGroup) {
    numAppContexts++;

    this.threadGroup = threadGroup;
    threadGroup2appContext.put(threadGroup, this);

    this.contextClassLoader =
        AccessController.doPrivileged(
            new PrivilegedAction<ClassLoader>() {
              public ClassLoader run() {
                return Thread.currentThread().getContextClassLoader();
              }
            });

    // Initialize push/pop lock and its condition to be used by all the
    // EventQueues within this AppContext
    Lock eventQueuePushPopLock = new ReentrantLock();
    put(EVENT_QUEUE_LOCK_KEY, eventQueuePushPopLock);
    Condition eventQueuePushPopCond = eventQueuePushPopLock.newCondition();
    put(EVENT_QUEUE_COND_KEY, eventQueuePushPopCond);
  }

  private static final ThreadLocal<AppContext> threadAppContext = new ThreadLocal<AppContext>();

  /**
   * Returns the appropriate AppContext for the caller, as determined by its ThreadGroup. If the
   * main "system" AppContext would be returned and there's an AWTSecurityManager installed, it is
   * called to get the proper AppContext based on the execution context.
   *
   * @return the AppContext for the caller.
   * @see java.lang.ThreadGroup
   * @since 1.2
   */
  public static final AppContext getAppContext() {
    if (numAppContexts == 1) // If there's only one system-wide,
    return mainAppContext; // return the main system AppContext.

    AppContext appContext = threadAppContext.get();

    if (null == appContext) {
      appContext =
          AccessController.doPrivileged(
              new PrivilegedAction<AppContext>() {
                public AppContext run() {
                  // Get the current ThreadGroup, and look for it and its
                  // parents in the hash from ThreadGroup to AppContext --
                  // it should be found, because we use createNewContext()
                  // when new AppContext objects are created.
                  ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
                  ThreadGroup threadGroup = currentThreadGroup;
                  AppContext context = threadGroup2appContext.get(threadGroup);
                  while (context == null) {
                    threadGroup = threadGroup.getParent();
                    if (threadGroup == null) {
                      // If we get here, we're running under a ThreadGroup that
                      // has no AppContext associated with it.  This should never
                      // happen, because createNewContext() should be used by the
                      // toolkit to create the ThreadGroup that everything runs
                      // under.
                      throw new RuntimeException("Invalid ThreadGroup");
                    }
                    context = threadGroup2appContext.get(threadGroup);
                  }
                  // In case we did anything in the above while loop, we add
                  // all the intermediate ThreadGroups to threadGroup2appContext
                  // so we won't spin again.
                  for (ThreadGroup tg = currentThreadGroup;
                      tg != threadGroup;
                      tg = tg.getParent()) {
                    threadGroup2appContext.put(tg, context);
                  }
                  // Now we're done, so we cache the latest key/value pair.
                  // (we do this before checking with any AWTSecurityManager, so if
                  // this Thread equates with the main AppContext in the cache, it
                  // still will)
                  threadAppContext.set(context);

                  return context;
                }
              });
    }

    if (appContext == mainAppContext) {
      // Before we return the main "system" AppContext, check to
      // see if there's an AWTSecurityManager installed.  If so,
      // allow it to choose the AppContext to return.
      SecurityManager securityManager = System.getSecurityManager();
      if ((securityManager != null) && (securityManager instanceof AWTSecurityManager)) {
        AWTSecurityManager awtSecMgr = (AWTSecurityManager) securityManager;
        AppContext secAppContext = awtSecMgr.getAppContext();
        if (secAppContext != null) {
          appContext = secAppContext; // Return what we're told
        }
      }
    }

    return appContext;
  }

  /**
   * Returns the main ("system") AppContext.
   *
   * @return the main AppContext
   * @since 1.8
   */
  static final AppContext getMainAppContext() {
    return mainAppContext;
  }

  private long DISPOSAL_TIMEOUT = 5000; // Default to 5-second timeout
  // for disposal of all Frames
  // (we wait for this time twice,
  // once for dispose(), and once
  // to clear the EventQueue).

  private long THREAD_INTERRUPT_TIMEOUT = 1000;
  // Default to 1-second timeout for all
  // interrupted Threads to exit, and another
  // 1 second for all stopped Threads to die.

  /**
   * Disposes of this AppContext, all of its top-level Frames, and all Threads and ThreadGroups
   * contained within it.
   *
   * <p>This method must be called from a Thread which is not contained within this AppContext.
   *
   * @exception IllegalThreadStateException if the current thread is contained within this
   *     AppContext
   * @since 1.2
   */
  public void dispose() throws IllegalThreadStateException {
    // Check to be sure that the current Thread isn't in this AppContext
    if (this.threadGroup.parentOf(Thread.currentThread().getThreadGroup())) {
      throw new IllegalThreadStateException(
          "Current Thread is contained within AppContext to be disposed.");
    }

    synchronized (this) {
      if (this.isDisposed) {
        return; // If already disposed, bail.
      }
      this.isDisposed = true;
    }

    final PropertyChangeSupport changeSupport = this.changeSupport;
    if (changeSupport != null) {
      changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true);
    }

    // First, we post an InvocationEvent to be run on the
    // EventDispatchThread which disposes of all top-level Frames and TrayIcons

    final Object notificationLock = new Object();

    Runnable runnable =
        new Runnable() {
          public void run() {
            // Alert PropertyChangeListeners that the GUI has been disposed.
            if (changeSupport != null) {
              changeSupport.firePropertyChange(GUI_DISPOSED, false, true);
            }
            synchronized (notificationLock) {
              notificationLock.notifyAll(); // Notify caller that we're done
            }
          }
        };
    synchronized (notificationLock) {
      SunToolkit.postEvent(this, new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
      try {
        notificationLock.wait(DISPOSAL_TIMEOUT);
      } catch (InterruptedException e) {
      }
    }

    // Next, we post another InvocationEvent to the end of the
    // EventQueue.  When it's executed, we know we've executed all
    // events in the queue.

    runnable =
        new Runnable() {
          public void run() {
            synchronized (notificationLock) {
              notificationLock.notifyAll(); // Notify caller that we're done
            }
          }
        };
    synchronized (notificationLock) {
      SunToolkit.postEvent(this, new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
      try {
        notificationLock.wait(DISPOSAL_TIMEOUT);
      } catch (InterruptedException e) {
      }
    }

    // Next, we interrupt all Threads in the ThreadGroup
    this.threadGroup.interrupt();
    // Note, the EventDispatchThread we've interrupted may dump an
    // InterruptedException to the console here.  This needs to be
    // fixed in the EventDispatchThread, not here.

    // Next, we sleep 10ms at a time, waiting for all of the active
    // Threads in the ThreadGroup to exit.

    long startTime = System.currentTimeMillis();
    long endTime = startTime + THREAD_INTERRUPT_TIMEOUT;
    while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
      }
    }

    // Then, we stop any remaining Threads
    this.threadGroup.stop();

    // Next, we sleep 10ms at a time, waiting for all of the active
    // Threads in the ThreadGroup to die.

    startTime = System.currentTimeMillis();
    endTime = startTime + THREAD_INTERRUPT_TIMEOUT;
    while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
      }
    }

    // Next, we remove this and all subThreadGroups from threadGroup2appContext
    int numSubGroups = this.threadGroup.activeGroupCount();
    if (numSubGroups > 0) {
      ThreadGroup[] subGroups = new ThreadGroup[numSubGroups];
      numSubGroups = this.threadGroup.enumerate(subGroups);
      for (int subGroup = 0; subGroup < numSubGroups; subGroup++) {
        threadGroup2appContext.remove(subGroups[subGroup]);
      }
    }
    threadGroup2appContext.remove(this.threadGroup);

    threadAppContext.set(null);

    // Finally, we destroy the ThreadGroup entirely.
    try {
      this.threadGroup.destroy();
    } catch (IllegalThreadStateException e) {
      // Fired if not all the Threads died, ignore it and proceed
    }

    synchronized (table) {
      this.table.clear(); // Clear out the Hashtable to ease garbage collection
    }

    numAppContexts--;

    mostRecentKeyValue = null;
  }

  static final class PostShutdownEventRunnable implements Runnable {
    private final AppContext appContext;

    public PostShutdownEventRunnable(AppContext ac) {
      appContext = ac;
    }

    public void run() {
      final EventQueue eq = (EventQueue) appContext.get(EVENT_QUEUE_KEY);
      if (eq != null) {
        eq.postEvent(AWTAutoShutdown.getShutdownEvent());
      }
    }
  }

  static final class CreateThreadAction implements PrivilegedAction {
    private final AppContext appContext;
    private final Runnable runnable;

    public CreateThreadAction(AppContext ac, Runnable r) {
      appContext = ac;
      runnable = r;
    }

    public Object run() {
      Thread t = new Thread(appContext.getThreadGroup(), runnable);
      t.setContextClassLoader(appContext.getContextClassLoader());
      t.setPriority(Thread.NORM_PRIORITY + 1);
      t.setDaemon(true);
      return t;
    }
  }

  static void stopEventDispatchThreads() {
    for (AppContext appContext : getAppContexts()) {
      if (appContext.isDisposed()) {
        continue;
      }
      Runnable r = new PostShutdownEventRunnable(appContext);
      // For security reasons EventQueue.postEvent should only be called
      // on a thread that belongs to the corresponding thread group.
      if (appContext != AppContext.getAppContext()) {
        // Create a thread that belongs to the thread group associated
        // with the AppContext and invokes EventQueue.postEvent.
        PrivilegedAction action = new CreateThreadAction(appContext, r);
        Thread thread = (Thread) AccessController.doPrivileged(action);
        thread.start();
      } else {
        r.run();
      }
    }
  }

  private MostRecentKeyValue mostRecentKeyValue = null;
  private MostRecentKeyValue shadowMostRecentKeyValue = null;

  /**
   * Returns the value to which the specified key is mapped in this context.
   *
   * @param key a key in the AppContext.
   * @return the value to which the key is mapped in this AppContext; <code>null</code> if the key
   *     is not mapped to any value.
   * @see #put(Object, Object)
   * @since 1.2
   */
  public Object get(Object key) {
    /*
     * The most recent reference should be updated inside a synchronized
     * block to avoid a race when put() and get() are executed in
     * parallel on different threads.
     */
    synchronized (table) {
      // Note: this most recent key/value caching is thread-hot.
      // A simple test using SwingSet found that 72% of lookups
      // were matched using the most recent key/value.  By instantiating
      // a simple MostRecentKeyValue object on cache misses, the
      // cache hits can be processed without synchronization.

      MostRecentKeyValue recent = mostRecentKeyValue;
      if ((recent != null) && (recent.key == key)) {
        return recent.value;
      }

      Object value = table.get(key);
      if (mostRecentKeyValue == null) {
        mostRecentKeyValue = new MostRecentKeyValue(key, value);
        shadowMostRecentKeyValue = new MostRecentKeyValue(key, value);
      } else {
        MostRecentKeyValue auxKeyValue = mostRecentKeyValue;
        shadowMostRecentKeyValue.setPair(key, value);
        mostRecentKeyValue = shadowMostRecentKeyValue;
        shadowMostRecentKeyValue = auxKeyValue;
      }
      return value;
    }
  }

  /**
   * Maps the specified <code>key</code> to the specified <code>value</code> in this AppContext.
   * Neither the key nor the value can be <code>null</code>.
   *
   * <p>The value can be retrieved by calling the <code>get</code> method with a key that is equal
   * to the original key.
   *
   * @param key the AppContext key.
   * @param value the value.
   * @return the previous value of the specified key in this AppContext, or <code>null</code> if it
   *     did not have one.
   * @exception NullPointerException if the key or value is <code>null</code>.
   * @see #get(Object)
   * @since 1.2
   */
  public Object put(Object key, Object value) {
    synchronized (table) {
      MostRecentKeyValue recent = mostRecentKeyValue;
      if ((recent != null) && (recent.key == key)) recent.value = value;
      return table.put(key, value);
    }
  }

  /**
   * Removes the key (and its corresponding value) from this AppContext. This method does nothing if
   * the key is not in the AppContext.
   *
   * @param key the key that needs to be removed.
   * @return the value to which the key had been mapped in this AppContext, or <code>null</code> if
   *     the key did not have a mapping.
   * @since 1.2
   */
  public Object remove(Object key) {
    synchronized (table) {
      MostRecentKeyValue recent = mostRecentKeyValue;
      if ((recent != null) && (recent.key == key)) recent.value = null;
      return table.remove(key);
    }
  }

  /**
   * Returns the root ThreadGroup for all Threads contained within this AppContext.
   *
   * @since 1.2
   */
  public ThreadGroup getThreadGroup() {
    return threadGroup;
  }

  /**
   * Returns the context ClassLoader that was used to create this AppContext.
   *
   * @see java.lang.Thread#getContextClassLoader
   */
  public ClassLoader getContextClassLoader() {
    return contextClassLoader;
  }

  /**
   * Returns a string representation of this AppContext.
   *
   * @since 1.2
   */
  @Override
  public String toString() {
    return getClass().getName() + "[threadGroup=" + threadGroup.getName() + "]";
  }

  /**
   * Returns an array of all the property change listeners registered on this component.
   *
   * @return all of this component's <code>PropertyChangeListener</code>s or an empty array if no
   *     property change listeners are currently registered
   * @see #addPropertyChangeListener
   * @see #removePropertyChangeListener
   * @see #getPropertyChangeListeners(java.lang.String)
   * @see java.beans.PropertyChangeSupport#getPropertyChangeListeners
   * @since 1.4
   */
  public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
    if (changeSupport == null) {
      return new PropertyChangeListener[0];
    }
    return changeSupport.getPropertyChangeListeners();
  }

  /**
   * Adds a PropertyChangeListener to the listener list for a specific property. The specified
   * property may be one of the following:
   *
   * <ul>
   *   <li>if this AppContext is disposed ("disposed")
   * </ul>
   *
   * <ul>
   *   <li>if this AppContext's unowned Windows have been disposed ("guidisposed"). Code to cleanup
   *       after the GUI is disposed (such as LookAndFeel.uninitialize()) should execute in response
   *       to this property being fired. Notifications for the "guidisposed" property are sent on
   *       the event dispatch thread.
   * </ul>
   *
   * <p>If listener is null, no exception is thrown and no action is performed.
   *
   * @param propertyName one of the property names listed above
   * @param listener the PropertyChangeListener to be added
   * @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
   * @see #getPropertyChangeListeners(java.lang.String)
   * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
   */
  public synchronized void addPropertyChangeListener(
      String propertyName, PropertyChangeListener listener) {
    if (listener == null) {
      return;
    }
    if (changeSupport == null) {
      changeSupport = new PropertyChangeSupport(this);
    }
    changeSupport.addPropertyChangeListener(propertyName, listener);
  }

  /**
   * Removes a PropertyChangeListener from the listener list for a specific property. This method
   * should be used to remove PropertyChangeListeners that were registered for a specific bound
   * property.
   *
   * <p>If listener is null, no exception is thrown and no action is performed.
   *
   * @param propertyName a valid property name
   * @param listener the PropertyChangeListener to be removed
   * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
   * @see #getPropertyChangeListeners(java.lang.String)
   * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
   */
  public synchronized void removePropertyChangeListener(
      String propertyName, PropertyChangeListener listener) {
    if (listener == null || changeSupport == null) {
      return;
    }
    changeSupport.removePropertyChangeListener(propertyName, listener);
  }

  /**
   * Returns an array of all the listeners which have been associated with the named property.
   *
   * @return all of the <code>PropertyChangeListeners</code> associated with the named property or
   *     an empty array if no listeners have been added
   * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
   * @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
   * @see #getPropertyChangeListeners
   * @since 1.4
   */
  public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
    if (changeSupport == null) {
      return new PropertyChangeListener[0];
    }
    return changeSupport.getPropertyChangeListeners(propertyName);
  }
}
Ejemplo n.º 7
0
/**
 * This class implements window which serves as content window for decorated frames. Its purpose to
 * provide correct events dispatching for the complex constructs such as decorated frames.
 *
 * <p>It should always be located at (- left inset, - top inset) in the associated decorated window.
 * So coordinates in it would be the same as java coordinates.
 */
public final class XContentWindow extends XWindow {
  private static PlatformLogger insLog =
      PlatformLogger.getLogger("sun.awt.X11.insets.XContentWindow");

  static XContentWindow createContent(XDecoratedPeer parentFrame) {
    final WindowDimensions dims = parentFrame.getDimensions();
    Rectangle rec = dims.getBounds();
    // Fix for  - set the location of the content window to the (-left inset, -top inset)
    Insets ins = dims.getInsets();
    if (ins != null) {
      rec.x = -ins.left;
      rec.y = -ins.top;
    } else {
      rec.x = 0;
      rec.y = 0;
    }
    final XContentWindow cw = new XContentWindow(parentFrame, rec);
    cw.xSetVisible(true);
    return cw;
  }

  private final XDecoratedPeer parentFrame;

  // A list of expose events that come when the parentFrame is iconified
  private final java.util.List<SavedExposeEvent> iconifiedExposeEvents =
      new java.util.ArrayList<SavedExposeEvent>();

  private XContentWindow(XDecoratedPeer parentFrame, Rectangle bounds) {
    super((Component) parentFrame.getTarget(), parentFrame.getShell(), bounds);
    this.parentFrame = parentFrame;
  }

  void preInit(XCreateWindowParams params) {
    super.preInit(params);
    params.putIfNull(BIT_GRAVITY, Integer.valueOf(XConstants.NorthWestGravity));
    Long eventMask = (Long) params.get(EVENT_MASK);
    if (eventMask != null) {
      eventMask = eventMask & ~(XConstants.StructureNotifyMask);
      params.put(EVENT_MASK, eventMask);
    }
  }

  protected String getWMName() {
    return "Content window";
  }

  protected boolean isEventDisabled(XEvent e) {
    switch (e.get_type()) {
        // Override parentFrame to receive MouseEnter/Exit
      case XConstants.EnterNotify:
      case XConstants.LeaveNotify:
        return false;
        // We handle ConfigureNotify specifically in XDecoratedPeer
      case XConstants.ConfigureNotify:
        return true;
        // We don't want SHOWN/HIDDEN on content window since it will duplicate XDecoratedPeer
      case XConstants.MapNotify:
      case XConstants.UnmapNotify:
        return true;
      default:
        return super.isEventDisabled(e) || parentFrame.isEventDisabled(e);
    }
  }

  // Coordinates are that of the shell
  void setContentBounds(WindowDimensions dims) {
    XToolkit.awtLock();
    try {
      // Bounds of content window are of the same size as bounds of Java window and with
      // location as -(insets)
      Rectangle newBounds = dims.getBounds();
      Insets in = dims.getInsets();
      if (in != null) {
        newBounds.setLocation(-in.left, -in.top);
      }
      if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
        insLog.fine("Setting content bounds {0}, old bounds {1}", newBounds, getBounds());
      }
      // Fix for 5023533:
      // Change in the size of the content window means, well, change of the size
      // Change in the location of the content window means change in insets
      boolean needHandleResize = !(newBounds.equals(getBounds()));
      reshape(newBounds);
      if (needHandleResize) {
        insLog.fine("Sending RESIZED");
        handleResize(newBounds);
      }
    } finally {
      XToolkit.awtUnlock();
    }
    validateSurface();
  }

  // NOTE: This method may be called by privileged threads.
  //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  public void handleResize(Rectangle bounds) {
    AWTAccessor.getComponentAccessor().setSize((Component) target, bounds.width, bounds.height);
    postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED));
  }

  public void handleExposeEvent(Component target, int x, int y, int w, int h) {
    // TODO: ?
    // get rid of 'istanceof' by subclassing:
    // XContentWindow -> XFrameContentWindow

    // Expose event(s) that result from deiconification
    // come before a deicinofication notification.
    // We reorder these events by saving all expose events
    // that come when the frame is iconified. Then we
    // actually handle saved expose events on deiconification.

    if (parentFrame instanceof XFramePeer
        && (((XFramePeer) parentFrame).getState() & java.awt.Frame.ICONIFIED) != 0) {
      // Save expose events if the frame is iconified
      // in order to handle them on deiconification.
      iconifiedExposeEvents.add(new SavedExposeEvent(target, x, y, w, h));
    } else {
      // Normal case: [it is not a frame or] the frame is not iconified.
      super.handleExposeEvent(target, x, y, w, h);
    }
  }

  void purgeIconifiedExposeEvents() {
    for (SavedExposeEvent evt : iconifiedExposeEvents) {
      super.handleExposeEvent(evt.target, evt.x, evt.y, evt.w, evt.h);
    }
    iconifiedExposeEvents.clear();
  }

  private static class SavedExposeEvent {
    Component target;
    int x, y, w, h;

    SavedExposeEvent(Component target, int x, int y, int w, int h) {
      this.target = target;
      this.x = x;
      this.y = y;
      this.w = w;
      this.h = h;
    }
  }

  public String toString() {
    return getClass().getName() + "[" + getBounds() + "]";
  }
}
Ejemplo n.º 8
0
public class LWWindowPeer extends LWContainerPeer<Window, JComponent>
    implements FramePeer,
        DialogPeer,
        FullScreenCapable,
        DisplayChangedListener,
        PlatformEventNotifier {
  public enum PeerType {
    SIMPLEWINDOW,
    FRAME,
    DIALOG,
    EMBEDDED_FRAME,
    VIEW_EMBEDDED_FRAME,
    LW_FRAME
  }

  private static final PlatformLogger focusLog =
      PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer");

  private final PlatformWindow platformWindow;

  private static final int MINIMUM_WIDTH = 1;
  private static final int MINIMUM_HEIGHT = 1;

  private Insets insets = new Insets(0, 0, 0, 0);

  private GraphicsDevice graphicsDevice;
  private GraphicsConfiguration graphicsConfig;

  private SurfaceData surfaceData;
  private final Object surfaceDataLock = new Object();

  private volatile int windowState = Frame.NORMAL;

  // check that the mouse is over the window
  private volatile boolean isMouseOver = false;

  // A peer where the last mouse event came to. Used by cursor manager to
  // find the component under cursor
  private static volatile LWComponentPeer<?, ?> lastCommonMouseEventPeer;

  // A peer where the last mouse event came to. Used to generate
  // MOUSE_ENTERED/EXITED notifications
  private volatile LWComponentPeer<?, ?> lastMouseEventPeer;

  // Peers where all dragged/released events should come to,
  // depending on what mouse button is being dragged according to Cocoa
  private static final LWComponentPeer<?, ?>[] mouseDownTarget = new LWComponentPeer<?, ?>[3];

  // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events
  // on MOUSE_RELEASE. Click events are only generated if there were no drag
  // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button
  private static int mouseClickButtons = 0;

  private volatile boolean isOpaque = true;

  private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13);

  private static LWWindowPeer grabbingWindow;

  private volatile boolean skipNextFocusChange;

  private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0);

  private volatile boolean textured;

  private final PeerType peerType;

  private final SecurityWarningWindow warningWindow;

  private volatile boolean targetFocusable;

  /**
   * Current modal blocker or null.
   *
   * <p>Synchronization: peerTreeLock.
   */
  private LWWindowPeer blocker;

  public LWWindowPeer(
      Window target,
      PlatformComponent platformComponent,
      PlatformWindow platformWindow,
      PeerType peerType) {
    super(target, platformComponent);
    this.platformWindow = platformWindow;
    this.peerType = peerType;

    Window owner = target.getOwner();
    LWWindowPeer ownerPeer =
        owner == null ? null : (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner);
    PlatformWindow ownerDelegate = (ownerPeer != null) ? ownerPeer.getPlatformWindow() : null;

    // The delegate.initialize() needs a non-null GC on X11.
    GraphicsConfiguration gc = getTarget().getGraphicsConfiguration();
    synchronized (getStateLock()) {
      // graphicsConfig should be updated according to the real window
      // bounds when the window is shown, see 4868278
      this.graphicsConfig = gc;
    }

    if (!target.isFontSet()) {
      target.setFont(DEFAULT_FONT);
    }

    if (!target.isBackgroundSet()) {
      target.setBackground(SystemColor.window);
    } else {
      // first we check if user provided alpha for background. This is
      // similar to what Apple's Java do.
      // Since JDK7 we should rely on setOpacity() only.
      // this.opacity = c.getAlpha();
    }

    if (!target.isForegroundSet()) {
      target.setForeground(SystemColor.windowText);
      // we should not call setForeground because it will call a repaint
      // which the peer may not be ready to do yet.
    }

    platformWindow.initialize(target, this, ownerDelegate);

    // Init warning window(for applets)
    SecurityWarningWindow warn = null;
    if (target.getWarningString() != null) {
      // accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip
      // and TrayIcon balloon windows without a warning window.
      if (!AWTAccessor.getWindowAccessor().isTrayIconWindow(target)) {
        LWToolkit toolkit = (LWToolkit) Toolkit.getDefaultToolkit();
        warn = toolkit.createSecurityWarning(target, this);
      }
    }

    warningWindow = warn;
  }

  @Override
  void initializeImpl() {
    super.initializeImpl();

    if (getTarget() instanceof Frame) {
      setTitle(((Frame) getTarget()).getTitle());
      setState(((Frame) getTarget()).getExtendedState());
    } else if (getTarget() instanceof Dialog) {
      setTitle(((Dialog) getTarget()).getTitle());
    }

    updateAlwaysOnTopState();
    updateMinimumSize();
    updateFocusableWindowState();

    final Shape shape = getTarget().getShape();
    if (shape != null) {
      applyShape(Region.getInstance(shape, null));
    }

    final float opacity = getTarget().getOpacity();
    if (opacity < 1.0f) {
      setOpacity(opacity);
    }

    setOpaque(getTarget().isOpaque());

    updateInsets(platformWindow.getInsets());
    if (getSurfaceData() == null) {
      replaceSurfaceData(false);
    }
    activateDisplayListener();
  }

  // Just a helper method
  @Override
  public PlatformWindow getPlatformWindow() {
    return platformWindow;
  }

  @Override
  protected LWWindowPeer getWindowPeerOrSelf() {
    return this;
  }

  // ---- PEER METHODS ---- //

  @Override
  protected void disposeImpl() {
    deactivateDisplayListener();
    SurfaceData oldData = getSurfaceData();
    synchronized (surfaceDataLock) {
      surfaceData = null;
    }
    if (oldData != null) {
      oldData.invalidate();
    }
    if (isGrabbing()) {
      ungrab();
    }
    if (warningWindow != null) {
      warningWindow.dispose();
    }

    platformWindow.dispose();
    super.disposeImpl();
  }

  @Override
  protected void setVisibleImpl(final boolean visible) {
    if (!visible && warningWindow != null) {
      warningWindow.setVisible(false, false);
    }
    updateFocusableWindowState();
    super.setVisibleImpl(visible);
    // TODO: update graphicsConfig, see 4868278
    platformWindow.setVisible(visible);
    if (isSimpleWindow()) {
      KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
      if (visible) {
        if (!getTarget().isAutoRequestFocus()) {
          return;
        } else {
          requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION);
        }
        // Focus the owner in case this window is focused.
      } else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) {
        // Transfer focus to the owner.
        LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this);
        if (owner != null) {
          owner.requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION);
        }
      }
    }
  }

  @Override
  public final GraphicsConfiguration getGraphicsConfiguration() {
    synchronized (getStateLock()) {
      return graphicsConfig;
    }
  }

  @Override
  public boolean updateGraphicsData(GraphicsConfiguration gc) {
    setGraphicsConfig(gc);
    return false;
  }

  protected final Graphics getOnscreenGraphics(Color fg, Color bg, Font f) {
    if (getSurfaceData() == null) {
      return null;
    }
    if (fg == null) {
      fg = SystemColor.windowText;
    }
    if (bg == null) {
      bg = SystemColor.window;
    }
    if (f == null) {
      f = DEFAULT_FONT;
    }
    return platformWindow.transformGraphics(new SunGraphics2D(getSurfaceData(), fg, bg, f));
  }

  @Override
  public void setBounds(int x, int y, int w, int h, int op) {

    if ((op & NO_EMBEDDED_CHECK) == 0 && getPeerType() == PeerType.VIEW_EMBEDDED_FRAME) {
      return;
    }

    if ((op & SET_CLIENT_SIZE) != 0) {
      // SET_CLIENT_SIZE is only applicable to window peers, so handle it here
      // instead of pulling 'insets' field up to LWComponentPeer
      // no need to add insets since Window's notion of width and height includes insets.
      op &= ~SET_CLIENT_SIZE;
      op |= SET_SIZE;
    }

    // Don't post ComponentMoved/Resized and Paint events
    // until we've got a notification from the delegate
    Rectangle cb = constrainBounds(x, y, w, h);

    Rectangle newBounds = new Rectangle(getBounds());
    if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {
      newBounds.x = cb.x;
      newBounds.y = cb.y;
    }
    if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {
      newBounds.width = cb.width;
      newBounds.height = cb.height;
    }
    // Native system could constraint bounds, so the peer wold be updated in the callback
    platformWindow.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height);
  }

  public Rectangle constrainBounds(Rectangle bounds) {
    return constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height);
  }

  public Rectangle constrainBounds(int x, int y, int w, int h) {

    if (w < MINIMUM_WIDTH) {
      w = MINIMUM_WIDTH;
    }

    if (h < MINIMUM_HEIGHT) {
      h = MINIMUM_HEIGHT;
    }

    final int maxW = getLWGC().getMaxTextureWidth();
    final int maxH = getLWGC().getMaxTextureHeight();

    if (w > maxW) {
      w = maxW;
    }
    if (h > maxH) {
      h = maxH;
    }

    return new Rectangle(x, y, w, h);
  }

  @Override
  public Point getLocationOnScreen() {
    return platformWindow.getLocationOnScreen();
  }

  /**
   * Overridden from LWContainerPeer to return the correct insets. Insets are queried from the
   * delegate and are kept up to date by requiering when needed (i.e. when the window geometry is
   * changed).
   */
  @Override
  public Insets getInsets() {
    synchronized (getStateLock()) {
      return insets;
    }
  }

  @Override
  public FontMetrics getFontMetrics(Font f) {
    // TODO: check for "use platform metrics" settings
    return platformWindow.getFontMetrics(f);
  }

  @Override
  public void toFront() {
    platformWindow.toFront();
  }

  @Override
  public void toBack() {
    platformWindow.toBack();
  }

  @Override
  public void setZOrder(ComponentPeer above) {
    throw new RuntimeException("not implemented");
  }

  @Override
  public void updateAlwaysOnTopState() {
    platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop());
  }

  @Override
  public void updateFocusableWindowState() {
    targetFocusable = getTarget().isFocusableWindow();
    platformWindow.updateFocusableWindowState();
  }

  @Override
  public void setModalBlocked(Dialog blocker, boolean blocked) {
    synchronized (getPeerTreeLock()) {
      ComponentPeer peer = AWTAccessor.getComponentAccessor().getPeer(blocker);
      if (blocked && (peer instanceof LWWindowPeer)) {
        this.blocker = (LWWindowPeer) peer;
      } else {
        this.blocker = null;
      }
    }

    platformWindow.setModalBlocked(blocked);
  }

  @Override
  public void updateMinimumSize() {
    final Dimension min;
    if (getTarget().isMinimumSizeSet()) {
      min = getTarget().getMinimumSize();
      min.width = Math.max(min.width, MINIMUM_WIDTH);
      min.height = Math.max(min.height, MINIMUM_HEIGHT);
    } else {
      min = new Dimension(MINIMUM_WIDTH, MINIMUM_HEIGHT);
    }

    final Dimension max;
    if (getTarget().isMaximumSizeSet()) {
      max = getTarget().getMaximumSize();
      max.width = Math.min(max.width, getLWGC().getMaxTextureWidth());
      max.height = Math.min(max.height, getLWGC().getMaxTextureHeight());
    } else {
      max = new Dimension(getLWGC().getMaxTextureWidth(), getLWGC().getMaxTextureHeight());
    }

    platformWindow.setSizeConstraints(min.width, min.height, max.width, max.height);
  }

  @Override
  public void updateIconImages() {
    getPlatformWindow().updateIconImages();
  }

  @Override
  public void setBackground(final Color c) {
    super.setBackground(c);
    updateOpaque();
  }

  @Override
  public void setOpacity(float opacity) {
    getPlatformWindow().setOpacity(opacity);
    repaintPeer();
  }

  @Override
  public final void setOpaque(final boolean isOpaque) {
    if (this.isOpaque != isOpaque) {
      this.isOpaque = isOpaque;
      updateOpaque();
    }
  }

  private void updateOpaque() {
    getPlatformWindow().setOpaque(!isTranslucent());
    replaceSurfaceData(false);
    repaintPeer();
  }

  @Override
  public void updateWindow() {}

  public final boolean isTextured() {
    return textured;
  }

  public final void setTextured(final boolean isTextured) {
    textured = isTextured;
  }

  @Override
  public final boolean isTranslucent() {
    synchronized (getStateLock()) {
      /*
       * Textured window is a special case of translucent window.
       * The difference is only in nswindow background. So when we set
       * texture property our peer became fully translucent. It doesn't
       * fill background, create non opaque backbuffers and layer etc.
       */
      return !isOpaque || isShaped() || isTextured();
    }
  }

  @Override
  final void applyShapeImpl(final Region shape) {
    super.applyShapeImpl(shape);
    updateOpaque();
  }

  @Override
  public void repositionSecurityWarning() {
    if (warningWindow != null) {
      AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
      Window target = getTarget();
      int x = compAccessor.getX(target);
      int y = compAccessor.getY(target);
      int width = compAccessor.getWidth(target);
      int height = compAccessor.getHeight(target);
      warningWindow.reposition(x, y, width, height);
    }
  }

  // ---- FRAME PEER METHODS ---- //

  @Override // FramePeer and DialogPeer
  public void setTitle(String title) {
    platformWindow.setTitle(title == null ? "" : title);
  }

  @Override
  public void setMenuBar(MenuBar mb) {
    platformWindow.setMenuBar(mb);
  }

  @Override // FramePeer and DialogPeer
  public void setResizable(boolean resizable) {
    platformWindow.setResizable(resizable);
  }

  @Override
  public void setState(int state) {
    platformWindow.setWindowState(state);
  }

  @Override
  public int getState() {
    return windowState;
  }

  @Override
  public void setMaximizedBounds(Rectangle bounds) {
    // TODO: not implemented
  }

  @Override
  public void setBoundsPrivate(int x, int y, int width, int height) {
    setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);
  }

  @Override
  public Rectangle getBoundsPrivate() {
    throw new RuntimeException("not implemented");
  }

  // ---- DIALOG PEER METHODS ---- //

  @Override
  public void blockWindows(List<Window> windows) {
    // TODO: LWX will probably need some collectJavaToplevels to speed this up
    for (Window w : windows) {
      WindowPeer wp = (WindowPeer) AWTAccessor.getComponentAccessor().getPeer(w);
      if (wp != null) {
        wp.setModalBlocked((Dialog) getTarget(), true);
      }
    }
  }

  // ---- PEER NOTIFICATIONS ---- //

  @Override
  public void notifyIconify(boolean iconify) {
    // The toplevel target is Frame and states are applicable to it.
    // Otherwise, the target is Window and it don't have state property.
    // Hopefully, no such events are posted in the queue so consider the
    // target as Frame in all cases.

    // REMIND: should we send it anyway if the state not changed since last
    // time?
    WindowEvent iconifyEvent =
        new WindowEvent(
            getTarget(), iconify ? WindowEvent.WINDOW_ICONIFIED : WindowEvent.WINDOW_DEICONIFIED);
    postEvent(iconifyEvent);

    int newWindowState = iconify ? Frame.ICONIFIED : Frame.NORMAL;
    postWindowStateChangedEvent(newWindowState);

    // REMIND: RepaintManager doesn't repaint iconified windows and
    // hence ignores any repaint request during deiconification.
    // So, we need to repaint window explicitly when it becomes normal.
    if (!iconify) {
      repaintPeer();
    }
  }

  @Override
  public void notifyZoom(boolean isZoomed) {
    int newWindowState = isZoomed ? Frame.MAXIMIZED_BOTH : Frame.NORMAL;
    postWindowStateChangedEvent(newWindowState);
  }

  /** Called by the {@code PlatformWindow} when any part of the window should be repainted. */
  @Override
  public void notifyExpose(final Rectangle r) {
    repaintPeer(r);
  }

  /**
   * Called by the {@code PlatformWindow} when this window is moved/resized by user or window insets
   * are changed. There's no notifyReshape() in LWComponentPeer as the only components which could
   * be resized by user are top-level windows.
   */
  @Override
  public void notifyReshape(int x, int y, int w, int h) {
    Rectangle oldBounds = getBounds();
    final boolean invalid = updateInsets(platformWindow.getInsets());
    final boolean moved = (x != oldBounds.x) || (y != oldBounds.y);
    final boolean resized = (w != oldBounds.width) || (h != oldBounds.height);

    // Check if anything changed
    if (!moved && !resized && !invalid) {
      return;
    }
    // First, update peer's bounds
    setBounds(x, y, w, h, SET_BOUNDS, false, false);

    // Second, update the graphics config and surface data
    final boolean isNewDevice = updateGraphicsDevice();
    if (resized || isNewDevice) {
      replaceSurfaceData();
      updateMinimumSize();
    }

    // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
    if (moved || invalid) {
      handleMove(x, y, true);
    }
    if (resized || invalid || isNewDevice) {
      handleResize(w, h, true);
      repaintPeer();
    }

    repositionSecurityWarning();
  }

  private void clearBackground(final int w, final int h) {
    final Graphics g = getOnscreenGraphics(getForeground(), getBackground(), getFont());
    if (g != null) {
      try {
        if (g instanceof Graphics2D) {
          ((Graphics2D) g).setComposite(AlphaComposite.Src);
        }
        if (isTranslucent()) {
          g.setColor(nonOpaqueBackground);
          g.fillRect(0, 0, w, h);
        }
        if (!isTextured()) {
          if (g instanceof SunGraphics2D) {
            ((SunGraphics2D) g).constrain(0, 0, w, h, getRegion());
          }
          g.setColor(getBackground());
          g.fillRect(0, 0, w, h);
        }
      } finally {
        g.dispose();
      }
    }
  }

  @Override
  public void notifyUpdateCursor() {
    getLWToolkit().getCursorManager().updateCursorLater(this);
  }

  @Override
  public void notifyActivation(boolean activation, LWWindowPeer opposite) {
    Window oppositeWindow = (opposite == null) ? null : opposite.getTarget();
    changeFocusedWindow(activation, oppositeWindow);
  }

  // MouseDown in non-client area
  @Override
  public void notifyNCMouseDown() {
    // Ungrab except for a click on a Dialog with the grabbing owner
    if (grabbingWindow != null && !grabbingWindow.isOneOfOwnersOf(this)) {
      grabbingWindow.ungrab();
    }
  }

  // ---- EVENTS ---- //

  /*
   * Called by the delegate to dispatch the event to Java. Event
   * coordinates are relative to non-client window are, i.e. the top-left
   * point of the client area is (insets.top, insets.left).
   */
  @Override
  public void notifyMouseEvent(
      PlatformWindow eventPlatformWindow,
      int id,
      long when,
      int button,
      int x,
      int y,
      int screenX,
      int screenY,
      int modifiers,
      int clickCount,
      boolean popupTrigger,
      byte[] bdata) {
    // TODO: fill "bdata" member of AWTEvent
    Rectangle r = getBounds();
    // findPeerAt() expects parent coordinates
    LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);

    if (id == MouseEvent.MOUSE_EXITED) {
      isMouseOver = false;
      if (lastMouseEventPeer != null) {
        if (lastMouseEventPeer.isEnabled()) {
          Point lp = lastMouseEventPeer.windowToLocal(x, y, this);
          Component target = lastMouseEventPeer.getTarget();
          postMouseExitedEvent(
              target, when, modifiers, lp, screenX, screenY, clickCount, popupTrigger, button);
        }

        // Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched
        // to a peer from another window. So we must first check if this peer is
        // the same as lastWindowPeer
        if (lastCommonMouseEventPeer != null
            && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) {
          lastCommonMouseEventPeer = null;
        }
        lastMouseEventPeer = null;
      }
    } else if (id == MouseEvent.MOUSE_ENTERED) {
      isMouseOver = true;
      if (targetPeer != null) {
        if (targetPeer.isEnabled()) {
          Point lp = targetPeer.windowToLocal(x, y, this);
          Component target = targetPeer.getTarget();
          postMouseEnteredEvent(
              target, when, modifiers, lp, screenX, screenY, clickCount, popupTrigger, button);
        }
        lastCommonMouseEventPeer = targetPeer;
        lastMouseEventPeer = targetPeer;
      }
    } else {

      LWWindowPeer topmostWindowPeer =
          eventPlatformWindow != null ? eventPlatformWindow.getPeer() : null;

      // topmostWindowPeer == null condition is added for the backward
      // compatibility with applets. It can be removed when the
      // getTopmostPlatformWindowUnderMouse() method will be properly
      // implemented in CPlatformEmbeddedFrame class
      if (topmostWindowPeer == this || topmostWindowPeer == null) {
        generateMouseEnterExitEventsForComponents(
            when, button, x, y, screenX, screenY, modifiers, clickCount, popupTrigger, targetPeer);
      } else {
        LWComponentPeer<?, ?> topmostTargetPeer = topmostWindowPeer.findPeerAt(r.x + x, r.y + y);
        topmostWindowPeer.generateMouseEnterExitEventsForComponents(
            when,
            button,
            x,
            y,
            screenX,
            screenY,
            modifiers,
            clickCount,
            popupTrigger,
            topmostTargetPeer);
      }

      // TODO: fill "bdata" member of AWTEvent

      int eventButtonMask = (button > 0) ? MouseEvent.getMaskForButton(button) : 0;
      int otherButtonsPressed = modifiers & ~eventButtonMask;

      // For pressed/dragged/released events OS X treats other
      // mouse buttons as if they were BUTTON2, so we do the same
      int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1;

      // MOUSE_ENTERED/EXITED are generated for the components strictly under
      // mouse even when dragging. That's why we first update lastMouseEventPeer
      // based on initial targetPeer value and only then recalculate targetPeer
      // for MOUSE_DRAGGED/RELEASED events
      if (id == MouseEvent.MOUSE_PRESSED) {

        // Ungrab only if this window is not an owned window of the grabbing one.
        if (!isGrabbing() && grabbingWindow != null && !grabbingWindow.isOneOfOwnersOf(this)) {
          grabbingWindow.ungrab();
        }
        if (otherButtonsPressed == 0) {
          mouseClickButtons = eventButtonMask;
        } else {
          mouseClickButtons |= eventButtonMask;
        }

        // The window should be focused on mouse click. If it gets activated by the native platform,
        // this request will be no op. It will take effect when:
        // 1. A simple not focused window is clicked.
        // 2. An active but not focused owner frame/dialog is clicked.
        // The mouse event then will trigger a focus request "in window" to the component, so the
        // window
        // should gain focus before.
        requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);

        mouseDownTarget[targetIdx] = targetPeer;
      } else if (id == MouseEvent.MOUSE_DRAGGED) {
        // Cocoa dragged event has the information about which mouse
        // button is being dragged. Use it to determine the peer that
        // should receive the dragged event.
        targetPeer = mouseDownTarget[targetIdx];
        mouseClickButtons &= ~modifiers;
      } else if (id == MouseEvent.MOUSE_RELEASED) {
        // TODO: currently, mouse released event goes to the same component
        // that received corresponding mouse pressed event. For most cases,
        // it's OK, however, we need to make sure that our behavior is consistent
        // with 1.6 for cases where component in question have been
        // hidden/removed in between of mouse pressed/released events.
        targetPeer = mouseDownTarget[targetIdx];

        if ((modifiers & eventButtonMask) == 0) {
          mouseDownTarget[targetIdx] = null;
        }

        // mouseClickButtons is updated below, after MOUSE_CLICK is sent
      }

      if (targetPeer == null) {
        // TODO This can happen if this window is invisible. this is correct behavior in this case?
        targetPeer = this;
      }

      Point lp = targetPeer.windowToLocal(x, y, this);
      if (targetPeer.isEnabled()) {
        MouseEvent event =
            new MouseEvent(
                targetPeer.getTarget(),
                id,
                when,
                modifiers,
                lp.x,
                lp.y,
                screenX,
                screenY,
                clickCount,
                popupTrigger,
                button);
        postEvent(event);
      }

      if (id == MouseEvent.MOUSE_RELEASED) {
        if ((mouseClickButtons & eventButtonMask) != 0 && targetPeer.isEnabled()) {
          postEvent(
              new MouseEvent(
                  targetPeer.getTarget(),
                  MouseEvent.MOUSE_CLICKED,
                  when,
                  modifiers,
                  lp.x,
                  lp.y,
                  screenX,
                  screenY,
                  clickCount,
                  popupTrigger,
                  button));
        }
        mouseClickButtons &= ~eventButtonMask;
      }
    }
    notifyUpdateCursor();
  }

  private void generateMouseEnterExitEventsForComponents(
      long when,
      int button,
      int x,
      int y,
      int screenX,
      int screenY,
      int modifiers,
      int clickCount,
      boolean popupTrigger,
      final LWComponentPeer<?, ?> targetPeer) {

    if (!isMouseOver || targetPeer == lastMouseEventPeer) {
      return;
    }

    // Generate Mouse Exit for components
    if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) {
      Point oldp = lastMouseEventPeer.windowToLocal(x, y, this);
      Component target = lastMouseEventPeer.getTarget();
      postMouseExitedEvent(
          target, when, modifiers, oldp, screenX, screenY, clickCount, popupTrigger, button);
    }
    lastCommonMouseEventPeer = targetPeer;
    lastMouseEventPeer = targetPeer;

    // Generate Mouse Enter for components
    if (targetPeer != null && targetPeer.isEnabled()) {
      Point newp = targetPeer.windowToLocal(x, y, this);
      Component target = targetPeer.getTarget();
      postMouseEnteredEvent(
          target, when, modifiers, newp, screenX, screenY, clickCount, popupTrigger, button);
    }
  }

  private void postMouseEnteredEvent(
      Component target,
      long when,
      int modifiers,
      Point loc,
      int xAbs,
      int yAbs,
      int clickCount,
      boolean popupTrigger,
      int button) {

    updateSecurityWarningVisibility();

    postEvent(
        new MouseEvent(
            target,
            MouseEvent.MOUSE_ENTERED,
            when,
            modifiers,
            loc.x,
            loc.y,
            xAbs,
            yAbs,
            clickCount,
            popupTrigger,
            button));
  }

  private void postMouseExitedEvent(
      Component target,
      long when,
      int modifiers,
      Point loc,
      int xAbs,
      int yAbs,
      int clickCount,
      boolean popupTrigger,
      int button) {

    updateSecurityWarningVisibility();

    postEvent(
        new MouseEvent(
            target,
            MouseEvent.MOUSE_EXITED,
            when,
            modifiers,
            loc.x,
            loc.y,
            xAbs,
            yAbs,
            clickCount,
            popupTrigger,
            button));
  }

  @Override
  public void notifyMouseWheelEvent(
      long when,
      int x,
      int y,
      int modifiers,
      int scrollType,
      int scrollAmount,
      int wheelRotation,
      double preciseWheelRotation,
      byte[] bdata) {
    // TODO: could we just use the last mouse event target here?
    Rectangle r = getBounds();
    // findPeerAt() expects parent coordinates
    final LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);
    if (targetPeer == null || !targetPeer.isEnabled()) {
      return;
    }

    Point lp = targetPeer.windowToLocal(x, y, this);
    // TODO: fill "bdata" member of AWTEvent
    // TODO: screenX/screenY
    postEvent(
        new MouseWheelEvent(
            targetPeer.getTarget(),
            MouseEvent.MOUSE_WHEEL,
            when,
            modifiers,
            lp.x,
            lp.y,
            0,
            0, /* screenX, Y */
            0 /* clickCount */,
            false /* popupTrigger */,
            scrollType,
            scrollAmount,
            wheelRotation,
            preciseWheelRotation));
  }

  /*
   * Called by the delegate when a key is pressed.
   */
  @Override
  public void notifyKeyEvent(
      int id, long when, int modifiers, int keyCode, char keyChar, int keyLocation) {
    LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
    Component focusOwner = kfmPeer.getCurrentFocusOwner();

    if (focusOwner == null) {
      focusOwner = kfmPeer.getCurrentFocusedWindow();
      if (focusOwner == null) {
        focusOwner = this.getTarget();
      }
    }

    KeyEvent keyEvent =
        new KeyEvent(focusOwner, id, when, modifiers, keyCode, keyChar, keyLocation);
    AWTAccessor.getKeyEventAccessor()
        .setExtendedKeyCode(
            keyEvent,
            (keyChar == KeyEvent.CHAR_UNDEFINED)
                ? keyCode
                : ExtendedKeyCodes.getExtendedKeyCodeForChar(keyChar));
    postEvent(keyEvent);
  }

  // ---- UTILITY METHODS ---- //

  private void activateDisplayListener() {
    final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    ((SunGraphicsEnvironment) ge).addDisplayChangedListener(this);
  }

  private void deactivateDisplayListener() {
    final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    ((SunGraphicsEnvironment) ge).removeDisplayChangedListener(this);
  }

  private void postWindowStateChangedEvent(int newWindowState) {
    if (getTarget() instanceof Frame) {
      AWTAccessor.getFrameAccessor().setExtendedState((Frame) getTarget(), newWindowState);
    }

    WindowEvent stateChangedEvent =
        new WindowEvent(getTarget(), WindowEvent.WINDOW_STATE_CHANGED, windowState, newWindowState);
    postEvent(stateChangedEvent);
    windowState = newWindowState;

    updateSecurityWarningVisibility();
  }

  private static int getGraphicsConfigScreen(GraphicsConfiguration gc) {
    // TODO: this method can be implemented in a more
    // efficient way by forwarding to the delegate
    GraphicsDevice gd = gc.getDevice();
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gds = ge.getScreenDevices();
    for (int i = 0; i < gds.length; i++) {
      if (gds[i] == gd) {
        return i;
      }
    }
    // Should never happen if gc is a screen device config
    return 0;
  }

  /*
   * This method is called when window's graphics config is changed from
   * the app code (e.g. when the window is made non-opaque) or when
   * the window is moved to another screen by user.
   *
   * Returns true if the graphics config has been changed, false otherwise.
   */
  private boolean setGraphicsConfig(GraphicsConfiguration gc) {
    synchronized (getStateLock()) {
      if (graphicsConfig == gc) {
        return false;
      }
      // If window's graphics config is changed from the app code, the
      // config correspond to the same device as before; when the window
      // is moved by user, graphicsDevice is updated in notifyReshape().
      // In either case, there's nothing to do with screenOn here
      graphicsConfig = gc;
    }
    // SurfaceData is replaced later in updateGraphicsData()
    return true;
  }

  /** Returns true if the GraphicsDevice has been changed, false otherwise. */
  public boolean updateGraphicsDevice() {
    GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice();
    synchronized (getStateLock()) {
      if (graphicsDevice == newGraphicsDevice) {
        return false;
      }
      graphicsDevice = newGraphicsDevice;
    }

    final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();

    if (!setGraphicsConfig(newGC)) return false;

    SunToolkit.executeOnEventHandlerThread(
        getTarget(),
        new Runnable() {
          public void run() {
            AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC);
          }
        });
    return true;
  }

  @Override
  public final void displayChanged() {
    if (updateGraphicsDevice()) {
      updateMinimumSize();
    }
    // Replace surface unconditionally, because internal state of the
    // GraphicsDevice could be changed.
    replaceSurfaceData();
    repaintPeer();
  }

  @Override
  public final void paletteChanged() {
    // components do not need to react to this event.
  }

  /*
   * May be called by delegate to provide SD to Java2D code.
   */
  public SurfaceData getSurfaceData() {
    synchronized (surfaceDataLock) {
      return surfaceData;
    }
  }

  private void replaceSurfaceData() {
    replaceSurfaceData(true);
  }

  private void replaceSurfaceData(final boolean blit) {
    synchronized (surfaceDataLock) {
      final SurfaceData oldData = getSurfaceData();
      surfaceData = platformWindow.replaceSurfaceData();
      final Rectangle size = getSize();
      if (getSurfaceData() != null && oldData != getSurfaceData()) {
        clearBackground(size.width, size.height);
      }

      if (blit) {
        blitSurfaceData(oldData, getSurfaceData());
      }

      if (oldData != null && oldData != getSurfaceData()) {
        // TODO: drop oldData for D3D/WGL pipelines
        // This can only happen when this peer is being created
        oldData.flush();
      }
    }
    flushOnscreenGraphics();
  }

  private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) {
    // TODO blit. proof-of-concept
    if (src != dst
        && src != null
        && dst != null
        && !(dst instanceof NullSurfaceData)
        && !(src instanceof NullSurfaceData)
        && src.getSurfaceType().equals(dst.getSurfaceType())
        && src.getDefaultScale() == dst.getDefaultScale()) {
      final Rectangle size = src.getBounds();
      final Blit blit = Blit.locate(src.getSurfaceType(), CompositeType.Src, dst.getSurfaceType());
      if (blit != null) {
        blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0, size.width, size.height);
      }
    }
  }

  /**
   * Request the window insets from the delegate and compares it with the current one. This method
   * is mostly called by the delegate, e.g. when the window state is changed and insets should be
   * recalculated.
   *
   * <p>This method may be called on the toolkit thread.
   */
  public final boolean updateInsets(final Insets newInsets) {
    synchronized (getStateLock()) {
      if (insets.equals(newInsets)) {
        return false;
      }
      insets = newInsets;
    }
    return true;
  }

  public static LWWindowPeer getWindowUnderCursor() {
    return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null;
  }

  public static LWComponentPeer<?, ?> getPeerUnderCursor() {
    return lastCommonMouseEventPeer;
  }

  /*
   * Requests platform to set native focus on a frame/dialog.
   * In case of a simple window, triggers appropriate java focus change.
   */
  public boolean requestWindowFocus(CausedFocusEvent.Cause cause) {
    if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
      focusLog.fine("requesting native focus to " + this);
    }

    if (!focusAllowedFor()) {
      focusLog.fine("focus is not allowed");
      return false;
    }

    // if (platformWindow.rejectFocusRequest(cause)) {
    //    return false;
    // }

    AppContext targetAppContext = AWTAccessor.getComponentAccessor().getAppContext(getTarget());
    KeyboardFocusManager kfm =
        AWTAccessor.getKeyboardFocusManagerAccessor()
            .getCurrentKeyboardFocusManager(targetAppContext);
    Window currentActive = kfm.getActiveWindow();

    Window opposite = LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();

    // Make the owner active window.
    if (isSimpleWindow()) {
      focusLog.fine("This is a Simple Window.");
      LWWindowPeer owner = getOwnerFrameDialog(this);

      // If owner is not natively active, request native
      // activation on it w/o sending events up to java.
      if (owner != null && !owner.platformWindow.isActive()) {
        if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
          focusLog.fine("requesting native focus to the owner " + owner);
        }
        LWWindowPeer currentActivePeer =
            currentActive == null
                ? null
                : (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(currentActive);

        // Ensure the opposite is natively active and suppress sending events.
        if (currentActivePeer != null && currentActivePeer.platformWindow.isActive()) {
          if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
            focusLog.fine("the opposite is " + currentActivePeer);
          }
          currentActivePeer.skipNextFocusChange = true;
        }
        owner.skipNextFocusChange = true;

        owner.platformWindow.requestWindowFocus();
      }

      // DKFM will synthesize all the focus/activation events correctly.
      changeFocusedWindow(true, opposite);
      focusLog.fine("DKFM will synthesize all the focus/activation events correctly");
      return true;

      // In case the toplevel is active but not focused, change focus directly,
      // as requesting native focus on it will not have effect.
    } else if (getTarget() == currentActive && !getTarget().hasFocus()) {

      changeFocusedWindow(true, opposite);
      focusLog.fine("toplevel is active but not focused, change focus directly");
      return true;
    }

    focusLog.fine("platformWindow.requestWindowFocus()");
    return platformWindow.requestWindowFocus();
  }

  protected boolean focusAllowedFor() {
    Window window = getTarget();
    // TODO: check if modal blocked

    boolean allowed =
        (getBlocker() == null) && window.isVisible() && window.isEnabled() && isFocusableWindow();

    focusLog.fine(
        "Checking whether the focus is allowed ["
            + allowed
            + "] for "
            + window.getName()
            + "; blocker: "
            + ((getBlocker() == null) ? "null" : getBlocker().getClass().getName())
            + "; window.isVisible: "
            + window.isVisible()
            + "; window.isEnabled: "
            + window.isEnabled()
            + "; isFocusableWindow: "
            + isFocusableWindow());

    return allowed;
  }

  private boolean isFocusableWindow() {
    boolean focusable = targetFocusable;
    if (isSimpleWindow()) {
      LWWindowPeer ownerPeer = getOwnerFrameDialog(this);
      if (ownerPeer == null) {
        return false;
      }
      return focusable && ownerPeer.targetFocusable;
    }
    return focusable;
  }

  public boolean isSimpleWindow() {
    Window window = getTarget();
    return !(window instanceof Dialog || window instanceof Frame);
  }

  @Override
  public void emulateActivation(boolean activate) {
    changeFocusedWindow(activate, null);
  }

  private boolean isOneOfOwnersOf(LWWindowPeer peer) {
    Window owner = (peer != null ? peer.getTarget().getOwner() : null);
    while (owner != null) {
      if ((LWWindowPeer) owner.getPeer() == this) {
        return true;
      }
      owner = owner.getOwner();
    }
    return false;
  }

  /*
   * Changes focused window on java level.
   */
  protected void changeFocusedWindow(boolean becomesFocused, Window opposite) {
    if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
      focusLog.fine((becomesFocused ? "gaining" : "loosing") + " focus window: " + this);
    }
    if (skipNextFocusChange) {
      focusLog.fine("skipping focus change");
      skipNextFocusChange = false;
      return;
    }
    if (!isFocusableWindow() && becomesFocused) {
      focusLog.fine("the window is not focusable");
      return;
    }
    if (becomesFocused) {
      synchronized (getPeerTreeLock()) {
        if (blocker != null) {
          if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
            focusLog.finest("the window is blocked by " + blocker);
          }
          return;
        }
      }
    }

    // Note, the method is not called:
    // - when the opposite (gaining focus) window is an owned/owner window.
    // - for a simple window in any case.
    if (!becomesFocused && (isGrabbing() || this.isOneOfOwnersOf(grabbingWindow))) {
      if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
        focusLog.fine("ungrabbing on " + grabbingWindow);
      }
      // ungrab a simple window if its owner looses activation.
      grabbingWindow.ungrab();
    }

    KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
    kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);

    int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;
    WindowEvent windowEvent =
        new TimedWindowEvent(getTarget(), eventID, opposite, System.currentTimeMillis());

    // TODO: wrap in SequencedEvent
    postEvent(windowEvent);
  }

  /*
   * Retrieves the owner of the peer.
   * Note: this method returns the owner which can be activated, (i.e. the instance
   * of Frame or Dialog may be returned).
   */
  static LWWindowPeer getOwnerFrameDialog(LWWindowPeer peer) {
    Window owner = (peer != null ? peer.getTarget().getOwner() : null);
    while (owner != null && !(owner instanceof Frame || owner instanceof Dialog)) {
      owner = owner.getOwner();
    }
    return owner == null ? null : (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner);
  }

  /** Returns the foremost modal blocker of this window, or null. */
  public LWWindowPeer getBlocker() {
    synchronized (getPeerTreeLock()) {
      LWWindowPeer blocker = this.blocker;
      if (blocker == null) {
        return null;
      }
      while (blocker.blocker != null) {
        blocker = blocker.blocker;
      }
      return blocker;
    }
  }

  @Override
  public void enterFullScreenMode() {
    platformWindow.enterFullScreenMode();
    updateSecurityWarningVisibility();
  }

  @Override
  public void exitFullScreenMode() {
    platformWindow.exitFullScreenMode();
    updateSecurityWarningVisibility();
  }

  public long getLayerPtr() {
    return getPlatformWindow().getLayerPtr();
  }

  void grab() {
    if (grabbingWindow != null && !isGrabbing()) {
      grabbingWindow.ungrab();
    }
    grabbingWindow = this;
  }

  final void ungrab(boolean doPost) {
    if (isGrabbing()) {
      grabbingWindow = null;
      if (doPost) {
        postEvent(new UngrabEvent(getTarget()));
      }
    }
  }

  void ungrab() {
    ungrab(true);
  }

  private boolean isGrabbing() {
    return this == grabbingWindow;
  }

  public PeerType getPeerType() {
    return peerType;
  }

  public void updateSecurityWarningVisibility() {
    if (warningWindow == null) {
      return;
    }

    if (!isVisible()) {
      return; // The warning window should already be hidden.
    }

    boolean show = false;

    if (!platformWindow.isFullScreenMode()) {
      if (isVisible()) {
        if (LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == getTarget()) {
          show = true;
        }

        if (platformWindow.isUnderMouse() || warningWindow.isUnderMouse()) {
          show = true;
        }
      }
    }

    warningWindow.setVisible(show, true);
  }

  @Override
  public String toString() {
    return super.toString() + " [target is " + getTarget() + "]";
  }
}
public class XEmbeddedFramePeer extends XFramePeer {

  private static final PlatformLogger xembedLog =
      PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbeddedFramePeer");

  LinkedList<AWTKeyStroke> strokes;

  XEmbedClientHelper embedder; // Caution - can be null if XEmbed is not supported

  public XEmbeddedFramePeer(EmbeddedFrame target) {
    // Don't specify PARENT_WINDOW param here. Instead we reparent
    // this embedded frame peer to the proper parent window after
    // an XEventDispatcher is registered to handle XEmbed events
    super(
        new XCreateWindowParams(
            new Object[] {
              TARGET, target,
              VISIBLE, Boolean.TRUE,
              EMBEDDED, Boolean.TRUE
            }));
  }

  public void preInit(XCreateWindowParams params) {
    super.preInit(params);
    strokes = new LinkedList<AWTKeyStroke>();
    if (supportsXEmbed()) {
      embedder = new XEmbedClientHelper();
    }
  }

  void postInit(XCreateWindowParams params) {
    super.postInit(params);
    if (embedder != null) {
      // install X11 event dispatcher
      embedder.setClient(this);
      // reparent to XEmbed server
      embedder.install();
    } else if (getParentWindowHandle() != 0) {
      XToolkit.awtLock();
      try {
        XlibWrapper.XReparentWindow(
            XToolkit.getDisplay(), getWindow(), getParentWindowHandle(), 0, 0);
      } finally {
        XToolkit.awtUnlock();
      }
    }
  }

  @Override
  public void dispose() {
    if (embedder != null) {
      // uninstall X11 event dispatcher
      embedder.setClient(null);
    }
    super.dispose();
  }

  public void updateMinimumSize() {}

  protected String getWMName() {
    return "JavaEmbeddedFrame";
  }

  final long getParentWindowHandle() {
    return ((XEmbeddedFrame) target).handle;
  }

  boolean supportsXEmbed() {
    return ((EmbeddedFrame) target).supportsXEmbed();
  }

  public boolean requestWindowFocus(long time, boolean timeProvided) {
    // Should check for active state of host application
    if (embedder != null && embedder.isActive()) {
      xembedLog.fine("Requesting focus from embedding host");
      return embedder.requestFocus();
    } else {
      xembedLog.fine("Requesting focus from X");
      return super.requestWindowFocus(time, timeProvided);
    }
  }

  protected void requestInitialFocus() {
    if (embedder != null && supportsXEmbed()) {
      embedder.requestFocus();
    } else {
      super.requestInitialFocus();
    }
  }

  protected boolean isEventDisabled(XEvent e) {
    if (embedder != null && embedder.isActive()) {
      switch (e.get_type()) {
        case XConstants.FocusIn:
        case XConstants.FocusOut:
          return true;
      }
    }
    return super.isEventDisabled(e);
  }

  public void handleConfigureNotifyEvent(XEvent xev) {
    assert (SunToolkit.isAWTLockHeldByCurrentThread());
    XConfigureEvent xe = xev.get_xconfigure();
    if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) {
      xembedLog.fine(xe.toString());
    }

    // fix for 5063031
    // if we use super.handleConfigureNotifyEvent() we would get wrong
    // size and position because embedded frame really is NOT a decorated one
    checkIfOnNewScreen(
        toGlobal(new Rectangle(xe.get_x(), xe.get_y(), xe.get_width(), xe.get_height())));

    Rectangle oldBounds = getBounds();

    synchronized (getStateLock()) {
      x = xe.get_x();
      y = xe.get_y();
      width = xe.get_width();
      height = xe.get_height();

      dimensions.setClientSize(width, height);
      dimensions.setLocation(x, y);
    }

    if (!getLocation().equals(oldBounds.getLocation())) {
      handleMoved(dimensions);
    }
    reconfigureContentWindow(dimensions);
  }

  protected void traverseOutForward() {
    if (embedder != null && embedder.isActive()) {
      if (embedder.isApplicationActive()) {
        xembedLog.fine("Traversing out Forward");
        embedder.traverseOutForward();
      }
    }
  }

  protected void traverseOutBackward() {
    if (embedder != null && embedder.isActive()) {
      if (embedder.isApplicationActive()) {
        xembedLog.fine("Traversing out Backward");
        embedder.traverseOutBackward();
      }
    }
  }

  // don't use getLocationOnScreen() inherited from XDecoratedPeer
  public Point getLocationOnScreen() {
    XToolkit.awtLock();
    try {
      return toGlobal(0, 0);
    } finally {
      XToolkit.awtUnlock();
    }
  }

  // don't use getBounds() inherited from XDecoratedPeer
  public Rectangle getBounds() {
    return new Rectangle(x, y, width, height);
  }

  public void setBoundsPrivate(int x, int y, int width, int height) {
    setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);
  }

  public Rectangle getBoundsPrivate() {
    int x = 0, y = 0;
    int w = 0, h = 0;
    XWindowAttributes attr = new XWindowAttributes();

    XToolkit.awtLock();
    try {
      XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), getWindow(), attr.pData);
      x = attr.get_x();
      y = attr.get_y();
      w = attr.get_width();
      h = attr.get_height();
    } finally {
      XToolkit.awtUnlock();
    }
    attr.dispose();

    return new Rectangle(x, y, w, h);
  }

  void registerAccelerator(AWTKeyStroke stroke) {
    if (stroke == null) return;
    strokes.add(stroke);
    if (embedder != null && embedder.isActive()) {
      embedder.registerAccelerator(stroke, strokes.size() - 1);
    }
  }

  void unregisterAccelerator(AWTKeyStroke stroke) {
    if (stroke == null) return;
    if (embedder != null && embedder.isActive()) {
      int index = strokes.indexOf(stroke);
      embedder.unregisterAccelerator(index);
    }
  }

  void notifyStarted() {
    // Register accelerators
    if (embedder != null && embedder.isActive()) {
      int i = 0;
      Iterator<AWTKeyStroke> iter = strokes.iterator();
      while (iter.hasNext()) {
        embedder.registerAccelerator(iter.next(), i++);
      }
    }
    // Now we know that the the embedder is an XEmbed server, so we
    // reregister the drop target to enable XDnD protocol support via
    // XEmbed.
    updateDropTarget();
  }

  void notifyStopped() {
    if (embedder != null && embedder.isActive()) {
      for (int i = strokes.size() - 1; i >= 0; i--) {
        embedder.unregisterAccelerator(i);
      }
    }
  }

  long getFocusTargetWindow() {
    return getWindow();
  }

  boolean isXEmbedActive() {
    return embedder != null && embedder.isActive();
  }

  public int getAbsoluteX() {
    Point absoluteLoc =
        XlibUtil.translateCoordinates(
            getWindow(), XToolkit.getDefaultRootWindow(), new Point(0, 0));
    return absoluteLoc != null ? absoluteLoc.x : 0;
  }

  public int getAbsoluteY() {
    Point absoluteLoc =
        XlibUtil.translateCoordinates(
            getWindow(), XToolkit.getDefaultRootWindow(), new Point(0, 0));
    return absoluteLoc != null ? absoluteLoc.y : 0;
  }

  public int getWidth() {
    return width;
  }

  public int getHeight() {
    return height;
  }

  public Dimension getSize() {
    return new Dimension(width, height);
  }

  // override XWindowPeer's method to let the embedded frame to block
  // the containing window
  public void setModalBlocked(Dialog blocker, boolean blocked) {
    super.setModalBlocked(blocker, blocked);

    EmbeddedFrame frame = (EmbeddedFrame) target;
    frame.notifyModalBlocked(blocker, blocked);
  }

  public void synthesizeFocusInOut(boolean doFocus) {
    XFocusChangeEvent xev = new XFocusChangeEvent();

    XToolkit.awtLock();
    try {
      xev.set_type(doFocus ? FocusIn : FocusOut);
      xev.set_window(getFocusProxy().getWindow());
      xev.set_mode(NotifyNormal);
      XlibWrapper.XSendEvent(
          XToolkit.getDisplay(), getFocusProxy().getWindow(), false, NoEventMask, xev.pData);
    } finally {
      XToolkit.awtUnlock();
      xev.dispose();
    }
  }
}
Ejemplo n.º 10
0
  public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException {
    // pre-condition check
    if (uri == null || responseHeaders == null) {
      throw new IllegalArgumentException("Argument is null");
    }

    // if there's no default CookieStore, no need to remember any cookie
    if (cookieJar == null) return;

    PlatformLogger logger = PlatformLogger.getLogger("java.net.CookieManager");
    for (String headerKey : responseHeaders.keySet()) {
      // RFC 2965 3.2.2, key must be 'Set-Cookie2'
      // we also accept 'Set-Cookie' here for backward compatibility
      if (headerKey == null
          || !(headerKey.equalsIgnoreCase("Set-Cookie2")
              || headerKey.equalsIgnoreCase("Set-Cookie"))) {
        continue;
      }

      for (String headerValue : responseHeaders.get(headerKey)) {
        try {
          List<HttpCookie> cookies;
          try {
            cookies = HttpCookie.parse(headerValue);
          } catch (IllegalArgumentException e) {
            // Bogus header, make an empty list and log the error
            cookies = java.util.Collections.EMPTY_LIST;
            if (logger.isLoggable(PlatformLogger.SEVERE)) {
              logger.severe("Invalid cookie for " + uri + ": " + headerValue);
            }
          }
          for (HttpCookie cookie : cookies) {
            if (cookie.getPath() == null) {
              // If no path is specified, then by default
              // the path is the directory of the page/doc
              String path = uri.getPath();
              if (!path.endsWith("/")) {
                int i = path.lastIndexOf("/");
                if (i > 0) {
                  path = path.substring(0, i + 1);
                } else {
                  path = "/";
                }
              }
              cookie.setPath(path);
            }

            // As per RFC 2965, section 3.3.1:
            // Domain  Defaults to the effective request-host.  (Note that because
            // there is no dot at the beginning of effective request-host,
            // the default Domain can only domain-match itself.)
            if (cookie.getDomain() == null) {
              cookie.setDomain(uri.getHost());
            }
            String ports = cookie.getPortlist();
            if (ports != null) {
              int port = uri.getPort();
              if (port == -1) {
                port = "https".equals(uri.getScheme()) ? 443 : 80;
              }
              if (ports.isEmpty()) {
                // Empty port list means this should be restricted
                // to the incoming URI port
                cookie.setPortlist("" + port);
                if (shouldAcceptInternal(uri, cookie)) {
                  cookieJar.add(uri, cookie);
                }
              } else {
                // Only store cookies with a port list
                // IF the URI port is in that list, as per
                // RFC 2965 section 3.3.2
                if (isInPortList(ports, port) && shouldAcceptInternal(uri, cookie)) {
                  cookieJar.add(uri, cookie);
                }
              }
            } else {
              if (shouldAcceptInternal(uri, cookie)) {
                cookieJar.add(uri, cookie);
              }
            }
          }
        } catch (IllegalArgumentException e) {
          // invalid set-cookie header string
          // no-op
        }
      }
    }
  }
Ejemplo n.º 11
0
public class WWindowPeer extends WPanelPeer implements WindowPeer, DisplayChangedListener {

  private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WWindowPeer");
  private static final PlatformLogger screenLog =
      PlatformLogger.getLogger("sun.awt.windows.screen.WWindowPeer");

  // we can't use WDialogPeer as blocker may be an instance of WPrintDialogPeer that
  // extends WWindowPeer, not WDialogPeer
  private WWindowPeer modalBlocker = null;

  private boolean isOpaque;

  private TranslucentWindowPainter painter;

  /*
   * A key used for storing a list of active windows in AppContext. The value
   * is a list of windows, sorted by the time of activation: later a window is
   * activated, greater its index is in the list.
   */
  private static final StringBuffer ACTIVE_WINDOWS_KEY = new StringBuffer("active_windows_list");

  /*
   * Listener for 'activeWindow' KFM property changes. It is added to each
   * AppContext KFM. See ActiveWindowListener inner class below.
   */
  private static PropertyChangeListener activeWindowListener = new ActiveWindowListener();

  /*
   * The object is a listener for the AppContext.GUI_DISPOSED property.
   */
  private static final PropertyChangeListener guiDisposedListener = new GuiDisposedListener();

  /*
   * Called (on the Toolkit thread) before the appropriate
   * WindowStateEvent is posted to the EventQueue.
   */
  private WindowListener windowListener;

  /** Initialize JNI field IDs */
  private static native void initIDs();

  static {
    initIDs();
  }

  // WComponentPeer overrides
  @SuppressWarnings("unchecked")
  protected void disposeImpl() {
    AppContext appContext = SunToolkit.targetToAppContext(target);
    synchronized (appContext) {
      List<WWindowPeer> l = (List<WWindowPeer>) appContext.get(ACTIVE_WINDOWS_KEY);
      if (l != null) {
        l.remove(this);
      }
    }

    // Remove ourself from the Map of DisplayChangeListeners
    GraphicsConfiguration gc = getGraphicsConfiguration();
    ((Win32GraphicsDevice) gc.getDevice()).removeDisplayChangedListener(this);

    synchronized (getStateLock()) {
      TranslucentWindowPainter currentPainter = painter;
      if (currentPainter != null) {
        currentPainter.flush();
        // don't set the current one to null here; reduces the chances of
        // MT issues (like NPEs)
      }
    }

    super.disposeImpl();
  }

  // WindowPeer implementation

  public void toFront() {
    updateFocusableWindowState();
    _toFront();
  }

  native void _toFront();

  public native void toBack();

  public native void setAlwaysOnTopNative(boolean value);

  public void setAlwaysOnTop(boolean value) {
    if ((value && ((Window) target).isVisible()) || !value) {
      setAlwaysOnTopNative(value);
    }
  }

  public void updateAlwaysOnTopState() {
    setAlwaysOnTop(((Window) target).isAlwaysOnTop());
  }

  public void updateFocusableWindowState() {
    setFocusableWindow(((Window) target).isFocusableWindow());
  }

  native void setFocusableWindow(boolean value);

  // FramePeer & DialogPeer partial shared implementation

  public void setTitle(String title) {
    // allow a null title to pass as an empty string.
    if (title == null) {
      title = "";
    }
    _setTitle(title);
  }

  native void _setTitle(String title);

  public void setResizable(boolean resizable) {
    _setResizable(resizable);
  }

  public native void _setResizable(boolean resizable);

  // Toolkit & peer internals

  WWindowPeer(Window target) {
    super(target);
  }

  void initialize() {
    super.initialize();

    updateInsets(insets_);

    Font f = ((Window) target).getFont();
    if (f == null) {
      f = defaultFont;
      ((Window) target).setFont(f);
      setFont(f);
    }
    // Express our interest in display changes
    GraphicsConfiguration gc = getGraphicsConfiguration();
    ((Win32GraphicsDevice) gc.getDevice()).addDisplayChangedListener(this);

    initActiveWindowsTracking((Window) target);

    updateIconImages();

    Shape shape = ((Window) target).getShape();
    if (shape != null) {
      applyShape(Region.getInstance(shape, null));
    }

    float opacity = ((Window) target).getOpacity();
    if (opacity < 1.0f) {
      setOpacity(opacity);
    }

    synchronized (getStateLock()) {
      // default value of a boolean field is 'false', so set isOpaque to
      // true here explicitly
      this.isOpaque = true;
      setOpaque(((Window) target).isOpaque());
    }
  }

  native void createAwtWindow(WComponentPeer parent);

  private volatile Window.Type windowType = Window.Type.NORMAL;

  // This method must be called for Window, Dialog, and Frame before creating
  // the hwnd
  void preCreate(WComponentPeer parent) {
    windowType = ((Window) target).getType();
  }

  void create(WComponentPeer parent) {
    preCreate(parent);
    createAwtWindow(parent);
  }

  @Override
  final WComponentPeer getNativeParent() {
    final Container owner = ((Window) target).getOwner();
    return (WComponentPeer) WToolkit.targetToPeer(owner);
  }

  // should be overriden in WDialogPeer
  protected void realShow() {
    super.show();
  }

  public void show() {
    updateFocusableWindowState();

    boolean alwaysOnTop = ((Window) target).isAlwaysOnTop();

    // Fix for 4868278.
    // If we create a window with a specific GraphicsConfig, and then move it with
    // setLocation() or setBounds() to another one before its peer has been created,
    // then calling Window.getGraphicsConfig() returns wrong config. That may lead
    // to some problems like wrong-placed tooltips. It is caused by calling
    // super.displayChanged() in WWindowPeer.displayChanged() regardless of whether
    // GraphicsDevice was really changed, or not. So we need to track it here.
    updateGC();

    realShow();
    updateMinimumSize();

    if (((Window) target).isAlwaysOnTopSupported() && alwaysOnTop) {
      setAlwaysOnTop(alwaysOnTop);
    }

    synchronized (getStateLock()) {
      if (!isOpaque) {
        updateWindow(true);
      }
    }
  }

  // Synchronize the insets members (here & in helper) with actual window
  // state.
  native void updateInsets(Insets i);

  static native int getSysMinWidth();

  static native int getSysMinHeight();

  static native int getSysIconWidth();

  static native int getSysIconHeight();

  static native int getSysSmIconWidth();

  static native int getSysSmIconHeight();
  /**
   * windows/classes/sun/awt/windows/ Creates native icon from specified raster data and updates
   * icon for window and all descendant windows that inherit icon. Raster data should be passed in
   * the ARGB form. Note that raster data format was changed to provide support for XP icons with
   * alpha-channel
   */
  native void setIconImagesData(
      int[] iconRaster, int w, int h, int[] smallIconRaster, int smw, int smh);

  synchronized native void reshapeFrame(int x, int y, int width, int height);

  public boolean requestWindowFocus(CausedFocusEvent.Cause cause) {
    if (!focusAllowedFor()) {
      return false;
    }
    return requestWindowFocus(cause == CausedFocusEvent.Cause.MOUSE_EVENT);
  }

  public native boolean requestWindowFocus(boolean isMouseEventCause);

  public boolean focusAllowedFor() {
    Window window = (Window) this.target;
    if (!window.isVisible() || !window.isEnabled() || !window.isFocusableWindow()) {
      return false;
    }
    if (isModalBlocked()) {
      return false;
    }
    return true;
  }

  public void hide() {
    WindowListener listener = windowListener;
    if (listener != null) {
      // We're not getting WINDOW_CLOSING from the native code when hiding
      // the window programmatically. So, create it and notify the listener.
      listener.windowClosing(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
    }
    super.hide();
  }

  // WARNING: it's called on the Toolkit thread!
  void preprocessPostEvent(AWTEvent event) {
    if (event instanceof WindowEvent) {
      WindowListener listener = windowListener;
      if (listener != null) {
        switch (event.getID()) {
          case WindowEvent.WINDOW_CLOSING:
            listener.windowClosing((WindowEvent) event);
            break;
          case WindowEvent.WINDOW_ICONIFIED:
            listener.windowIconified((WindowEvent) event);
            break;
        }
      }
    }
  }

  synchronized void addWindowListener(WindowListener l) {
    windowListener = AWTEventMulticaster.add(windowListener, l);
  }

  synchronized void removeWindowListener(WindowListener l) {
    windowListener = AWTEventMulticaster.remove(windowListener, l);
  }

  public void updateMinimumSize() {
    Dimension minimumSize = null;
    if (((Component) target).isMinimumSizeSet()) {
      minimumSize = ((Component) target).getMinimumSize();
    }
    if (minimumSize != null) {
      int msw = getSysMinWidth();
      int msh = getSysMinHeight();
      int w = (minimumSize.width >= msw) ? minimumSize.width : msw;
      int h = (minimumSize.height >= msh) ? minimumSize.height : msh;
      setMinSize(w, h);
    } else {
      setMinSize(0, 0);
    }
  }

  public void updateIconImages() {
    java.util.List<Image> imageList = ((Window) target).getIconImages();
    if (imageList == null || imageList.size() == 0) {
      setIconImagesData(null, 0, 0, null, 0, 0);
    } else {
      int w = getSysIconWidth();
      int h = getSysIconHeight();
      int smw = getSysSmIconWidth();
      int smh = getSysSmIconHeight();
      DataBufferInt iconData = SunToolkit.getScaledIconData(imageList, w, h);
      DataBufferInt iconSmData = SunToolkit.getScaledIconData(imageList, smw, smh);
      if (iconData != null && iconSmData != null) {
        setIconImagesData(iconData.getData(), w, h, iconSmData.getData(), smw, smh);
      } else {
        setIconImagesData(null, 0, 0, null, 0, 0);
      }
    }
  }

  native void setMinSize(int width, int height);

  /*
   * ---- MODALITY SUPPORT ----
   */

  /**
   * Some modality-related code here because WFileDialogPeer, WPrintDialogPeer and WPageDialogPeer
   * are descendants of WWindowPeer, not WDialogPeer
   */
  public boolean isModalBlocked() {
    return modalBlocker != null;
  }

  @SuppressWarnings("deprecation")
  public void setModalBlocked(Dialog dialog, boolean blocked) {
    synchronized (
        ((Component) getTarget()).getTreeLock()) // State lock should always be after awtLock
    {
      // use WWindowPeer instead of WDialogPeer because of FileDialogs and PrintDialogs
      WWindowPeer blockerPeer = (WWindowPeer) dialog.getPeer();
      if (blocked) {
        modalBlocker = blockerPeer;
        // handle native dialogs separately, as they may have not
        // got HWND yet; modalEnable/modalDisable is called from
        // their setHWnd() methods
        if (blockerPeer instanceof WFileDialogPeer) {
          ((WFileDialogPeer) blockerPeer).blockWindow(this);
        } else if (blockerPeer instanceof WPrintDialogPeer) {
          ((WPrintDialogPeer) blockerPeer).blockWindow(this);
        } else {
          modalDisable(dialog, blockerPeer.getHWnd());
        }
      } else {
        modalBlocker = null;
        if (blockerPeer instanceof WFileDialogPeer) {
          ((WFileDialogPeer) blockerPeer).unblockWindow(this);
        } else if (blockerPeer instanceof WPrintDialogPeer) {
          ((WPrintDialogPeer) blockerPeer).unblockWindow(this);
        } else {
          modalEnable(dialog);
        }
      }
    }
  }

  native void modalDisable(Dialog blocker, long blockerHWnd);

  native void modalEnable(Dialog blocker);

  /*
   * Returns all the ever active windows from the current AppContext.
   * The list is sorted by the time of activation, so the latest
   * active window is always at the end.
   */
  @SuppressWarnings("unchecked")
  public static long[] getActiveWindowHandles() {
    AppContext appContext = AppContext.getAppContext();
    synchronized (appContext) {
      List<WWindowPeer> l = (List<WWindowPeer>) appContext.get(ACTIVE_WINDOWS_KEY);
      if (l == null) {
        return null;
      }
      long[] result = new long[l.size()];
      for (int j = 0; j < l.size(); j++) {
        result[j] = l.get(j).getHWnd();
      }
      return result;
    }
  }

  /*
   * ----DISPLAY CHANGE SUPPORT----
   */

  /*
   * Called from native code when we have been dragged onto another screen.
   */
  void draggedToNewScreen() {
    SunToolkit.executeOnEventHandlerThread(
        (Component) target,
        new Runnable() {
          public void run() {
            displayChanged();
          }
        });
  }

  public void updateGC() {
    int scrn = getScreenImOn();
    if (screenLog.isLoggable(PlatformLogger.Level.FINER)) {
      log.finer("Screen number: " + scrn);
    }

    // get current GD
    Win32GraphicsDevice oldDev = (Win32GraphicsDevice) winGraphicsConfig.getDevice();

    Win32GraphicsDevice newDev;
    GraphicsDevice devs[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
    // Occasionally during device addition/removal getScreenImOn can return
    // a non-existing screen number. Use the default device in this case.
    if (scrn >= devs.length) {
      newDev =
          (Win32GraphicsDevice)
              GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    } else {
      newDev = (Win32GraphicsDevice) devs[scrn];
    }

    // Set winGraphicsConfig to the default GC for the monitor this Window
    // is now mostly on.
    winGraphicsConfig = (Win32GraphicsConfig) newDev.getDefaultConfiguration();
    if (screenLog.isLoggable(PlatformLogger.Level.FINE)) {
      if (winGraphicsConfig == null) {
        screenLog.fine("Assertion (winGraphicsConfig != null) failed");
      }
    }

    // if on a different display, take off old GD and put on new GD
    if (oldDev != newDev) {
      oldDev.removeDisplayChangedListener(this);
      newDev.addDisplayChangedListener(this);
    }

    AWTAccessor.getComponentAccessor()
        .setGraphicsConfiguration((Component) target, winGraphicsConfig);
  }

  /**
   * From the DisplayChangedListener interface.
   *
   * <p>This method handles a display change - either when the display settings are changed, or when
   * the window has been dragged onto a different display. Called after a change in the display
   * mode. This event triggers replacing the surfaceData object (since that object reflects the
   * current display depth information, which has just changed).
   */
  public void displayChanged() {
    updateGC();
  }

  /** Part of the DisplayChangedListener interface: components do not need to react to this event */
  public void paletteChanged() {}

  private native int getScreenImOn();

  // Used in Win32GraphicsDevice.
  public final native void setFullScreenExclusiveModeState(boolean state);

  /*
   * ----END DISPLAY CHANGE SUPPORT----
   */

  public void grab() {
    nativeGrab();
  }

  public void ungrab() {
    nativeUngrab();
  }

  private native void nativeGrab();

  private native void nativeUngrab();

  private final boolean hasWarningWindow() {
    return ((Window) target).getWarningString() != null;
  }

  boolean isTargetUndecorated() {
    return true;
  }

  // These are the peer bounds. They get updated at:
  //    1. the WWindowPeer.setBounds() method.
  //    2. the native code (on WM_SIZE/WM_MOVE)
  private volatile int sysX = 0;
  private volatile int sysY = 0;
  private volatile int sysW = 0;
  private volatile int sysH = 0;

  public native void repositionSecurityWarning();

  @Override
  public void setBounds(int x, int y, int width, int height, int op) {
    sysX = x;
    sysY = y;
    sysW = width;
    sysH = height;

    super.setBounds(x, y, width, height, op);
  }

  @Override
  public void print(Graphics g) {
    // We assume we print the whole frame,
    // so we expect no clip was set previously
    Shape shape = AWTAccessor.getWindowAccessor().getShape((Window) target);
    if (shape != null) {
      g.setClip(shape);
    }
    super.print(g);
  }

  @SuppressWarnings("deprecation")
  private void replaceSurfaceDataRecursively(Component c) {
    if (c instanceof Container) {
      for (Component child : ((Container) c).getComponents()) {
        replaceSurfaceDataRecursively(child);
      }
    }
    ComponentPeer cp = c.getPeer();
    if (cp instanceof WComponentPeer) {
      ((WComponentPeer) cp).replaceSurfaceDataLater();
    }
  }

  public final Graphics getTranslucentGraphics() {
    synchronized (getStateLock()) {
      return isOpaque ? null : painter.getBackBuffer(false).getGraphics();
    }
  }

  @Override
  public void setBackground(Color c) {
    super.setBackground(c);
    synchronized (getStateLock()) {
      if (!isOpaque && ((Window) target).isVisible()) {
        updateWindow(true);
      }
    }
  }

  private native void setOpacity(int iOpacity);

  private float opacity = 1.0f;

  public void setOpacity(float opacity) {
    if (!((SunToolkit) ((Window) target).getToolkit()).isWindowOpacitySupported()) {
      return;
    }

    if (opacity < 0.0f || opacity > 1.0f) {
      throw new IllegalArgumentException(
          "The value of opacity should be in the range [0.0f .. 1.0f].");
    }

    if (((this.opacity == 1.0f && opacity < 1.0f) || (this.opacity < 1.0f && opacity == 1.0f))
        && !Win32GraphicsEnvironment.isVistaOS()) {
      // non-Vista OS: only replace the surface data if opacity status
      // changed (see WComponentPeer.isAccelCapable() for more)
      replaceSurfaceDataRecursively((Component) getTarget());
    }

    this.opacity = opacity;

    final int maxOpacity = 0xff;
    int iOpacity = (int) (opacity * maxOpacity);
    if (iOpacity < 0) {
      iOpacity = 0;
    }
    if (iOpacity > maxOpacity) {
      iOpacity = maxOpacity;
    }

    setOpacity(iOpacity);

    synchronized (getStateLock()) {
      if (!isOpaque && ((Window) target).isVisible()) {
        updateWindow(true);
      }
    }
  }

  private native void setOpaqueImpl(boolean isOpaque);

  public void setOpaque(boolean isOpaque) {
    synchronized (getStateLock()) {
      if (this.isOpaque == isOpaque) {
        return;
      }
    }

    Window target = (Window) getTarget();

    if (!isOpaque) {
      SunToolkit sunToolkit = (SunToolkit) target.getToolkit();
      if (!sunToolkit.isWindowTranslucencySupported()
          || !sunToolkit.isTranslucencyCapable(target.getGraphicsConfiguration())) {
        return;
      }
    }

    boolean isVistaOS = Win32GraphicsEnvironment.isVistaOS();

    if (this.isOpaque != isOpaque && !isVistaOS) {
      // non-Vista OS: only replace the surface data if the opacity
      // status changed (see WComponentPeer.isAccelCapable() for more)
      replaceSurfaceDataRecursively(target);
    }

    synchronized (getStateLock()) {
      this.isOpaque = isOpaque;
      setOpaqueImpl(isOpaque);
      if (isOpaque) {
        TranslucentWindowPainter currentPainter = painter;
        if (currentPainter != null) {
          currentPainter.flush();
          painter = null;
        }
      } else {
        painter = TranslucentWindowPainter.createInstance(this);
      }
    }

    if (isVistaOS) {
      // On Vista: setting the window non-opaque makes the window look
      // rectangular, though still catching the mouse clicks within
      // its shape only. To restore the correct visual appearance
      // of the window (i.e. w/ the correct shape) we have to reset
      // the shape.
      Shape shape = target.getShape();
      if (shape != null) {
        target.setShape(shape);
      }
    }

    if (target.isVisible()) {
      updateWindow(true);
    }
  }

  public native void updateWindowImpl(int[] data, int width, int height);

  public void updateWindow() {
    updateWindow(false);
  }

  private void updateWindow(boolean repaint) {
    Window w = (Window) target;
    synchronized (getStateLock()) {
      if (isOpaque || !w.isVisible() || (w.getWidth() <= 0) || (w.getHeight() <= 0)) {
        return;
      }
      TranslucentWindowPainter currentPainter = painter;
      if (currentPainter != null) {
        currentPainter.updateWindow(repaint);
      } else if (log.isLoggable(PlatformLogger.Level.FINER)) {
        log.finer("Translucent window painter is null in updateWindow");
      }
    }
  }

  /*
   * The method maps the list of the active windows to the window's AppContext,
   * then the method registers ActiveWindowListener, GuiDisposedListener listeners;
   * it executes the initilialization only once per AppContext.
   */
  @SuppressWarnings("unchecked")
  private static void initActiveWindowsTracking(Window w) {
    AppContext appContext = AppContext.getAppContext();
    synchronized (appContext) {
      List<WWindowPeer> l = (List<WWindowPeer>) appContext.get(ACTIVE_WINDOWS_KEY);
      if (l == null) {
        l = new LinkedList<WWindowPeer>();
        appContext.put(ACTIVE_WINDOWS_KEY, l);
        appContext.addPropertyChangeListener(AppContext.GUI_DISPOSED, guiDisposedListener);

        KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        kfm.addPropertyChangeListener("activeWindow", activeWindowListener);
      }
    }
  }

  /*
   * The GuiDisposedListener class listens for the AppContext.GUI_DISPOSED property,
   * it removes the list of the active windows from the disposed AppContext and
   * unregisters ActiveWindowListener listener.
   */
  private static class GuiDisposedListener implements PropertyChangeListener {
    public void propertyChange(PropertyChangeEvent e) {
      boolean isDisposed = (Boolean) e.getNewValue();
      if (isDisposed != true) {
        if (log.isLoggable(PlatformLogger.Level.FINE)) {
          log.fine(" Assertion (newValue != true) failed for AppContext.GUI_DISPOSED ");
        }
      }
      AppContext appContext = AppContext.getAppContext();
      synchronized (appContext) {
        appContext.remove(ACTIVE_WINDOWS_KEY);
        appContext.removePropertyChangeListener(AppContext.GUI_DISPOSED, this);

        KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        kfm.removePropertyChangeListener("activeWindow", activeWindowListener);
      }
    }
  }

  /*
   * Static inner class, listens for 'activeWindow' KFM property changes and
   * updates the list of active windows per AppContext, so the latest active
   * window is always at the end of the list. The list is stored in AppContext.
   */
  @SuppressWarnings(value = {"deprecation", "unchecked"})
  private static class ActiveWindowListener implements PropertyChangeListener {
    public void propertyChange(PropertyChangeEvent e) {
      Window w = (Window) e.getNewValue();
      if (w == null) {
        return;
      }
      AppContext appContext = SunToolkit.targetToAppContext(w);
      synchronized (appContext) {
        WWindowPeer wp = (WWindowPeer) w.getPeer();
        // add/move wp to the end of the list
        List<WWindowPeer> l = (List<WWindowPeer>) appContext.get(ACTIVE_WINDOWS_KEY);
        if (l != null) {
          l.remove(wp);
          l.add(wp);
        }
      }
    }
  }
}
/**
 * This utility class is used to suspend execution on a thread while still allowing {@code
 * EventDispatchThread} to dispatch events. The API methods of the class are thread-safe.
 *
 * @author Anton Tarasov, Artem Ananiev
 * @since 1.7
 */
class WaitDispatchSupport implements SecondaryLoop {

  private static final PlatformLogger log =
      PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");

  private EventDispatchThread dispatchThread;
  private EventFilter filter;

  private volatile Conditional extCondition;
  private volatile Conditional condition;

  private long interval;
  // Use a shared daemon timer to serve all the WaitDispatchSupports
  private static Timer timer;
  // When this WDS expires, we cancel the timer task leaving the
  // shared timer up and running
  private TimerTask timerTask;

  private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
  private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);

  private static synchronized void initializeTimer() {
    if (timer == null) {
      timer = new Timer("AWT-WaitDispatchSupport-Timer", true);
    }
  }

  /**
   * Creates a {@code WaitDispatchSupport} instance to serve the given event dispatch thread.
   *
   * @param dispatchThread An event dispatch thread that should not stop dispatching events while
   *     waiting
   * @since 1.7
   */
  public WaitDispatchSupport(EventDispatchThread dispatchThread) {
    this(dispatchThread, null);
  }

  /**
   * Creates a {@code WaitDispatchSupport} instance to serve the given event dispatch thread.
   *
   * @param dispatchThread An event dispatch thread that should not stop dispatching events while
   *     waiting
   * @param extCondition A conditional object used to determine if the loop should be terminated
   * @since 1.7
   */
  public WaitDispatchSupport(EventDispatchThread dispatchThread, Conditional extCond) {
    if (dispatchThread == null) {
      throw new IllegalArgumentException("The dispatchThread can not be null");
    }

    this.dispatchThread = dispatchThread;
    this.extCondition = extCond;
    this.condition =
        new Conditional() {
          @Override
          public boolean evaluate() {
            if (log.isLoggable(PlatformLogger.Level.FINEST)) {
              log.finest(
                  "evaluate(): blockingEDT="
                      + keepBlockingEDT.get()
                      + ", blockingCT="
                      + keepBlockingCT.get());
            }
            boolean extEvaluate = (extCondition != null) ? extCondition.evaluate() : true;
            if (!keepBlockingEDT.get() || !extEvaluate) {
              if (timerTask != null) {
                timerTask.cancel();
                timerTask = null;
              }
              return false;
            }
            return true;
          }
        };
  }

  /**
   * Creates a {@code WaitDispatchSupport} instance to serve the given event dispatch thread.
   *
   * <p>The {@link EventFilter} is set on the {@code dispatchThread} while waiting. The filter is
   * removed on completion of the waiting process.
   *
   * <p>
   *
   * @param dispatchThread An event dispatch thread that should not stop dispatching events while
   *     waiting
   * @param filter {@code EventFilter} to be set
   * @param interval A time interval to wait for. Note that when the waiting process takes place on
   *     EDT there is no guarantee to stop it in the given time
   * @since 1.7
   */
  public WaitDispatchSupport(
      EventDispatchThread dispatchThread,
      Conditional extCondition,
      EventFilter filter,
      long interval) {
    this(dispatchThread, extCondition);
    this.filter = filter;
    if (interval < 0) {
      throw new IllegalArgumentException("The interval value must be >= 0");
    }
    this.interval = interval;
    if (interval != 0) {
      initializeTimer();
    }
  }

  /** @inheritDoc */
  @Override
  public boolean enter() {
    if (log.isLoggable(PlatformLogger.Level.FINE)) {
      log.fine(
          "enter(): blockingEDT=" + keepBlockingEDT.get() + ", blockingCT=" + keepBlockingCT.get());
    }

    if (!keepBlockingEDT.compareAndSet(false, true)) {
      log.fine("The secondary loop is already running, aborting");
      return false;
    }

    final Runnable run =
        new Runnable() {
          public void run() {
            log.fine("Starting a new event pump");
            if (filter == null) {
              dispatchThread.pumpEvents(condition);
            } else {
              dispatchThread.pumpEventsForFilter(condition, filter);
            }
          }
        };

    // We have two mechanisms for blocking: if we're on the
    // dispatch thread, start a new event pump; if we're
    // on any other thread, call wait() on the treelock

    Thread currentThread = Thread.currentThread();
    if (currentThread == dispatchThread) {
      if (log.isLoggable(PlatformLogger.Level.FINEST)) {
        log.finest("On dispatch thread: " + dispatchThread);
      }
      if (interval != 0) {
        if (log.isLoggable(PlatformLogger.Level.FINEST)) {
          log.finest("scheduling the timer for " + interval + " ms");
        }
        timer.schedule(
            timerTask =
                new TimerTask() {
                  @Override
                  public void run() {
                    if (keepBlockingEDT.compareAndSet(true, false)) {
                      wakeupEDT();
                    }
                  }
                },
            interval);
      }
      // Dispose SequencedEvent we are dispatching on the the current
      // AppContext, to prevent us from hang - see 4531693 for details
      SequencedEvent currentSE =
          KeyboardFocusManager.getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
      if (currentSE != null) {
        if (log.isLoggable(PlatformLogger.Level.FINE)) {
          log.fine("Dispose current SequencedEvent: " + currentSE);
        }
        currentSE.dispose();
      }
      // In case the exit() method is called before starting
      // new event pump it will post the waking event to EDT.
      // The event will be handled after the the new event pump
      // starts. Thus, the enter() method will not hang.
      //
      // Event pump should be privileged. See 6300270.
      AccessController.doPrivileged(
          new PrivilegedAction() {
            public Object run() {
              run.run();
              return null;
            }
          });
    } else {
      if (log.isLoggable(PlatformLogger.Level.FINEST)) {
        log.finest("On non-dispatch thread: " + currentThread);
      }
      synchronized (getTreeLock()) {
        if (filter != null) {
          dispatchThread.addEventFilter(filter);
        }
        try {
          EventQueue eq = dispatchThread.getEventQueue();
          eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
          keepBlockingCT.set(true);
          if (interval > 0) {
            long currTime = System.currentTimeMillis();
            while (keepBlockingCT.get()
                && ((extCondition != null) ? extCondition.evaluate() : true)
                && (currTime + interval > System.currentTimeMillis())) {
              getTreeLock().wait(interval);
            }
          } else {
            while (keepBlockingCT.get()
                && ((extCondition != null) ? extCondition.evaluate() : true)) {
              getTreeLock().wait();
            }
          }
          if (log.isLoggable(PlatformLogger.Level.FINE)) {
            log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
          }
        } catch (InterruptedException e) {
          if (log.isLoggable(PlatformLogger.Level.FINE)) {
            log.fine("Exception caught while waiting: " + e);
          }
        } finally {
          if (filter != null) {
            dispatchThread.removeEventFilter(filter);
          }
        }
        // If the waiting process has been stopped because of the
        // time interval passed or an exception occurred, the state
        // should be changed
        keepBlockingEDT.set(false);
        keepBlockingCT.set(false);
      }
    }

    return true;
  }

  /** @inheritDoc */
  public boolean exit() {
    if (log.isLoggable(PlatformLogger.Level.FINE)) {
      log.fine(
          "exit(): blockingEDT=" + keepBlockingEDT.get() + ", blockingCT=" + keepBlockingCT.get());
    }
    if (keepBlockingEDT.compareAndSet(true, false)) {
      wakeupEDT();
      return true;
    }
    return false;
  }

  private static final Object getTreeLock() {
    return Component.LOCK;
  }

  private final Runnable wakingRunnable =
      new Runnable() {
        public void run() {
          log.fine("Wake up EDT");
          synchronized (getTreeLock()) {
            keepBlockingCT.set(false);
            getTreeLock().notifyAll();
          }
          log.fine("Wake up EDT done");
        }
      };

  private void wakeupEDT() {
    if (log.isLoggable(PlatformLogger.Level.FINEST)) {
      log.finest("wakeupEDT(): EDT == " + dispatchThread);
    }
    EventQueue eq = dispatchThread.getEventQueue();
    eq.postEvent(new PeerEvent(this, wakingRunnable, PeerEvent.PRIORITY_EVENT));
  }
}
/**
 * The XDragSourceContextPeer class is the class responsible for handling the interaction between
 * the XDnD/Motif DnD subsystem and Java drag sources.
 *
 * @since 1.5
 */
public final class XDragSourceContextPeer extends SunDragSourceContextPeer
    implements XDragSourceProtocolListener {
  private static final PlatformLogger logger =
      PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDragSourceContextPeer");

  /* The events selected on the root window when the drag begins. */
  private static final int ROOT_EVENT_MASK =
      (int) XConstants.ButtonMotionMask
          | (int) XConstants.KeyPressMask
          | (int) XConstants.KeyReleaseMask;
  /* The events to be delivered during grab. */
  private static final int GRAB_EVENT_MASK =
      (int) XConstants.ButtonPressMask
          | (int) XConstants.ButtonMotionMask
          | (int) XConstants.ButtonReleaseMask;

  /* The event mask of the root window before the drag operation starts. */
  private long rootEventMask = 0;
  private boolean dndInProgress = false;
  private boolean dragInProgress = false;
  private long dragRootWindow = 0;

  /* The protocol chosen for the communication with the current drop target. */
  private XDragSourceProtocol dragProtocol = null;
  /* The drop action chosen by the current drop target. */
  private int targetAction = DnDConstants.ACTION_NONE;
  /* The set of drop actions supported by the drag source. */
  private int sourceActions = DnDConstants.ACTION_NONE;
  /* The drop action selected by the drag source based on the modifiers state
  and the action selected by the current drop target. */
  private int sourceAction = DnDConstants.ACTION_NONE;
  /* The data formats supported by the drag source for the current drag
  operation. */
  private long[] sourceFormats = null;
  /* The XID of the root subwindow that contains the current target. */
  private long targetRootSubwindow = 0;
  /* The pointer location. */
  private int xRoot = 0;
  private int yRoot = 0;
  /* Keyboard modifiers state. */
  private int eventState = 0;

  /* XEmbed DnD support. We act as a proxy between source and target. */
  private long proxyModeSourceWindow = 0;

  /* The singleton instance. */
  private static final XDragSourceContextPeer theInstance = new XDragSourceContextPeer(null);

  private XDragSourceContextPeer(DragGestureEvent dge) {
    super(dge);
  }

  static XDragSourceProtocolListener getXDragSourceProtocolListener() {
    return theInstance;
  }

  static XDragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
      throws InvalidDnDOperationException {
    theInstance.setTrigger(dge);
    return theInstance;
  }

  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);
  }

  public long getProxyModeSourceWindow() {
    return proxyModeSourceWindow;
  }

  private void setProxyModeSourceWindowImpl(long window) {
    proxyModeSourceWindow = window;
  }

  public static void setProxyModeSourceWindow(long window) {
    theInstance.setProxyModeSourceWindowImpl(window);
  }

  /** set cursor */
  public void setCursor(Cursor c) throws InvalidDnDOperationException {
    XToolkit.awtLock();
    try {
      super.setCursor(c);
    } finally {
      XToolkit.awtUnlock();
    }
  }

  protected void setNativeCursor(long nativeCtxt, Cursor c, int cType) {
    assert XToolkit.isAWTLockHeldByCurrentThread();

    if (c == null) {
      return;
    }

    long xcursor = XGlobalCursorManager.getCursor(c);

    if (xcursor == 0) {
      return;
    }

    XlibWrapper.XChangeActivePointerGrab(
        XToolkit.getDisplay(), GRAB_EVENT_MASK, xcursor, XConstants.CurrentTime);
  }

  protected boolean needsBogusExitBeforeDrop() {
    return false;
  }

  private void throwGrabFailureException(String msg, int grabStatus)
      throws InvalidDnDOperationException {
    String msgCause = "";
    switch (grabStatus) {
      case XConstants.GrabNotViewable:
        msgCause = "not viewable";
        break;
      case XConstants.AlreadyGrabbed:
        msgCause = "already grabbed";
        break;
      case XConstants.GrabInvalidTime:
        msgCause = "invalid time";
        break;
      case XConstants.GrabFrozen:
        msgCause = "grab frozen";
        break;
      default:
        msgCause = "unknown failure";
        break;
    }
    throw new InvalidDnDOperationException(msg + ": " + msgCause);
  }

  /** 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);
  }

  /** The caller must own awtLock. */
  private void cleanupTargetInfo() {
    targetAction = DnDConstants.ACTION_NONE;
    dragProtocol = null;
    targetRootSubwindow = 0;
  }

  private void removeDnDGrab(long time) {
    assert XToolkit.isAWTLockHeldByCurrentThread();

    XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), time);
    XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), time);

    /* Restore the root event mask if it was changed. */
    if ((rootEventMask | ROOT_EVENT_MASK) != rootEventMask && dragRootWindow != 0) {

      XlibWrapper.XSelectInput(XToolkit.getDisplay(), dragRootWindow, rootEventMask);
    }

    rootEventMask = 0;
    dragRootWindow = 0;
  }

  private boolean processClientMessage(XClientMessageEvent xclient) {
    if (dragProtocol != null) {
      return dragProtocol.processClientMessage(xclient);
    }
    return false;
  }

  /**
   * Updates the source action according to the specified state.
   *
   * @returns true if the source
   */
  private boolean updateSourceAction(int state) {
    int action =
        SunDragSourceContextPeer.convertModifiersToDropAction(
            XWindow.getModifiers(state, 0, 0), sourceActions);
    if (sourceAction == action) {
      return false;
    }
    sourceAction = action;
    return true;
  }

  /** Returns the client window under the specified root subwindow. */
  private static long findClientWindow(long window) {
    if (XlibUtil.isTrueToplevelWindow(window)) {
      return window;
    }

    Set<Long> children = XlibUtil.getChildWindows(window);
    for (Long child : children) {
      long win = findClientWindow(child);
      if (win != 0) {
        return win;
      }
    }

    return 0;
  }

  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);
      }
    }
  }

  /*
   * 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());
    }
  }

  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());
    }
  }

  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;
  }

  /**
   * 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;
  }

  static boolean processEvent(XEvent ev) {
    XToolkit.awtLock();
    try {
      try {
        return theInstance.doProcessEvent(ev);
      } catch (XException e) {
        e.printStackTrace();
        return false;
      }
    } finally {
      XToolkit.awtUnlock();
    }
  }

  /* XDragSourceProtocolListener implementation */

  public void handleDragReply(int action) {
    // NOTE: we have to use the current pointer location, since
    // the target didn't specify the coordinates for the reply.
    handleDragReply(action, xRoot, yRoot);
  }

  public void handleDragReply(int action, int x, int y) {
    // NOTE: we have to use the current modifiers state, since
    // the target didn't specify the modifiers state for the reply.
    handleDragReply(action, xRoot, yRoot, XWindow.getModifiers(eventState, 0, 0));
  }

  public void handleDragReply(int action, int x, int y, int modifiers) {
    if (action == DnDConstants.ACTION_NONE && targetAction != DnDConstants.ACTION_NONE) {
      dragExit(x, y);
    } else if (action != DnDConstants.ACTION_NONE) {
      int type = 0;

      if (targetAction == DnDConstants.ACTION_NONE) {
        type = SunDragSourceContextPeer.DISPATCH_ENTER;
      } else {
        type = SunDragSourceContextPeer.DISPATCH_MOTION;
      }

      // Note that we use the modifiers state a
      postDragSourceDragEvent(action, modifiers, x, y, type);
    }

    targetAction = action;
  }

  public void handleDragFinished() {
    /* Assume that the drop was successful. */
    handleDragFinished(true);
  }

  public void handleDragFinished(boolean success) {
    /* Assume that the performed drop action is the latest drop action
    accepted by the drop target. */
    handleDragFinished(true, targetAction);
  }

  public void handleDragFinished(boolean success, int action) {
    // NOTE: we have to use the current pointer location, since
    // the target didn't specify the coordinates for the reply.
    handleDragFinished(success, action, xRoot, yRoot);
  }

  public void handleDragFinished(boolean success, int action, int x, int y) {
    dragDropFinished(success, action, x, y);

    dndInProgress = false;
    cleanup(XConstants.CurrentTime);
  }
}