1 /*
   2  * Copyright (c) 2003, 2020, 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.AWTEvent;
  29 import java.awt.AWTException;
  30 import java.awt.BufferCapabilities;
  31 import java.awt.Color;
  32 import java.awt.Component;
  33 import java.awt.Container;
  34 import java.awt.Dimension;
  35 import java.awt.Font;
  36 import java.awt.FontMetrics;
  37 import java.awt.Graphics;
  38 import java.awt.GraphicsConfiguration;
  39 import java.awt.Image;
  40 import java.awt.Point;
  41 import java.awt.Rectangle;
  42 import java.awt.Toolkit;
  43 import java.awt.Window;
  44 import java.awt.event.ComponentEvent;
  45 import java.awt.event.FocusEvent;
  46 import java.awt.event.InputEvent;
  47 import java.awt.event.InvocationEvent;
  48 import java.awt.event.KeyEvent;
  49 import java.awt.event.PaintEvent;
  50 import java.awt.image.ColorModel;
  51 import java.awt.image.VolatileImage;
  52 import java.awt.peer.ComponentPeer;
  53 import java.awt.peer.ContainerPeer;
  54 
  55 import sun.java2d.pipe.Region;
  56 
  57 public class XEmbedChildProxyPeer implements ComponentPeer, XEventDispatcher{
  58     XEmbeddingContainer container;
  59     XEmbedChildProxy proxy;
  60     long handle;
  61     XEmbedChildProxyPeer(XEmbedChildProxy proxy) {
  62         this.container = proxy.getEmbeddingContainer();
  63         this.handle = proxy.getHandle();
  64         this.proxy = proxy;
  65         initDispatching();
  66     }
  67 
  68     void initDispatching() {
  69         XToolkit.awtLock();
  70         try {
  71             XToolkit.addEventDispatcher(handle, this);
  72             XlibWrapper.XSelectInput(XToolkit.getDisplay(), handle,
  73                     XConstants.StructureNotifyMask | XConstants.PropertyChangeMask);
  74         }
  75         finally {
  76             XToolkit.awtUnlock();
  77         }
  78         container.notifyChildEmbedded(handle);
  79     }
  80     public boolean isObscured() { return false; }
  81     public boolean canDetermineObscurity() { return false; }
  82     public void                 setVisible(boolean b) {
  83         if (!b) {
  84             XToolkit.awtLock();
  85             try {
  86                 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), handle);
  87             }
  88             finally {
  89                 XToolkit.awtUnlock();
  90             }
  91         } else {
  92             XToolkit.awtLock();
  93             try {
  94                 XlibWrapper.XMapWindow(XToolkit.getDisplay(), handle);
  95             }
  96             finally {
  97                 XToolkit.awtUnlock();
  98             }
  99         }
 100     }
 101     public void setEnabled(boolean b) {}
 102     public void paint(Graphics g) {}
 103     public void print(Graphics g) {}
 104     public void setBounds(int x, int y, int width, int height, int op) {
 105         // Unimplemeneted: Check for min/max hints for non-resizable
 106         XToolkit.awtLock();
 107         try {
 108             XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), handle, x, y, width, height);
 109         }
 110         finally {
 111             XToolkit.awtUnlock();
 112         }
 113     }
 114     public void handleEvent(AWTEvent e) {
 115         switch (e.getID()) {
 116           case FocusEvent.FOCUS_GAINED:
 117               XKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(proxy);
 118               container.focusGained(handle);
 119               break;
 120           case FocusEvent.FOCUS_LOST:
 121               XKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
 122               container.focusLost(handle);
 123               break;
 124           case KeyEvent.KEY_PRESSED:
 125           case KeyEvent.KEY_RELEASED:
 126               if (!((InputEvent)e).isConsumed()) {
 127                   container.forwardKeyEvent(handle, (KeyEvent)e);
 128               }
 129               break;
 130         }
 131     }
 132     public void                coalescePaintEvent(PaintEvent e) {}
 133     public Point                getLocationOnScreen() {
 134         XWindowAttributes attr = new XWindowAttributes();
 135         XToolkit.awtLock();
 136         try{
 137             XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), handle, attr.pData);
 138             return new Point(attr.get_x(), attr.get_y());
 139         } finally {
 140             XToolkit.awtUnlock();
 141             attr.dispose();
 142         }
 143     }
 144     public Dimension            getPreferredSize() {
 145         XToolkit.awtLock();
 146         long p_hints = XlibWrapper.XAllocSizeHints();
 147         try {
 148             XSizeHints hints = new XSizeHints(p_hints);
 149             XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), handle, p_hints, XlibWrapper.larg1);
 150             Dimension res = new Dimension(hints.get_width(), hints.get_height());
 151             return res;
 152         } finally {
 153             XlibWrapper.XFree(p_hints);
 154             XToolkit.awtUnlock();
 155         }
 156     }
 157     public Dimension            getMinimumSize() {
 158         XToolkit.awtLock();
 159         long p_hints = XlibWrapper.XAllocSizeHints();
 160         try {
 161             XSizeHints hints = new XSizeHints(p_hints);
 162             XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), handle, p_hints, XlibWrapper.larg1);
 163             Dimension res = new Dimension(hints.get_min_width(), hints.get_min_height());
 164             return res;
 165         } finally {
 166             XlibWrapper.XFree(p_hints);
 167             XToolkit.awtUnlock();
 168         }
 169     }
 170     public ColorModel           getColorModel() { return null; }
 171     public Toolkit              getToolkit() { return Toolkit.getDefaultToolkit(); }
 172 
 173     public Graphics             getGraphics() { return null; }
 174     public FontMetrics          getFontMetrics(Font font) { return null; }
 175     public void         dispose() {
 176         container.detachChild(handle);
 177     }
 178     public void         setForeground(Color c) {}
 179     public void         setBackground(Color c) {}
 180     public void         setFont(Font f) {}
 181     public void                 updateCursorImmediately() {}
 182 
 183     void postEvent(AWTEvent event) {
 184         XToolkit.postEvent(XToolkit.targetToAppContext(proxy), event);
 185     }
 186 
 187     boolean simulateMotifRequestFocus(Component lightweightChild, boolean temporary,
 188                                       boolean focusedWindowChangeAllowed, long time)
 189     {
 190         if (lightweightChild == null) {
 191             lightweightChild = (Component)proxy;
 192         }
 193         Component currentOwner = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusOwner();
 194         if (currentOwner != null && !currentOwner.isDisplayable()) {
 195             currentOwner = null;
 196         }
 197         FocusEvent  fg = new FocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED, false, currentOwner );
 198         FocusEvent fl = null;
 199         if (currentOwner != null) {
 200             fl = new FocusEvent(currentOwner, FocusEvent.FOCUS_LOST, false, lightweightChild);
 201         }
 202 
 203         // TODO: do we need to wrap in sequenced?
 204         if (fl != null) {
 205             postEvent(XComponentPeer.wrapInSequenced(fl));
 206         }
 207         postEvent(XComponentPeer.wrapInSequenced(fg));
 208         // End of Motif compatibility code
 209         return true;
 210     }
 211 
 212     public boolean requestFocus(Component lightweightChild,
 213                                 boolean temporary,
 214                                 boolean focusedWindowChangeAllowed,
 215                                 long time,
 216                                 FocusEvent.Cause cause)
 217     {
 218         int result = XKeyboardFocusManagerPeer
 219             .shouldNativelyFocusHeavyweight(proxy, lightweightChild,
 220                                             temporary, false, time, cause);
 221 
 222         switch (result) {
 223           case XKeyboardFocusManagerPeer.SNFH_FAILURE:
 224               return false;
 225           case XKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:
 226               // Currently we just generate focus events like we deal with lightweight instead of calling
 227               // XSetInputFocus on native window
 228 
 229               /**
 230                * The problems with requests in non-focused window arise because shouldNativelyFocusHeavyweight
 231                * checks that native window is focused while appropriate WINDOW_GAINED_FOCUS has not yet
 232                * been processed - it is in EventQueue. Thus, SNFH allows native request and stores request record
 233                * in requests list - and it breaks our requests sequence as first record on WGF should be the last focus
 234                * owner which had focus before WLF. So, we should not add request record for such requests
 235                * but store this component in mostRecent - and return true as before for compatibility.
 236                */
 237               Container parent = proxy.getParent();
 238               // Search for parent window
 239               while (parent != null && !(parent instanceof Window)) {
 240                   parent = parent.getParent();
 241               }
 242               if (parent != null) {
 243                   Window parentWindow = (Window)parent;
 244                   // and check that it is focused
 245                   if (!parentWindow.isFocused() &&
 246                       XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == parentWindow) {
 247                       // if it is not - skip requesting focus on Solaris
 248                       // but return true for compatibility.
 249                       return true;
 250                   }
 251               }
 252 
 253               // NOTE: We simulate heavyweight behavior of Motif - component receives focus right
 254               // after request, not after event. Normally, we should better listen for event
 255               // by listeners.
 256 
 257               // TODO: consider replacing with XKeyboardFocusManagerPeer.deliverFocus
 258               return simulateMotifRequestFocus(lightweightChild, temporary, focusedWindowChangeAllowed, time);
 259               // Motif compatibility code
 260           case XKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:
 261               // Either lightweight or excessive requiest - all events are generated.
 262               return true;
 263         }
 264         return false;
 265     }
 266     public boolean              isFocusable() {
 267         return true;
 268     }
 269 
 270     public Image                createImage(int width, int height) { return null; }
 271     public VolatileImage        createVolatileImage(int width, int height) { return null; }
 272     public GraphicsConfiguration getGraphicsConfiguration() { return null; }
 273     public boolean     handlesWheelScrolling() { return true; }
 274     public void createBuffers(int numBuffers, BufferCapabilities caps)
 275       throws AWTException { }
 276     public Image getBackBuffer() { return null; }
 277     public void flip(int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction) {  }
 278     public void destroyBuffers() { }
 279 
 280     /**
 281      * Used by lightweight implementations to tell a ComponentPeer to layout
 282      * its sub-elements.  For instance, a lightweight Checkbox needs to layout
 283      * the box, as well as the text label.
 284      */
 285     public void        layout() {}
 286 
 287     Window getTopLevel(Component comp) {
 288         while (comp != null && !(comp instanceof Window)) {
 289             comp = comp.getParent();
 290         }
 291         return (Window)comp;
 292     }
 293 
 294     void childResized() {
 295         XToolkit.postEvent(XToolkit.targetToAppContext(proxy), new ComponentEvent(proxy, ComponentEvent.COMPONENT_RESIZED));
 296         container.childResized(proxy);
 297 //         XToolkit.postEvent(XToolkit.targetToAppContext(proxy), new InvocationEvent(proxy, new Runnable() {
 298 //                 public void run() {
 299 //                     getTopLevel(proxy).invalidate();
 300 //                     getTopLevel(proxy).pack();
 301 //                 }
 302 //             }));
 303     }
 304     void handlePropertyNotify(XEvent xev) {
 305         XPropertyEvent ev = xev.get_xproperty();
 306         if (ev.get_atom() == XAtom.XA_WM_NORMAL_HINTS) {
 307             childResized();
 308         }
 309     }
 310     void handleConfigureNotify(XEvent xev) {
 311         childResized();
 312     }
 313     public void dispatchEvent(XEvent xev) {
 314         int type = xev.get_type();
 315         switch (type) {
 316           case XConstants.PropertyNotify:
 317               handlePropertyNotify(xev);
 318               break;
 319           case XConstants.ConfigureNotify:
 320               handleConfigureNotify(xev);
 321               break;
 322         }
 323     }
 324 
 325     void requestXEmbedFocus() {
 326         postEvent(new InvocationEvent(proxy, new Runnable() {
 327                 public void run() {
 328                     proxy.requestFocusInWindow();
 329                 }
 330             }));
 331     }
 332 
 333     public void reparent(ContainerPeer newNativeParent) {
 334     }
 335     public boolean isReparentSupported() {
 336         return false;
 337     }
 338     public Rectangle getBounds() {
 339         XWindowAttributes attrs = new XWindowAttributes();
 340         XToolkit.awtLock();
 341         try {
 342             XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), handle, attrs.pData);
 343             return new Rectangle(attrs.get_x(), attrs.get_y(), attrs.get_width(), attrs.get_height());
 344         } finally {
 345             XToolkit.awtUnlock();
 346             attrs.dispose();
 347         }
 348     }
 349     public void setBoundsOperation(int operation) {
 350     }
 351 
 352     public void applyShape(Region shape) {
 353     }
 354 
 355     public void setZOrder(ComponentPeer above) {
 356     }
 357 
 358     public boolean updateGraphicsData(GraphicsConfiguration gc) {
 359         return false;
 360     }
 361 }