1 /*
   2  * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.X11;
  27 
  28 import java.awt.*;
  29 
  30 import java.util.LinkedList;
  31 import java.util.Iterator;
  32 
  33 import sun.util.logging.PlatformLogger;
  34 
  35 import sun.awt.EmbeddedFrame;
  36 import sun.awt.SunToolkit;
  37 
  38 import static sun.awt.X11.XConstants.*;
  39 
  40 public class XEmbeddedFramePeer extends XFramePeer {
  41 
  42     private static final PlatformLogger xembedLog = PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbeddedFramePeer");
  43 
  44     LinkedList<AWTKeyStroke> strokes;
  45 
  46     XEmbedClientHelper embedder; // Caution - can be null if XEmbed is not supported
  47     public XEmbeddedFramePeer(EmbeddedFrame target) {
  48         // Don't specify PARENT_WINDOW param here. Instead we reparent
  49         // this embedded frame peer to the proper parent window after
  50         // an XEventDispatcher is registered to handle XEmbed events
  51         super(new XCreateWindowParams(new Object[] {
  52             TARGET, target,
  53             VISIBLE, Boolean.TRUE,
  54             EMBEDDED, Boolean.TRUE}));
  55     }
  56 
  57     public void preInit(XCreateWindowParams params) {
  58         super.preInit(params);
  59         strokes = new LinkedList<AWTKeyStroke>();
  60         if (supportsXEmbed()) {
  61             embedder = new XEmbedClientHelper();
  62         }
  63     }
  64     void postInit(XCreateWindowParams params) {
  65         super.postInit(params);
  66         if (embedder != null) {
  67             // install X11 event dispatcher
  68             embedder.setClient(this);
  69             // reparent to XEmbed server
  70             embedder.install();
  71         } else if (getParentWindowHandle() != 0) {
  72             XToolkit.awtLock();
  73             try {
  74                 XlibWrapper.XReparentWindow(XToolkit.getDisplay(),
  75                                             getWindow(),
  76                                             getParentWindowHandle(),
  77                                             0, 0);
  78             } finally {
  79                 XToolkit.awtUnlock();
  80             }
  81         }
  82     }
  83 
  84     @Override
  85     public void dispose() {
  86         if (embedder != null) {
  87             // uninstall X11 event dispatcher
  88             embedder.setClient(null);
  89         }
  90         super.dispose();
  91     }
  92 
  93     public void updateMinimumSize() {
  94     }
  95 
  96     protected String getWMName() {
  97         return "JavaEmbeddedFrame";
  98     }
  99 
 100     final long getParentWindowHandle() {
 101         return ((XEmbeddedFrame)target).handle;
 102     }
 103 
 104     boolean supportsXEmbed() {
 105         return ((EmbeddedFrame)target).supportsXEmbed();
 106     }
 107 
 108     public boolean requestWindowFocus(long time, boolean timeProvided) {
 109         // Should check for active state of host application
 110         if (embedder != null && embedder.isActive()) {
 111             xembedLog.fine("Requesting focus from embedding host");
 112             return embedder.requestFocus();
 113         } else {
 114             xembedLog.fine("Requesting focus from X");
 115             return super.requestWindowFocus(time, timeProvided);
 116         }
 117     }
 118 
 119     protected void requestInitialFocus() {
 120         if (embedder != null && supportsXEmbed()) {
 121             embedder.requestFocus();
 122         } else {
 123             super.requestInitialFocus();
 124         }
 125     }
 126 
 127     protected boolean isEventDisabled(XEvent e) {
 128         if (embedder != null && embedder.isActive()) {
 129             switch (e.get_type()) {
 130               case XConstants.FocusIn:
 131               case XConstants.FocusOut:
 132                   return true;
 133             }
 134         }
 135         return super.isEventDisabled(e);
 136     }
 137 
 138     public void handleConfigureNotifyEvent(XEvent xev)
 139     {
 140         assert (SunToolkit.isAWTLockHeldByCurrentThread());
 141         XConfigureEvent xe = xev.get_xconfigure();
 142         if (xembedLog.isLoggable(PlatformLogger.FINE)) {
 143             xembedLog.fine(xe.toString());
 144         }
 145 
 146         // fix for 5063031
 147         // if we use super.handleConfigureNotifyEvent() we would get wrong
 148         // size and position because embedded frame really is NOT a decorated one
 149         checkIfOnNewScreen(toGlobal(new Rectangle(xe.get_x(),
 150                 xe.get_y(),
 151                 xe.get_width(),
 152                 xe.get_height())));
 153 
 154         Rectangle oldBounds = getBounds();
 155 
 156         synchronized (getStateLock()) {
 157             x = xe.get_x();
 158             y = xe.get_y();
 159             width = xe.get_width();
 160             height = xe.get_height();
 161 
 162             dimensions.setClientSize(width, height);
 163             dimensions.setLocation(x, y);
 164         }
 165 
 166         if (!getLocation().equals(oldBounds.getLocation())) {
 167             handleMoved(dimensions);
 168         }
 169         reconfigureContentWindow(dimensions);
 170     }
 171 
 172     protected void traverseOutForward() {
 173         if (embedder != null && embedder.isActive()) {
 174             if (embedder.isApplicationActive()) {
 175                 xembedLog.fine("Traversing out Forward");
 176                 embedder.traverseOutForward();
 177             }
 178         }
 179     }
 180 
 181     protected void traverseOutBackward() {
 182         if (embedder != null && embedder.isActive()) {
 183             if (embedder.isApplicationActive()) {
 184                 xembedLog.fine("Traversing out Backward");
 185                 embedder.traverseOutBackward();
 186             }
 187         }
 188     }
 189 
 190     // don't use getLocationOnScreen() inherited from XDecoratedPeer
 191     public Point getLocationOnScreen() {
 192         XToolkit.awtLock();
 193         try {
 194             return toGlobal(0, 0);
 195         } finally {
 196             XToolkit.awtUnlock();
 197         }
 198     }
 199 
 200     // don't use getBounds() inherited from XDecoratedPeer
 201     public Rectangle getBounds() {
 202         return new Rectangle(x, y, width, height);
 203     }
 204 
 205     public void setBoundsPrivate(int x, int y, int width, int height) {
 206         setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);
 207     }
 208 
 209     public Rectangle getBoundsPrivate() {
 210         int x = 0, y = 0;
 211         int w = 0, h = 0;
 212         XWindowAttributes attr = new XWindowAttributes();
 213 
 214         XToolkit.awtLock();
 215         try {
 216             XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 217                 getWindow(), attr.pData);
 218             x = attr.get_x();
 219             y = attr.get_y();
 220             w = attr.get_width();
 221             h = attr.get_height();
 222         } finally {
 223             XToolkit.awtUnlock();
 224         }
 225         attr.dispose();
 226 
 227         return new Rectangle(x, y, w, h);
 228     }
 229     void registerAccelerator(AWTKeyStroke stroke) {
 230         if (stroke == null) return;
 231         strokes.add(stroke);
 232         if (embedder != null && embedder.isActive()) {
 233             embedder.registerAccelerator(stroke, strokes.size()-1);
 234         }
 235     }
 236 
 237     void unregisterAccelerator(AWTKeyStroke stroke) {
 238         if (stroke == null) return;
 239         if (embedder != null && embedder.isActive()) {
 240             int index = strokes.indexOf(stroke);
 241             embedder.unregisterAccelerator(index);
 242         }
 243     }
 244 
 245     void notifyStarted() {
 246         // Register accelerators
 247         if (embedder != null && embedder.isActive()) {
 248             int i = 0;
 249             Iterator<AWTKeyStroke> iter = strokes.iterator();
 250             while (iter.hasNext()) {
 251                 embedder.registerAccelerator(iter.next(), i++);
 252             }
 253         }
 254         // Now we know that the the embedder is an XEmbed server, so we
 255         // reregister the drop target to enable XDnD protocol support via
 256         // XEmbed.
 257         updateDropTarget();
 258     }
 259     void notifyStopped() {
 260         if (embedder != null && embedder.isActive()) {
 261             for (int i = strokes.size() - 1; i >= 0; i--) {
 262                 embedder.unregisterAccelerator(i);
 263             }
 264         }
 265     }
 266 
 267     long getFocusTargetWindow() {
 268         return getWindow();
 269     }
 270 
 271     boolean isXEmbedActive() {
 272         return embedder != null && embedder.isActive();
 273     }
 274 
 275     public int getAbsoluteX()
 276     {
 277         Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(),
 278                                                           XToolkit.getDefaultRootWindow(),
 279                                                           new Point(0, 0));
 280         return absoluteLoc != null ? absoluteLoc.x : 0;
 281     }
 282 
 283     public int getAbsoluteY()
 284     {
 285         Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(),
 286                                                           XToolkit.getDefaultRootWindow(),
 287                                                           new Point(0, 0));
 288         return absoluteLoc != null ? absoluteLoc.y : 0;
 289     }
 290 
 291     public int getWidth() {
 292         return width;
 293     }
 294     public int getHeight() {
 295         return height;
 296     }
 297 
 298     public Dimension getSize() {
 299         return new Dimension(width, height);
 300     }
 301 
 302     // override XWindowPeer's method to let the embedded frame to block
 303     // the containing window
 304     public void setModalBlocked(Dialog blocker, boolean blocked) {
 305         super.setModalBlocked(blocker, blocked);
 306 
 307         EmbeddedFrame frame = (EmbeddedFrame)target;
 308         frame.notifyModalBlocked(blocker, blocked);
 309     }
 310 
 311     public void synthesizeFocusInOut(boolean doFocus) {
 312         XFocusChangeEvent xev = new XFocusChangeEvent();
 313 
 314         XToolkit.awtLock();
 315         try {
 316             xev.set_type(doFocus ? FocusIn : FocusOut);
 317             xev.set_window(getFocusProxy().getWindow());
 318             xev.set_mode(NotifyNormal);
 319             XlibWrapper.XSendEvent(XToolkit.getDisplay(), getFocusProxy().getWindow(), false,
 320                                    NoEventMask, xev.pData);
 321         } finally {
 322             XToolkit.awtUnlock();
 323             xev.dispose();
 324         }
 325     }
 326 }