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