1 /*
2 * Copyright (c) 2002, 2016, 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.*;
28
29 import java.awt.event.ComponentEvent;
30 import java.awt.event.InvocationEvent;
31 import java.awt.event.WindowEvent;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Map;
35
36 import sun.awt.IconInfo;
37 import sun.util.logging.PlatformLogger;
38
39 import sun.awt.AWTAccessor;
40 import sun.awt.SunToolkit;
41
42 abstract class XDecoratedPeer extends XWindowPeer {
43 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XDecoratedPeer");
44 private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XDecoratedPeer");
45 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XDecoratedPeer");
46 private static final PlatformLogger iconLog = PlatformLogger.getLogger("sun.awt.X11.icon.XDecoratedPeer");
47
48 // Set to true when we get the first ConfigureNotify after being
49 // reparented - indicates that WM has adopted the top-level.
50 boolean configure_seen;
51 boolean insets_corrected;
52
53 XIconWindow iconWindow;
54 WindowDimensions dimensions;
55 XContentWindow content;
56 Insets currentInsets;
57 XFocusProxyWindow focusProxy;
58 static final Map<Class<?>,Insets> lastKnownInsets =
59 Collections.synchronizedMap(new HashMap<>());
60
61 XDecoratedPeer(Window target) {
62 super(target);
63 }
64
65 XDecoratedPeer(XCreateWindowParams params) {
66 super(params);
67 }
68
69 public long getShell() {
70 return window;
71 }
72
73 public long getContentWindow() {
74 return (content == null) ? window : content.getWindow();
75 }
76
77 void preInit(XCreateWindowParams params) {
78 super.preInit(params);
79 winAttr.initialFocus = true;
80
81 currentInsets = new Insets(0,0,0,0);
82 if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
83 currentInsets = lastKnownInsets.get(getClass());
84 }
85 applyGuessedInsets();
86
87 Rectangle bounds = (Rectangle)params.get(BOUNDS);
88 dimensions = new WindowDimensions(bounds, getRealInsets(), false);
89 params.put(BOUNDS, dimensions.getClientRect());
90 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
91 insLog.fine("Initial dimensions {0}", dimensions);
92 }
93
94 // Deny default processing of these events on the shell - proxy will take care of
95 // them instead
96 Long eventMask = (Long)params.get(EVENT_MASK);
97 params.add(EVENT_MASK, Long.valueOf(eventMask.longValue() & ~(XConstants.FocusChangeMask | XConstants.KeyPressMask | XConstants.KeyReleaseMask)));
98 }
99
100 void postInit(XCreateWindowParams params) {
101 // The size hints must be set BEFORE mapping the window (see 6895647)
102 updateSizeHints(dimensions);
103
104 // The super method maps the window if it's visible on the shared level
105 super.postInit(params);
106
107 // The lines that follow need to be in a postInit, so they
108 // happen after the X window is created.
109 initResizability();
110 XWM.requestWMExtents(getWindow());
111
112 content = XContentWindow.createContent(this);
113
114 if (warningWindow != null) {
115 warningWindow.toFront();
116 }
117 focusProxy = createFocusProxy();
118 }
119
120 void setIconHints(java.util.List<IconInfo> icons) {
121 if (!XWM.getWM().setNetWMIcon(this, icons)) {
122 if (icons.size() > 0) {
123 if (iconWindow == null) {
124 iconWindow = new XIconWindow(this);
125 }
126 iconWindow.setIconImages(icons);
127 }
128 }
129 }
130
131 public void updateMinimumSize() {
132 super.updateMinimumSize();
133 updateMinSizeHints();
134 }
135
136 private void updateMinSizeHints() {
137 if (isResizable()) {
138 Dimension minimumSize = getTargetMinimumSize();
139 if (minimumSize != null) {
140 Insets insets = getRealInsets();
141 int minWidth = minimumSize.width - insets.left - insets.right;
142 int minHeight = minimumSize.height - insets.top - insets.bottom;
143 if (minWidth < 0) minWidth = 0;
144 if (minHeight < 0) minHeight = 0;
145 setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)),
146 getX(), getY(), minWidth, minHeight);
147 if (isVisible()) {
148 Rectangle bounds = getShellBounds();
149 int nw = (bounds.width < minWidth) ? minWidth : bounds.width;
150 int nh = (bounds.height < minHeight) ? minHeight : bounds.height;
151 if (nw != bounds.width || nh != bounds.height) {
152 setShellSize(new Rectangle(0, 0, nw, nh));
153 }
154 }
155 } else {
156 boolean isMinSizeSet = isMinSizeSet();
157 XWM.removeSizeHints(this, XUtilConstants.PMinSize);
158 /* Some WMs need remap to redecorate the window */
159 if (isMinSizeSet && isShowing() && XWM.needRemap(this)) {
160 /*
161 * Do the re/mapping at the Xlib level. Since we essentially
162 * work around a WM bug we don't want this hack to be exposed
163 * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
164 */
165 xSetVisible(false);
166 XToolkit.XSync();
167 xSetVisible(true);
168 }
169 }
170 }
171 }
172
173 XFocusProxyWindow createFocusProxy() {
174 return new XFocusProxyWindow(this);
175 }
176
177 protected XAtomList getWMProtocols() {
178 XAtomList protocols = super.getWMProtocols();
179 protocols.add(wm_delete_window);
180 protocols.add(wm_take_focus);
181 return protocols;
182 }
183
184 public Graphics getGraphics() {
185 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
186 return getGraphics(content.surfaceData,
187 compAccessor.getForeground(target),
188 compAccessor.getBackground(target),
189 compAccessor.getFont(target));
190 }
191
192 public void setTitle(String title) {
193 if (log.isLoggable(PlatformLogger.Level.FINE)) {
194 log.fine("Title is " + title);
195 }
196 winAttr.title = title;
197 updateWMName();
198 }
199
200 protected String getWMName() {
201 if (winAttr.title == null || winAttr.title.trim().equals("")) {
202 return " ";
203 } else {
204 return winAttr.title;
205 }
206 }
207
208 void updateWMName() {
209 super.updateWMName();
210 String name = getWMName();
211 XToolkit.awtLock();
212 try {
213 if (name == null || name.trim().equals("")) {
214 name = "Java";
215 }
216 XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME);
217 iconNameAtom.setProperty(getWindow(), name);
218 XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME");
219 netIconNameAtom.setPropertyUTF8(getWindow(), name);
220 } finally {
221 XToolkit.awtUnlock();
222 }
223 }
224
225 // NOTE: This method may be called by privileged threads.
226 // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
227 public void handleIconify() {
228 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED));
229 }
230
231 // NOTE: This method may be called by privileged threads.
232 // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
233 public void handleDeiconify() {
234 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED));
235 }
236
237 public void handleFocusEvent(XEvent xev) {
238 super.handleFocusEvent(xev);
239 XFocusChangeEvent xfe = xev.get_xfocus();
240
241 // If we somehow received focus events forward it instead to proxy
242 // FIXME: Shouldn't we instead check for inferrior?
243 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
244 focusLog.finer("Received focus event on shell: " + xfe);
245 }
246 // focusProxy.xRequestFocus();
247 }
248
249 /***************************************************************************************
250 * I N S E T S C O D E
251 **************************************************************************************/
252
253 protected boolean isInitialReshape() {
254 return false;
255 }
256
257 private static Insets difference(Insets i1, Insets i2) {
258 return new Insets(i1.top-i2.top, i1.left - i2.left, i1.bottom-i2.bottom, i1.right-i2.right);
259 }
260
261 private static boolean isNull(Insets i) {
262 return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0);
263 }
264
265 private static Insets copy(Insets i) {
266 return new Insets(i.top, i.left, i.bottom, i.right);
267 }
268
269 private Insets copyAndScaleDown(Insets i) {
270 return new Insets(scaleDown(i.top), scaleDown(i.left),
271 scaleDown(i.bottom), scaleDown(i.right));
272 }
273
274
275 // insets which we get from WM (e.g from _NET_FRAME_EXTENTS)
276 private Insets wm_set_insets;
277
278 private Insets getWMSetInsets(XAtom changedAtom) {
279 if (isEmbedded()) {
280 return null;
281 }
282
283 if (wm_set_insets != null) {
284 return wm_set_insets;
285 }
286
287 if (changedAtom == null) {
288 wm_set_insets = XWM.getInsetsFromExtents(getWindow());
289 } else {
290 wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom);
291 }
292
293 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
294 insLog.finer("FRAME_EXTENTS: {0}", wm_set_insets);
295 }
296
297 if (wm_set_insets != null) {
298 wm_set_insets = copyAndScaleDown(wm_set_insets);
299 }
300 return wm_set_insets;
301 }
302
303 private void resetWMSetInsets() {
304 if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
305 currentInsets = new Insets(0, 0, 0, 0);
306 wm_set_insets = null;
307 }
308 }
309
310 public void handlePropertyNotify(XEvent xev) {
311 super.handlePropertyNotify(xev);
312
313 XPropertyEvent ev = xev.get_xproperty();
314 if( !insets_corrected && isReparented() &&
315 XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
316 int state = XWM.getWM().getState(this);
317 if ((state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
318 // Stop ignoring ConfigureNotify because no extents will be sent
319 // by WM for initially maximized decorated window.
320 // Re-request window bounds to ensure actual dimensions and
321 // notify the target with the initial size.
322 insets_corrected = true;
323 XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
324 getWindow(), 0, 0);
325 }
326 }
327 if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom()
328 || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom())
329 {
330 if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
331 getWMSetInsets(XAtom.get(ev.get_atom()));
332 } else {
333 if(!isReparented()) {
334 return;
335 }
336 wm_set_insets = null;
337 Insets in = getWMSetInsets(XAtom.get(ev.get_atom()));
338 if (isNull(in)) {
339 return;
340 }
341 if (!isEmbedded() && !isTargetUndecorated()) {
342 lastKnownInsets.put(getClass(), in);
343 }
344 if (!in.equals(dimensions.getInsets())) {
345 if (insets_corrected || isMaximized()) {
346 currentInsets = in;
347 insets_corrected = true;
348 // insets were changed by WM. To handle this situation
349 // re-request window bounds because the current
350 // dimensions may be not actual as well.
351 XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
352 getWindow(), 0, 0);
353 } else {
354 // recalculate dimensions when window is just created
355 // and the initially guessed insets were wrong
356 handleCorrectInsets(in);
357 }
358 } else if (!insets_corrected || !dimensions.isClientSizeSet()) {
359 insets_corrected = true;
360 // initial insets were guessed correctly. Re-request
361 // frame bounds because they may be changed by WM if the
362 // initial window position overlapped desktop's toolbars.
363 // This should initiate the final ConfigureNotify upon which
364 // the target will be notified with the final size.
365 XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
366 getWindow(), 0, 0);
367 }
368 }
369 }
370 }
371
372 long reparent_serial = 0;
373
374 public void handleReparentNotifyEvent(XEvent xev) {
375 XReparentEvent xe = xev.get_xreparent();
376 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
377 insLog.fine(xe.toString());
378 }
379 reparent_serial = xe.get_serial();
380 XToolkit.awtLock();
381 try {
382 long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
383
384 if (isEmbedded()) {
385 setReparented(true);
386 insets_corrected = true;
387 return;
388 }
389 Component t = target;
390 if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) {
391 setReparented(true);
392 insets_corrected = true;
393 reshape(dimensions, SET_SIZE, false);
394 } else if (xe.get_parent() == root) {
395 configure_seen = false;
396 insets_corrected = false;
397
398 /*
399 * We can be repareted to root for two reasons:
400 * . setVisible(false)
401 * . WM exited
402 */
403 if (isVisible()) { /* WM exited */
404 /* Work around 4775545 */
405 XWM.getWM().unshadeKludge(this);
406 insLog.fine("- WM exited");
407 } else {
408 insLog.fine(" - reparent due to hide");
409 }
410 } else { /* reparented to WM frame, figure out our insets */
411 setReparented(true);
412 insets_corrected = false;
413 if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
414 return;
415 }
416
417 // Check if we have insets provided by the WM
418 Insets correctWM = getWMSetInsets(null);
419 if (correctWM != null) {
420 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
421 insLog.finer("wm-provided insets {0}", correctWM);
422 }
423 // If these insets are equal to our current insets - no actions are necessary
424 Insets dimInsets = dimensions.getInsets();
425 if (correctWM.equals(dimInsets)) {
426 insLog.finer("Insets are the same as estimated - no additional reshapes necessary");
427 no_reparent_artifacts = true;
428 insets_corrected = true;
429 applyGuessedInsets();
430 return;
431 }
432 } else {
433 correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent());
434 if (correctWM != null) {
435 correctWM = copyAndScaleDown(correctWM);
436 }
437
438 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
439 if (correctWM != null) {
440 insLog.finer("correctWM {0}", correctWM);
441 } else {
442 insLog.finer("correctWM insets are not available, waiting for configureNotify");
443 }
444 }
445 }
446
447 if (correctWM != null) {
448 handleCorrectInsets(correctWM);
449 }
450 }
451 } finally {
452 XToolkit.awtUnlock();
453 }
454 }
455
456 protected void handleCorrectInsets(Insets correctWM) {
457 XToolkit.awtLock();
458 try {
459 /*
460 * Ok, now see if we need adjust window size because
461 * initial insets were wrong (most likely they were).
462 */
463 Insets correction = difference(correctWM, currentInsets);
464 if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
465 insLog.finest("Corrention {0}", correction);
466 }
467 if (!isNull(correction)) {
468 currentInsets = copy(correctWM);
469 applyGuessedInsets();
470
471 //Fix for 6318109: PIT: Min Size is not honored properly when a
472 //smaller size is specified in setSize(), XToolkit
473 //update minimum size hints
474 updateMinSizeHints();
475 }
476 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
477 insLog.finer("Dimensions before reparent: " + dimensions);
478 }
479
480 dimensions.setInsets(getRealInsets());
481 insets_corrected = true;
482
483 if (isMaximized()) {
484 return;
485 }
486
487 /*
488 * If this window has been sized by a pack() we need
489 * to keep the interior geometry intact. Since pack()
490 * computed width and height with wrong insets, we
491 * must adjust the target dimensions appropriately.
492 */
493 if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) {
494 reshape(dimensions, SET_BOUNDS, false);
495 } else {
496 reshape(dimensions, SET_SIZE, false);
497 }
498 } finally {
499 XToolkit.awtUnlock();
500 }
501 }
502
503 public void handleMoved(WindowDimensions dims) {
504 Point loc = dims.getLocation();
505 AWTAccessor.getComponentAccessor().setLocation(target, loc.x, loc.y);
506 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED));
507 }
508
509
510 protected Insets guessInsets() {
511 if (isEmbedded() || isTargetUndecorated()) {
512 return new Insets(0, 0, 0, 0);
513 } else {
514 if (!isNull(currentInsets)) {
515 /* insets were set on wdata by System Properties */
516 return copy(currentInsets);
517 } else {
518 Insets res = getWMSetInsets(null);
519 if (res == null) {
520 res = XWM.getWM().guessInsets(this);
521 if (res != null) {
522 res = copyAndScaleDown(res);
523 }
524 }
525 return res;
526 }
527 }
528 }
529
530 private void applyGuessedInsets() {
531 Insets guessed = guessInsets();
532 currentInsets = copy(guessed);
533 }
534
535 public void revalidate() {
536 XToolkit.executeOnEventHandlerThread(target, new Runnable() {
537 public void run() {
538 target.invalidate();
539 target.validate();
540 }
541 });
542 }
543
544 Insets getRealInsets() {
545 if (isNull(currentInsets)) {
546 applyGuessedInsets();
547 }
548 return currentInsets;
549 }
550
551 public Insets getInsets() {
552 Insets in = copy(getRealInsets());
553 in.top += getMenuBarHeight();
554 if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
555 insLog.finest("Get insets returns {0}", in);
556 }
557 return in;
558 }
559
560 boolean gravityBug() {
561 return XWM.configureGravityBuggy();
562 }
563
564 // The height of area used to display current active input method
565 int getInputMethodHeight() {
566 return 0;
567 }
568
569 void updateSizeHints(WindowDimensions dims) {
570 Rectangle rec = dims.getClientRect();
571 checkShellRect(rec);
572 updateSizeHints(rec.x, rec.y, rec.width, rec.height);
573 }
574
575 void updateSizeHints() {
576 updateSizeHints(dimensions);
577 }
578
579 // Coordinates are that of the target
580 // Called only on Toolkit thread
581 public void reshape(WindowDimensions newDimensions, int op,
582 boolean userReshape)
583 {
584 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
585 insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape);
586 }
587 if (userReshape) {
588 // We handle only userReshape == true cases. It means that
589 // if the window manager or any other part of the windowing
590 // system sets inappropriate size for this window, we can
591 // do nothing but accept it.
592 Rectangle newBounds = newDimensions.getBounds();
593 Insets insets = newDimensions.getInsets();
594 // Inherit isClientSizeSet from newDimensions
595 if (newDimensions.isClientSizeSet()) {
596 newBounds = new Rectangle(newBounds.x, newBounds.y,
597 newBounds.width - insets.left - insets.right,
598 newBounds.height - insets.top - insets.bottom);
599 }
600 newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet());
601 }
602 XToolkit.awtLock();
603 try {
604 if (!isReparented() || !isVisible()) {
605 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
606 insLog.fine("- not reparented({0}) or not visible({1}), default reshape",
607 Boolean.valueOf(isReparented()), Boolean.valueOf(visible));
608 }
609
610 // Fix for 6323293.
611 // This actually is needed to preserve compatibility with previous releases -
612 // some of licensees are expecting componentMoved event on invisible one while
613 // its location changes.
614 Point oldLocation = getLocation();
615
616 Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target),
617 AWTAccessor.getComponentAccessor().getY(target));
618
619 if (!newLocation.equals(oldLocation)) {
620 handleMoved(newDimensions);
621 }
622
623 dimensions = new WindowDimensions(newDimensions);
624 updateSizeHints(dimensions);
625 Rectangle client = dimensions.getClientRect();
626 checkShellRect(client);
627 setShellBounds(client);
628 if (content != null &&
629 !content.getSize().equals(newDimensions.getSize()))
630 {
631 reconfigureContentWindow(newDimensions);
632 }
633 return;
634 }
635
636 int wm = XWM.getWMID();
637 updateChildrenSizes();
638 applyGuessedInsets();
639
640 Rectangle shellRect = newDimensions.getClientRect();
641
642 if (gravityBug()) {
643 Insets in = newDimensions.getInsets();
644 shellRect.translate(in.left, in.top);
645 }
646
647 if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) {
648 shellRect.setLocation(0, 0);
649 }
650
651 checkShellRectSize(shellRect);
652 if (!isEmbedded()) {
653 checkShellRectPos(shellRect);
654 }
655
656 op = op & ~NO_EMBEDDED_CHECK;
657
658 if (op == SET_LOCATION) {
659 setShellPosition(shellRect);
660 } else if (isResizable()) {
661 if (op == SET_BOUNDS) {
662 setShellBounds(shellRect);
663 } else {
664 setShellSize(shellRect);
665 }
666 } else {
667 XWM.setShellNotResizable(this, newDimensions, shellRect, true);
668 if (op == SET_BOUNDS) {
669 setShellPosition(shellRect);
670 }
671 }
672
673 reconfigureContentWindow(newDimensions);
674 } finally {
675 XToolkit.awtUnlock();
676 }
677 }
678
679 /**
680 * @param x, y, width, heith - dimensions of the window with insets
681 */
682 private void reshape(int x, int y, int width, int height, int operation,
683 boolean userReshape)
684 {
685 Rectangle newRec;
686 boolean setClient = false;
687 WindowDimensions dims = new WindowDimensions(dimensions);
688 switch (operation & (~NO_EMBEDDED_CHECK)) {
689 case SET_LOCATION:
690 // Set location always sets bounds location. However, until the window is mapped we
691 // should use client coordinates
692 dims.setLocation(x, y);
693 break;
694 case SET_SIZE:
695 // Set size sets bounds size. However, until the window is mapped we
696 // should use client coordinates
697 dims.setSize(width, height);
698 break;
699 case SET_CLIENT_SIZE: {
700 // Sets client rect size. Width and height contain insets.
701 Insets in = currentInsets;
702 width -= in.left+in.right;
703 height -= in.top+in.bottom;
704 dims.setClientSize(width, height);
705 break;
706 }
707 case SET_BOUNDS:
708 default:
709 dims.setLocation(x, y);
710 dims.setSize(width, height);
711 break;
712 }
713 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
714 insLog.fine("For the operation {0} new dimensions are {1}",
715 operationToString(operation), dims);
716 }
717
718 reshape(dims, operation, userReshape);
719 }
720
721 // This method gets overriden in XFramePeer & XDialogPeer.
722 abstract boolean isTargetUndecorated();
723
724 /**
725 * @see java.awt.peer.ComponentPeer#setBounds
726 */
727 public void setBounds(int x, int y, int width, int height, int op) {
728 // TODO: Rewrite with WindowDimensions
729 reshape(x, y, width, height, op, true);
730 validateSurface();
731 }
732
733 // Coordinates are that of the shell
734 void reconfigureContentWindow(WindowDimensions dims) {
735 if (content == null) {
736 insLog.fine("WARNING: Content window is null");
737 return;
738 }
739 content.setContentBounds(dims);
740 }
741
742 boolean no_reparent_artifacts = false;
743 public void handleConfigureNotifyEvent(XEvent xev) {
744 if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM && !insets_corrected) {
745 return;
746 }
747 assert (SunToolkit.isAWTLockHeldByCurrentThread());
748 XConfigureEvent xe = xev.get_xconfigure();
749 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
750 insLog.fine("Configure notify {0}", xe);
751 }
752
753 // XXX: should really only consider synthetic events, but
754 if (isReparented()) {
755 configure_seen = true;
756 }
757
758 if (!isMaximized()
759 && (xe.get_serial() == reparent_serial || xe.get_window() != getShell())
760 && !no_reparent_artifacts)
761 {
762 insLog.fine("- reparent artifact, skipping");
763 return;
764 }
765 no_reparent_artifacts = false;
766
767 /**
768 * When there is a WM we receive some CN before being visible and after.
769 * We should skip all CN which are before being visible, because we assume
770 * the gravity is in action while it is not yet.
771 *
772 * When there is no WM we receive CN only _before_ being visible.
773 * We should process these CNs.
774 */
775 if (!isVisible() && XWM.getWMID() != XWM.NO_WM) {
776 insLog.fine(" - not visible, skipping");
777 return;
778 }
779
780 /*
781 * Some window managers configure before we are reparented and
782 * the send event flag is set! ugh... (Enlighetenment for one,
783 * possibly MWM as well). If we haven't been reparented yet
784 * this is just the WM shuffling us into position. Ignore
785 * it!!!! or we wind up in a bogus location.
786 */
787 int runningWM = XWM.getWMID();
788 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
789 insLog.fine("reparented={0}, visible={1}, WM={2}, decorations={3}",
790 isReparented(), isVisible(), runningWM, getDecorations());
791 }
792 if (!isReparented() && isVisible() && runningWM != XWM.NO_WM
793 && !XWM.isNonReparentingWM()
794 && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) {
795 insLog.fine("- visible but not reparented, skipping");
796 return;
797 }
798 //Last chance to correct insets
799 if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) {
800 long parent = XlibUtil.getParentWindow(window);
801 Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null;
802 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
803 if (correctWM != null) {
804 insLog.finer("Configure notify - insets : " + correctWM);
805 } else {
806 insLog.finer("Configure notify - insets are still not available");
807 }
808 }
809 if (correctWM != null) {
810 handleCorrectInsets(copyAndScaleDown(correctWM));
811 } else {
812 //Only one attempt to correct insets is made (to lower risk)
813 //if insets are still not available we simply set the flag
814 insets_corrected = true;
815 }
816 }
817
818 updateChildrenSizes();
819
820 Point newLocation = getNewLocation(xe, currentInsets.left, currentInsets.top);
821 WindowDimensions newDimensions =
822 new WindowDimensions(newLocation,
823 new Dimension(scaleDown(xe.get_width()),
824 scaleDown(xe.get_height())),
825 copy(currentInsets), true);
826
827 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
828 insLog.finer("Insets are {0}, new dimensions {1}",
829 currentInsets, newDimensions);
830 }
831
832 checkIfOnNewScreen(newDimensions.getBounds());
833
834 Point oldLocation = getLocation();
835 dimensions = newDimensions;
836 if (!newLocation.equals(oldLocation)) {
837 handleMoved(newDimensions);
838 }
839 reconfigureContentWindow(newDimensions);
840 updateChildrenSizes();
841
842 repositionSecurityWarning();
843 }
844
845 private void checkShellRectSize(Rectangle shellRect) {
846 shellRect.width = Math.max(MIN_SIZE, shellRect.width);
847 shellRect.height = Math.max(MIN_SIZE, shellRect.height);
848 }
849
850 private void checkShellRectPos(Rectangle shellRect) {
851 int wm = XWM.getWMID();
852 if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) {
853 if (shellRect.x == 0 && shellRect.y == 0) {
854 shellRect.x = shellRect.y = 1;
855 }
856 }
857 }
858
859 private void checkShellRect(Rectangle shellRect) {
860 checkShellRectSize(shellRect);
861 checkShellRectPos(shellRect);
862 }
863
864 public void setShellBounds(Rectangle rec) {
865 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
866 insLog.fine("Setting shell bounds on " + this + " to " + rec);
867 }
868 XToolkit.awtLock();
869 try {
870 updateSizeHints(rec.x, rec.y, rec.width, rec.height);
871 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(),
872 scaleUp(rec.x), scaleUp(rec.y),
873 scaleUp(rec.width), scaleUp(rec.height));
874 }
875 finally {
876 XToolkit.awtUnlock();
877 }
878 }
879 public void setShellSize(Rectangle rec) {
880 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
881 insLog.fine("Setting shell size on " + this + " to " + rec);
882 }
883 XToolkit.awtLock();
884 try {
885 updateSizeHints(rec.x, rec.y, rec.width, rec.height);
886 XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(),
887 scaleUp(rec.width), scaleUp(rec.height));
888 }
889 finally {
890 XToolkit.awtUnlock();
891 }
892 }
893 public void setShellPosition(Rectangle rec) {
894 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
895 insLog.fine("Setting shell position on " + this + " to " + rec);
896 }
897 XToolkit.awtLock();
898 try {
899 updateSizeHints(rec.x, rec.y, rec.width, rec.height);
900 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(),
901 scaleUp(rec.x), scaleUp(rec.y));
902 }
903 finally {
904 XToolkit.awtUnlock();
905 }
906 }
907
908 void initResizability() {
909 setResizable(winAttr.initialResizability);
910 }
911 public void setResizable(boolean resizable) {
912 int fs = winAttr.functions;
913 if (!isResizable() && resizable) {
914 resetWMSetInsets();
915 if (!isEmbedded()) {
916 setReparented(false);
917 }
918 winAttr.isResizable = resizable;
919 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
920 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
921 } else {
922 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
923 }
924 winAttr.functions = fs;
925 XWM.setShellResizable(this);
926 } else if (isResizable() && !resizable) {
927 resetWMSetInsets();
928 if (!isEmbedded()) {
929 setReparented(false);
930 }
931 winAttr.isResizable = resizable;
932 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
933 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
934 } else {
935 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
936 }
937 winAttr.functions = fs;
938 XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false);
939 }
940 }
941
942 Rectangle getShellBounds() {
943 return dimensions.getClientRect();
944 }
945
946 public Rectangle getBounds() {
947 return dimensions.getBounds();
948 }
949
950 public Dimension getSize() {
951 return dimensions.getSize();
952 }
953
954 public int getX() {
955 return dimensions.getLocation().x;
956 }
957
958 public int getY() {
959 return dimensions.getLocation().y;
960 }
961
962 public Point getLocation() {
963 return dimensions.getLocation();
964 }
965
966 public int getAbsoluteX() {
967 // NOTE: returning this peer's location which is shell location
968 return dimensions.getScreenBounds().x;
969 }
970
971 public int getAbsoluteY() {
972 // NOTE: returning this peer's location which is shell location
973 return dimensions.getScreenBounds().y;
974 }
975
976 public int getWidth() {
977 return getSize().width;
978 }
979
980 public int getHeight() {
981 return getSize().height;
982 }
983
984 public final WindowDimensions getDimensions() {
985 return dimensions;
986 }
987
988 public Point getLocationOnScreen() {
989 XToolkit.awtLock();
990 try {
991 if (configure_seen) {
992 return toGlobal(0,0);
993 } else {
994 Point location = target.getLocation();
995 if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
996 insLog.fine("getLocationOnScreen {0} not reparented: {1} ",
997 this, location);
998 }
999 return location;
1000 }
1001 } finally {
1002 XToolkit.awtUnlock();
1003 }
1004 }
1005
1006
1007 /***************************************************************************************
1008 * END OF I N S E T S C O D E
1009 **************************************************************************************/
1010
1011 protected boolean isEventDisabled(XEvent e) {
1012 switch (e.get_type()) {
1013 // Do not generate MOVED/RESIZED events since we generate them by ourselves
1014 case XConstants.ConfigureNotify:
1015 return true;
1016 case XConstants.EnterNotify:
1017 case XConstants.LeaveNotify:
1018 // Disable crossing event on outer borders of Frame so
1019 // we receive only one set of cross notifications(first set is from content window)
1020 return true;
1021 default:
1022 return super.isEventDisabled(e);
1023 }
1024 }
1025
1026 int getDecorations() {
1027 return winAttr.decorations;
1028 }
1029
1030 int getFunctions() {
1031 return winAttr.functions;
1032 }
1033
1034 public void setVisible(boolean vis) {
1035 if (log.isLoggable(PlatformLogger.Level.FINER)) {
1036 log.finer("Setting {0} to visible {1}", this, Boolean.valueOf(vis));
1037 }
1038 if (vis && !isVisible()) {
1039 XWM.setShellDecor(this);
1040 super.setVisible(vis);
1041 if (winAttr.isResizable) {
1042 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
1043 //We need to update frame's minimum size, not to reset it
1044 XWM.removeSizeHints(this, XUtilConstants.PMaxSize);
1045 updateMinimumSize();
1046 }
1047 } else {
1048 super.setVisible(vis);
1049 }
1050 }
1051
1052 protected void suppressWmTakeFocus(boolean doSuppress) {
1053 XAtomList protocols = getWMProtocols();
1054 if (doSuppress) {
1055 protocols.remove(wm_take_focus);
1056 } else {
1057 protocols.add(wm_take_focus);
1058 }
1059 wm_protocols.setAtomListProperty(this, protocols);
1060 }
1061
1062 public void dispose() {
1063 if (content != null) {
1064 content.destroy();
1065 }
1066 focusProxy.destroy();
1067
1068 if (iconWindow != null) {
1069 iconWindow.destroy();
1070 }
1071
1072 super.dispose();
1073 }
1074
1075 public void handleClientMessage(XEvent xev) {
1076 super.handleClientMessage(xev);
1077 XClientMessageEvent cl = xev.get_xclient();
1078 if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) {
1079 if (cl.get_data(0) == wm_delete_window.getAtom()) {
1080 handleQuit();
1081 } else if (cl.get_data(0) == wm_take_focus.getAtom()) {
1082 handleWmTakeFocus(cl);
1083 }
1084 }
1085 }
1086
1087 private void handleWmTakeFocus(XClientMessageEvent cl) {
1088 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1089 focusLog.fine("WM_TAKE_FOCUS on {0}", this);
1090 }
1091
1092 if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
1093 // JDK-8159460
1094 Window focusedWindow = XKeyboardFocusManagerPeer.getInstance()
1095 .getCurrentFocusedWindow();
1096 Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
1097 if (activeWindow != target) {
1098 requestWindowFocus(cl.get_data(1), true);
1099 } else {
1100 WindowEvent we = new WindowEvent(focusedWindow,
1101 WindowEvent.WINDOW_GAINED_FOCUS);
1102 sendEvent(we);
1103 }
1104 } else {
1105 requestWindowFocus(cl.get_data(1), true);
1106 }
1107 }
1108
1109 /**
1110 * Requests focus to this decorated top-level by requesting X input focus
1111 * to the shell window.
1112 */
1113 protected void requestXFocus(long time, boolean timeProvided) {
1114 // We have proxied focus mechanism - instead of shell the focus is held
1115 // by "proxy" - invisible mapped window. When we want to set X input focus to
1116 // toplevel set it on proxy instead.
1117 if (focusProxy == null) {
1118 if (focusLog.isLoggable(PlatformLogger.Level.WARNING)) {
1119 focusLog.warning("Focus proxy is null for " + this);
1120 }
1121 } else {
1122 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1123 focusLog.fine("Requesting focus to proxy: " + focusProxy);
1124 }
1125 if (timeProvided) {
1126 focusProxy.xRequestFocus(time);
1127 } else {
1128 focusProxy.xRequestFocus();
1129 }
1130 }
1131 }
1132
1133 XFocusProxyWindow getFocusProxy() {
1134 return focusProxy;
1135 }
1136
1137 public void handleQuit() {
1138 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING));
1139 }
1140
1141 final void dumpMe() {
1142 System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height);
1143 }
1144
1145 final void dumpTarget() {
1146 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
1147 int getWidth = compAccessor.getWidth(target);
1148 int getHeight = compAccessor.getHeight(target);
1149 int getTargetX = compAccessor.getX(target);
1150 int getTargetY = compAccessor.getY(target);
1151 System.err.println(">>> Target: " + getTargetX + ", " + getTargetY + ", " + getWidth + ", " + getHeight);
1152 }
1153
1154 final void dumpShell() {
1155 dumpWindow("Shell", getShell());
1156 }
1157 final void dumpContent() {
1158 dumpWindow("Content", getContentWindow());
1159 }
1160 final void dumpParent() {
1161 long parent = XlibUtil.getParentWindow(getShell());
1162 if (parent != 0)
1163 {
1164 dumpWindow("Parent", parent);
1165 }
1166 else
1167 {
1168 System.err.println(">>> NO PARENT");
1169 }
1170 }
1171
1172 final void dumpWindow(String id, long window) {
1173 XWindowAttributes pattr = new XWindowAttributes();
1174 try {
1175 XToolkit.awtLock();
1176 try {
1177 int status =
1178 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1179 window, pattr.pData);
1180 }
1181 finally {
1182 XToolkit.awtUnlock();
1183 }
1184 System.err.println(">>>> " + id + ": " + pattr.get_x()
1185 + ", " + pattr.get_y() + ", " + pattr.get_width()
1186 + ", " + pattr.get_height());
1187 } finally {
1188 pattr.dispose();
1189 }
1190 }
1191
1192 final void dumpAll() {
1193 dumpTarget();
1194 dumpMe();
1195 dumpParent();
1196 dumpShell();
1197 dumpContent();
1198 }
1199
1200 boolean isMaximized() {
1201 return false;
1202 }
1203
1204 @Override
1205 boolean isOverrideRedirect() {
1206 return Window.Type.POPUP.equals(getWindowType());
1207 }
1208
1209 public boolean requestWindowFocus(long time, boolean timeProvided) {
1210 focusLog.fine("Request for decorated window focus");
1211 // If this is Frame or Dialog we can't assure focus request success - but we still can try
1212 // If this is Window and its owner Frame is active we can be sure request succedded.
1213 Window focusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();
1214 Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
1215
1216 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
1217 focusLog.finer("Current window is: active={0}, focused={1}",
1218 Boolean.valueOf(target == activeWindow),
1219 Boolean.valueOf(target == focusedWindow));
1220 }
1221
1222 XWindowPeer toFocus = this;
1223 while (toFocus.nextTransientFor != null) {
1224 toFocus = toFocus.nextTransientFor;
1225 }
1226 if (toFocus == null || !toFocus.focusAllowedFor()) {
1227 // This might change when WM will have property to determine focus policy.
1228 // Right now, because policy is unknown we can't be sure we succedded
1229 return false;
1230 }
1231 if (this == toFocus) {
1232 if (isWMStateNetHidden()) {
1233 focusLog.fine("The window is unmapped, so rejecting the request");
1234 return false;
1235 }
1236 if (target == activeWindow && target != focusedWindow) {
1237 // Happens when an owned window is currently focused
1238 focusLog.fine("Focus is on child window - transferring it back to the owner");
1239 handleWindowFocusInSync(-1);
1240 return true;
1241 }
1242 Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow();
1243 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
1244 focusLog.finest("Real native focused window: " + realNativeFocusedWindow +
1245 "\nKFM's focused window: " + focusedWindow);
1246 }
1247
1248 // A workaround for Metacity. See 6522725, 6613426, 7147075.
1249 if (target == realNativeFocusedWindow && XWM.getWMID() == XWM.METACITY_WM) {
1250 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1251 focusLog.fine("The window is already natively focused.");
1252 }
1253 return true;
1254 }
1255 }
1256 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1257 focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus));
1258 }
1259
1260 if (timeProvided) {
1261 toFocus.requestXFocus(time);
1262 } else {
1263 toFocus.requestXFocus();
1264 }
1265 return (this == toFocus);
1266 }
1267
1268 XWindowPeer actualFocusedWindow = null;
1269 void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
1270 synchronized(getStateLock()) {
1271 this.actualFocusedWindow = actualFocusedWindow;
1272 }
1273 }
1274
1275 boolean requestWindowFocus(XWindowPeer actualFocusedWindow,
1276 long time, boolean timeProvided)
1277 {
1278 setActualFocusedWindow(actualFocusedWindow);
1279 return requestWindowFocus(time, timeProvided);
1280 }
1281 public void handleWindowFocusIn(long serial) {
1282 if (null == actualFocusedWindow) {
1283 super.handleWindowFocusIn(serial);
1284 } else {
1285 /*
1286 * Fix for 6314575.
1287 * If this is a result of clicking on one of the Frame's component
1288 * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing
1289 * it or not should be made after the appropriate Java mouse event (if any)
1290 * is handled by the component where 'actualFocusedWindow' value may be reset.
1291 *
1292 * The fix is based on the empiric fact consisting in that the component
1293 * receives native mouse event nearly at the same time the Frame receives
1294 * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but
1295 * definetely before the Frame gets FocusIn event (when this method is called).
1296 */
1297 postEvent(new InvocationEvent(target, new Runnable() {
1298 public void run() {
1299 XWindowPeer fw = null;
1300 synchronized (getStateLock()) {
1301 fw = actualFocusedWindow;
1302 actualFocusedWindow = null;
1303 if (null == fw || !fw.isVisible() || !fw.isFocusableWindow()) {
1304 fw = XDecoratedPeer.this;
1305 }
1306 }
1307 fw.handleWindowFocusIn_Dispatch();
1308 }
1309 }));
1310 }
1311 }
1312
1313 public void handleWindowFocusOut(Window oppositeWindow, long serial) {
1314 Window actualFocusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();
1315
1316 // If the actual focused window is not this decorated window then retain it.
1317 if (actualFocusedWindow != null && actualFocusedWindow != target) {
1318 Window owner = XWindowPeer.getDecoratedOwner(actualFocusedWindow);
1319
1320 if (owner != null && owner == target) {
1321 setActualFocusedWindow(AWTAccessor.getComponentAccessor().getPeer(actualFocusedWindow));
1322 }
1323 }
1324 super.handleWindowFocusOut(oppositeWindow, serial);
1325 }
1326 }
--- EOF ---