1 /*
2  * Copyright (c) 2003, 2017, 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 package sun.awt.X11;
26 
27 import java.awt.Component;
28 import java.awt.Rectangle;
29 import java.awt.Insets;
30 
31 import java.awt.event.ComponentEvent;
32 
33 import sun.util.logging.PlatformLogger;
34 
35 import sun.awt.AWTAccessor;
36 
37 /**
38  * This class implements window which serves as content window for decorated frames.
39  * Its purpose to provide correct events dispatching for the complex
40  * constructs such as decorated frames.
41  *
42  * It should always be located at (- left inset, - top inset) in the associated
43  * decorated window.  So coordinates in it would be the same as java coordinates.
44  */
45 public final class XContentWindow extends XWindow {
46     private static PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XContentWindow");
47 
createContent(XDecoratedPeer parentFrame)48     static XContentWindow createContent(XDecoratedPeer parentFrame) {
49         final WindowDimensions dims = parentFrame.getDimensions();
50         Rectangle rec = dims.getBounds();
51         // Fix for  - set the location of the content window to the (-left inset, -top inset)
52         Insets ins = dims.getInsets();
53         if (ins != null) {
54             rec.x = -ins.left;
55             rec.y = -ins.top;
56         } else {
57             rec.x = 0;
58             rec.y = 0;
59         }
60         final XContentWindow cw = new XContentWindow(parentFrame, rec);
61         cw.xSetVisible(true);
62         return cw;
63     }
64 
65     private final XDecoratedPeer parentFrame;
66 
67     // A list of expose events that come when the parentFrame is iconified
68     private final java.util.List<SavedExposeEvent> iconifiedExposeEvents =
69             new java.util.ArrayList<SavedExposeEvent>();
70 
XContentWindow(XDecoratedPeer parentFrame, Rectangle bounds)71     private XContentWindow(XDecoratedPeer parentFrame, Rectangle bounds) {
72         super((Component)parentFrame.getTarget(), parentFrame.getShell(), bounds);
73         this.parentFrame = parentFrame;
74     }
75 
preInit(XCreateWindowParams params)76     void preInit(XCreateWindowParams params) {
77         super.preInit(params);
78         params.putIfNull(BIT_GRAVITY, Integer.valueOf(XConstants.NorthWestGravity));
79         Long eventMask = (Long)params.get(EVENT_MASK);
80         if (eventMask != null) {
81             eventMask = eventMask & ~(XConstants.StructureNotifyMask);
82             params.put(EVENT_MASK, eventMask);
83         }
84     }
85 
getWMName()86     protected String getWMName() {
87         return "Content window";
88     }
isEventDisabled(XEvent e)89     protected boolean isEventDisabled(XEvent e) {
90         switch (e.get_type()) {
91           // Override parentFrame to receive MouseEnter/Exit
92           case XConstants.EnterNotify:
93           case XConstants.LeaveNotify:
94               return false;
95           // We handle ConfigureNotify specifically in XDecoratedPeer
96           case XConstants.ConfigureNotify:
97               return true;
98           // We don't want SHOWN/HIDDEN on content window since it will duplicate XDecoratedPeer
99           case XConstants.MapNotify:
100           case XConstants.UnmapNotify:
101               return true;
102           default:
103               return super.isEventDisabled(e) || parentFrame.isEventDisabled(e);
104         }
105     }
106 
107     // Coordinates are that of the shell
setContentBounds(WindowDimensions dims)108     void setContentBounds(WindowDimensions dims) {
109         XToolkit.awtLock();
110         try {
111             // Bounds of content window are of the same size as bounds of Java window and with
112             // location as -(insets)
113             Rectangle newBounds = dims.getBounds();
114             Insets in = dims.getInsets();
115             if (in != null) {
116                 newBounds.setLocation(-in.left, -in.top);
117             }
118             if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
119                 insLog.fine("Setting content bounds {0}, old bounds {1}",
120                             newBounds, getBounds());
121             }
122             // Fix for 5023533:
123             // Change in the size of the content window means, well, change of the size
124             // Change in the location of the content window means change in insets
125             boolean needHandleResize = !(newBounds.equals(getBounds()));
126             boolean needPaint = width <= 0 || height <= 0;
127             reshape(newBounds);
128             if (needHandleResize) {
129                 insLog.fine("Sending RESIZED");
130                 handleResize(newBounds);
131             }
132             if (needPaint) {
133                 postPaintEvent(target, 0, 0, newBounds.width, newBounds.height);
134             }
135         } finally {
136             XToolkit.awtUnlock();
137         }
138     }
139 
140     @Override
handleExposeEvent(XEvent xev)141     public void handleExposeEvent(XEvent xev) {
142         if(parentFrame.isTargetUndecorated() &&
143            XWM.getWMID() != XWM.UNITY_COMPIZ_WM &&
144                 width <= 0 && height <= 0) {
145             // WM didn't send initial ConfigureNotify, so set the bounds here
146             setContentBounds(parentFrame.getDimensions());
147         }
148         if (width <= 0 || height <= 0) {
149             return;
150         }
151         super.handleExposeEvent(xev);
152     }
153 
154     // NOTE: This method may be called by privileged threads.
155     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
handleResize(Rectangle bounds)156     public void handleResize(Rectangle bounds) {
157         AWTAccessor.getComponentAccessor().setSize(target, bounds.width, bounds.height);
158         postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED));
159     }
160 
161 
postPaintEvent(Component target, int x, int y, int w, int h)162     public void postPaintEvent(Component target, int x, int y, int w, int h) {
163         // TODO: ?
164         // get rid of 'istanceof' by subclassing:
165         // XContentWindow -> XFrameContentWindow
166 
167         // Expose event(s) that result from deiconification
168         // come before a deicinofication notification.
169         // We reorder these events by saving all expose events
170         // that come when the frame is iconified. Then we
171         // actually handle saved expose events on deiconification.
172 
173         if (parentFrame instanceof XFramePeer &&
174                 (((XFramePeer)parentFrame).getState() & java.awt.Frame.ICONIFIED) != 0) {
175             // Save expose events if the frame is iconified
176             // in order to handle them on deiconification.
177             iconifiedExposeEvents.add(new SavedExposeEvent(target, x, y, w, h));
178         } else {
179             // Normal case: [it is not a frame or] the frame is not iconified.
180             super.postPaintEvent(target, x, y, w, h);
181         }
182     }
183 
purgeIconifiedExposeEvents()184     void purgeIconifiedExposeEvents() {
185         for (SavedExposeEvent evt : iconifiedExposeEvents) {
186             super.postPaintEvent(evt.target, evt.x, evt.y, evt.w, evt.h);
187         }
188         iconifiedExposeEvents.clear();
189     }
190 
191     private static class SavedExposeEvent {
192         Component target;
193         int x, y, w, h;
SavedExposeEvent(Component target, int x, int y, int w, int h)194         SavedExposeEvent(Component target, int x, int y, int w, int h) {
195             this.target = target;
196             this.x = x;
197             this.y = y;
198             this.w = w;
199             this.h = h;
200         }
201     }
202 
toString()203     public String toString() {
204         return getClass().getName() + "[" + getBounds() + "]";
205     }
206 }
207