1 /*
   2  * Copyright 2002-2008 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any 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 java.util.logging.Level;
  34 import java.util.logging.Logger;
  35 
  36 import sun.awt.EmbeddedFrame;
  37 import sun.awt.SunToolkit;
  38 
  39 public class XEmbeddedFramePeer extends XFramePeer {
  40 
  41     private static final Logger xembedLog = Logger.getLogger("sun.awt.X11.xembed.XEmbeddedFramePeer");
  42 
  43     LinkedList<AWTKeyStroke> strokes;
  44 
  45     XEmbedClientHelper embedder; // Caution - can be null if XEmbed is not supported
  46     public XEmbeddedFramePeer(EmbeddedFrame target) {
  47         // Don't specify PARENT_WINDOW param here. Instead we reparent
  48         // this embedded frame peer to the proper parent window after
  49         // an XEventDispatcher is registered to handle XEmbed events
  50         super(new XCreateWindowParams(new Object[] {
  51             TARGET, target,
  52             VISIBLE, Boolean.TRUE,
  53             EMBEDDED, Boolean.TRUE}));
  54     }
  55 
  56     public void preInit(XCreateWindowParams params) {
  57         super.preInit(params);
  58         strokes = new LinkedList<AWTKeyStroke>();
  59         if (supportsXEmbed()) {
  60             embedder = new XEmbedClientHelper();
  61         }
  62     }
  63     void postInit(XCreateWindowParams params) {
  64         super.postInit(params);
  65         if (embedder != null) {
  66             // install X11 event dispatcher
  67             embedder.setClient(this);
  68             // reparent to XEmbed server
  69             embedder.install();
  70         } else if (getParentWindowHandle() != 0) {
  71             XToolkit.awtLock();
  72             try {
  73                 XlibWrapper.XReparentWindow(XToolkit.getDisplay(),
  74                                             getWindow(),
  75                                             getParentWindowHandle(),
  76                                             0, 0);
  77             } finally {
  78                 XToolkit.awtUnlock();
  79             }
  80         }
  81     }
  82 
  83     @Override
  84     public void dispose() {
  85         if (embedder != null) {
  86             // uninstall X11 event dispatcher
  87             embedder.setClient(null);
  88         }
  89         super.dispose();
  90     }
  91 
  92     public void updateMinimumSize() {
  93     }
  94 
  95     protected String getWMName() {
  96         return "JavaEmbeddedFrame";
  97     }
  98 
  99     final long getParentWindowHandle() {
 100         return ((XEmbeddedFrame)target).handle;
 101     }
 102 
 103     boolean supportsXEmbed() {
 104         return ((EmbeddedFrame)target).supportsXEmbed();
 105     }
 106 
 107     public boolean requestWindowFocus(long time, boolean timeProvided) {
 108         // Should check for active state of host application
 109         if (embedder != null && embedder.isActive()) {
 110             xembedLog.fine("Requesting focus from embedding host");
 111             return embedder.requestFocus();
 112         } else {
 113             xembedLog.fine("Requesting focus from X");
 114             return super.requestWindowFocus(time, timeProvided);
 115         }
 116     }
 117 
 118     protected void requestInitialFocus() {
 119         if (embedder != null && supportsXEmbed()) {
 120             embedder.requestFocus();
 121         } else {
 122             super.requestInitialFocus();
 123         }
 124     }
 125 
 126     protected boolean isEventDisabled(XEvent e) {
 127         if (embedder != null && embedder.isActive()) {
 128             switch (e.get_type()) {
 129               case XConstants.FocusIn:
 130               case XConstants.FocusOut:
 131                   return true;
 132             }
 133         }
 134         return super.isEventDisabled(e);
 135     }
 136 
 137     public void handleConfigureNotifyEvent(XEvent xev)
 138     {
 139         assert (SunToolkit.isAWTLockHeldByCurrentThread());
 140         XConfigureEvent xe = xev.get_xconfigure();
 141         if (xembedLog.isLoggable(Level.FINE)) {
 142             xembedLog.fine(xe.toString());
 143         }
 144 
 145         // fix for 5063031
 146         // if we use super.handleConfigureNotifyEvent() we would get wrong
 147         // size and position because embedded frame really is NOT a decorated one
 148         checkIfOnNewScreen(toGlobal(new Rectangle(xe.get_x(),
 149                 xe.get_y(),
 150                 xe.get_width(),
 151                 xe.get_height())));
 152 
 153         Rectangle oldBounds = getBounds();
 154 
 155         synchronized (getStateLock()) {
 156             x = xe.get_x();
 157             y = xe.get_y();
 158             width = xe.get_width();
 159             height = xe.get_height();
 160 
 161             dimensions.setClientSize(width, height);
 162             dimensions.setLocation(x, y);
 163         }
 164 
 165         if (!getLocation().equals(oldBounds.getLocation())) {
 166             handleMoved(dimensions);
 167         }
 168         reconfigureContentWindow(dimensions);
 169     }
 170 
 171     protected void traverseOutForward() {
 172         if (embedder != null && embedder.isActive()) {
 173             if (embedder.isApplicationActive()) {
 174                 xembedLog.fine("Traversing out Forward");
 175                 embedder.traverseOutForward();
 176             }
 177         }
 178     }
 179 
 180     protected void traverseOutBackward() {
 181         if (embedder != null && embedder.isActive()) {
 182             if (embedder.isApplicationActive()) {
 183                 xembedLog.fine("Traversing out Backward");
 184                 embedder.traverseOutBackward();
 185             }
 186         }
 187     }
 188 
 189     // don't use getLocationOnScreen() inherited from XDecoratedPeer
 190     public Point getLocationOnScreen() {
 191         XToolkit.awtLock();
 192         try {
 193             return toGlobal(0, 0);
 194         } finally {
 195             XToolkit.awtUnlock();
 196         }
 197     }
 198 
 199     // don't use getBounds() inherited from XDecoratedPeer
 200     public Rectangle getBounds() {
 201         return new Rectangle(x, y, width, height);
 202     }
 203 
 204     public void setBoundsPrivate(int x, int y, int width, int height) {
 205         setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);
 206     }
 207 
 208     public Rectangle getBoundsPrivate() {
 209         int x = 0, y = 0;
 210         int w = 0, h = 0;
 211         XWindowAttributes attr = new XWindowAttributes();
 212 
 213         XToolkit.awtLock();
 214         try {
 215             XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 216                 getWindow(), attr.pData);
 217             x = attr.get_x();
 218             y = attr.get_y();
 219             w = attr.get_width();
 220             h = attr.get_height();
 221         } finally {
 222             XToolkit.awtUnlock();
 223         }
 224         attr.dispose();
 225 
 226         return new Rectangle(x, y, w, h);
 227     }
 228     void registerAccelerator(AWTKeyStroke stroke) {
 229         if (stroke == null) return;
 230         strokes.add(stroke);
 231         if (embedder != null && embedder.isActive()) {
 232             embedder.registerAccelerator(stroke, strokes.size()-1);
 233         }
 234     }
 235 
 236     void unregisterAccelerator(AWTKeyStroke stroke) {
 237         if (stroke == null) return;
 238         if (embedder != null && embedder.isActive()) {
 239             int index = strokes.indexOf(stroke);
 240             embedder.unregisterAccelerator(index);
 241         }
 242     }
 243 
 244     void notifyStarted() {
 245         // Register accelerators
 246         if (embedder != null && embedder.isActive()) {
 247             int i = 0;
 248             Iterator<AWTKeyStroke> iter = strokes.iterator();
 249             while (iter.hasNext()) {
 250                 embedder.registerAccelerator(iter.next(), i++);
 251             }
 252         }
 253         // Now we know that the the embedder is an XEmbed server, so we
 254         // reregister the drop target to enable XDnD protocol support via
 255         // XEmbed.
 256         updateDropTarget();
 257     }
 258     void notifyStopped() {
 259         if (embedder != null && embedder.isActive()) {
 260             for (int i = strokes.size() - 1; i >= 0; i--) {
 261                 embedder.unregisterAccelerator(i);
 262             }
 263         }
 264     }
 265 
 266     long getFocusTargetWindow() {
 267         return getWindow();
 268     }
 269 
 270     boolean isXEmbedActive() {
 271         return embedder != null && embedder.isActive();
 272     }
 273 
 274     public int getAbsoluteX()
 275     {
 276         Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(),
 277                                                           XToolkit.getDefaultRootWindow(),
 278                                                           new Point(0, 0));
 279         return absoluteLoc.x;
 280     }
 281 
 282     public int getAbsoluteY()
 283     {
 284         Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(),
 285                                                           XToolkit.getDefaultRootWindow(),
 286                                                           new Point(0, 0));
 287         return absoluteLoc.y;
 288     }
 289 
 290     public int getWidth() {
 291         return width;
 292     }
 293     public int getHeight() {
 294         return height;
 295     }
 296 
 297     public Dimension getSize() {
 298         return new Dimension(width, height);
 299     }
 300 
 301     // override XWindowPeer's method to let the embedded frame to block
 302     // the containing window
 303     public void setModalBlocked(Dialog blocker, boolean blocked) {
 304         super.setModalBlocked(blocker, blocked);
 305 
 306         EmbeddedFrame frame = (EmbeddedFrame)target;
 307         frame.notifyModalBlocked(blocker, blocked);
 308     }
 309 }