blob: 4657f75c49b06f9a1d52f3539cbbc05d835275ab [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package sun.awt.X11;
26
27import java.awt.AWTEvent;
28import java.awt.AWTException;
29import java.awt.BufferCapabilities;
30import java.awt.Color;
31import java.awt.Component;
32import java.awt.Container;
33import java.awt.Cursor;
34import java.awt.DefaultKeyboardFocusManager;
35import java.awt.Dimension;
36import java.awt.Event;
37import java.awt.Font;
38import java.awt.FontMetrics;
39import java.awt.Graphics;
40import java.awt.Image;
41import java.awt.Insets;
42import java.awt.KeyboardFocusManager;
43import java.awt.MenuBar;
44import java.awt.Point;
45import java.awt.Rectangle;
46import java.awt.SystemColor;
47import java.awt.Toolkit;
48import java.awt.Window;
49import java.awt.dnd.DropTarget;
50import java.awt.dnd.peer.DropTargetPeer;
51import java.awt.event.FocusEvent;
52import java.awt.event.InputEvent;
53import java.awt.event.InputMethodEvent;
54import java.awt.event.KeyEvent;
55import java.awt.event.MouseEvent;
56import java.awt.event.MouseWheelEvent;
57import java.awt.event.PaintEvent;
58import java.awt.event.WindowEvent;
59import java.awt.event.InvocationEvent;
60import java.awt.image.ImageObserver;
61import java.awt.image.ImageProducer;
62import java.awt.image.VolatileImage;
63import java.awt.peer.CanvasPeer;
64import java.awt.peer.ComponentPeer;
65import java.awt.peer.ContainerPeer;
66import java.awt.peer.LightweightPeer;
67import java.awt.peer.PanelPeer;
68import java.awt.peer.WindowPeer;
69import java.lang.reflect.*;
70import java.security.*;
71import java.util.Collection;
72import java.util.HashSet;
73import java.util.Set;
74import java.util.Vector;
75import java.util.logging.*;
76import sun.awt.*;
77import sun.awt.event.IgnorePaintEvent;
78import sun.awt.image.SunVolatileImage;
79import sun.awt.image.ToolkitImage;
80import sun.java2d.pipe.Region;
81
82public class XComponentPeer extends XWindow implements ComponentPeer, DropTargetPeer, XConstants {
83 /* FIX ME: these constants copied from java.awt.KeyboardFocusManager */
84 static final int SNFH_FAILURE = 0;
85 static final int SNFH_SUCCESS_HANDLED = 1;
86 static final int SNFH_SUCCESS_PROCEED = 2;
87
88 private static final Logger log = Logger.getLogger("sun.awt.X11.XComponentPeer");
89 private static final Logger buffersLog = Logger.getLogger("sun.awt.X11.XComponentPeer.multibuffer");
90 private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XComponentPeer");
91 private static final Logger fontLog = Logger.getLogger("sun.awt.X11.font.XComponentPeer");
92 private static final Logger enableLog = Logger.getLogger("sun.awt.X11.enable.XComponentPeer");
93 private static final Logger shapeLog = Logger.getLogger("sun.awt.X11.shape.XComponentPeer");
94
95 boolean paintPending = false;
96 boolean isLayouting = false;
97 boolean enabled;
98
99 // Actually used only by XDecoratedPeer
100 protected int boundsOperation;
101
102 Color foreground;
103 Color background;
104
105 // Colors calculated as on Motif using MotifColorUtilties.
106 // If you use these, call updateMotifColors() in the peer's Constructor and
107 // setBackground(). Examples are XCheckboxPeer and XButtonPeer.
108 Color darkShadow;
109 Color lightShadow;
110 Color selectColor;
111
112 Font font;
113 private long backBuffer = 0;
114 private VolatileImage xBackBuffer = null;
115
116 static Color[] systemColors;
117
118 XComponentPeer() {
119 }
120
121 XComponentPeer (XCreateWindowParams params) {
122 super(params);
123 }
124
125 XComponentPeer(Component target, long parentWindow, Rectangle bounds) {
126 super(target, parentWindow, bounds);
127 }
128
129 /**
130 * Standard peer constructor, with corresponding Component
131 */
132 XComponentPeer(Component target) {
133 super(target);
134 }
135
136
137 void preInit(XCreateWindowParams params) {
138 super.preInit(params);
139 boundsOperation = DEFAULT_OPERATION;
140 }
141 void postInit(XCreateWindowParams params) {
142 super.postInit(params);
143 Color c;
144 Font f;
145 Cursor cursor;
146
147 pSetCursor(target.getCursor());
148
149 foreground = target.getForeground();
150 background = target.getBackground();
151 font = target.getFont();
152
153 if (isInitialReshape()) {
154 Rectangle r = target.getBounds();
155 reshape(r.x, r.y, r.width, r.height);
156 }
157
158 enabled = target.isEnabled();
159
160 // If any of our heavyweight ancestors are disable, we should be too
161 // See 6176875 for more information
162 Component comp = target;
163 while( !(comp == null || comp instanceof Window) ) {
164 comp = comp.getParent();
165 if( comp != null && !comp.isEnabled() && !comp.isLightweight() ){
166 setEnabled(false);
167 break;
168 }
169 }
170 enableLog.log(Level.FINE, "Initial enable state: {0}", new Object[] {Boolean.valueOf(enabled)});
171
172 if (target.isVisible()) {
173 show();
174 }
175 }
176
177 protected boolean isInitialReshape() {
178 return true;
179 }
180
181 public void reparent(ContainerPeer newNativeParent) {
182 XComponentPeer newPeer = (XComponentPeer)newNativeParent;
183 XToolkit.awtLock();
184 try {
185 XlibWrapper.XReparentWindow(XToolkit.getDisplay(), getWindow(), newPeer.getContentWindow(), x, y);
186 parentWindow = newPeer;
187 } finally {
188 XToolkit.awtUnlock();
189 }
190 }
191 public boolean isReparentSupported() {
192 return System.getProperty("sun.awt.X11.XComponentPeer.reparentNotSupported", "false").equals("false");
193 }
194
195 public boolean isObscured() {
196 Container container = (target instanceof Container) ?
197 (Container)target : target.getParent();
198
199 if (container == null) {
200 return true;
201 }
202
203 Container parent;
204 while ((parent = container.getParent()) != null) {
205 container = parent;
206 }
207
208 if (container instanceof Window) {
209 XWindowPeer wpeer = (XWindowPeer)(container.getPeer());
210 if (wpeer != null) {
211 return (wpeer.winAttr.visibilityState !=
212 wpeer.winAttr.AWT_UNOBSCURED);
213 }
214 }
215 return true;
216 }
217
218 public boolean canDetermineObscurity() {
219 return true;
220 }
221
222 static XComponentPeer getNativeContainer(Component comp) {
223 if (comp == null) {
224 return null;
225 }
226
227 synchronized(comp.getTreeLock()) {
228 while (comp != null && (ComponentAccessor.getPeer(comp) instanceof LightweightPeer)) {
229 comp = ComponentAccessor.getParent_NoClientCode(comp);
230 }
231
232 if (comp != null) {
233 ComponentPeer peer = ComponentAccessor.getPeer(comp);
234 if (peer != null && peer instanceof XComponentPeer) {
235 return (XComponentPeer)peer;
236 }
237 }
238 }
239
240 return null;
241 }
242
243 /*************************************************
244 * FOCUS STUFF
245 *************************************************/
246
247 /**
248 * Keeps the track of focused state of the _NATIVE_ window
249 */
250 boolean bHasFocus = false;
251
252 /**
253 * Descendants should use this method to determine whether or not native window
254 * has focus.
255 */
256 final public boolean hasFocus() {
257 return bHasFocus;
258 }
259
260 /**
261 * Called when component receives focus
262 */
263 public void focusGained(FocusEvent e) {
264 focusLog.log(Level.FINE, "{0}", new Object[] {e});
265 bHasFocus = true;
266 }
267
268 /**
269 * Called when component loses focus
270 */
271 public void focusLost(FocusEvent e) {
272 focusLog.log(Level.FINE, "{0}", new Object[] {e});
273 bHasFocus = false;
274 }
275
276 public boolean isFocusable() {
277 /* should be implemented by other sub-classes */
278 return false;
279 }
280
281 private static Class seClass;
282 private static Constructor seCtor;
283
284 final static AWTEvent wrapInSequenced(AWTEvent event) {
285 try {
286 if (seClass == null) {
287 seClass = Class.forName("java.awt.SequencedEvent");
288 }
289
290 if (seCtor == null) {
291 seCtor = (Constructor) AccessController.doPrivileged(new PrivilegedExceptionAction() {
292 public Object run() throws Exception {
293 Constructor ctor = seClass.getConstructor(new Class[] { AWTEvent.class });
294 ctor.setAccessible(true);
295 return ctor;
296 }
297 });
298 }
299
300 return (AWTEvent) seCtor.newInstance(new Object[] { event });
301 }
302 catch (ClassNotFoundException e) {
303 throw new NoClassDefFoundError("java.awt.SequencedEvent.");
304 }
305 catch (PrivilegedActionException ex) {
306 throw new NoClassDefFoundError("java.awt.SequencedEvent.");
307 }
308 catch (InstantiationException e) {
309 assert false;
310 }
311 catch (IllegalAccessException e) {
312 assert false;
313 }
314 catch (InvocationTargetException e) {
315 assert false;
316 }
317
318 return null;
319 }
320
321 /**
322 * Returns whether or not this component should be given focus on mouse click.
323 * Default implementation return whether or not this peer is "focusable"
324 * Descendants might want to override it to extend/restrict conditions at which this
325 * component should be focused by click (see MCanvasPeer and MPanelPeer)
326 */
327 protected boolean shouldFocusOnClick() {
328 return isFocusable();
329 }
330
331 /**
332 * Checks whether or not this component would be focused by native system if it would be allowed to do so.
333 * Currently it checks that it displayable, visible, enabled and focusable.
334 */
335 static boolean canBeFocusedByClick(Component component) {
336 if (component == null) {
337 return false;
338 } else {
339 return component.isDisplayable() && component.isVisible() && component.isEnabled() && component.isFocusable();
340 }
341 }
342
343 static Window getContainingWindow(Component comp) {
344 while (comp != null && !(comp instanceof Window)) {
345 comp = comp.getParent();
346 }
347
348 return (Window)comp;
349 }
350
351 static Method processSynchronousLightweightTransferMethod;
352 static boolean processSynchronousLightweightTransfer(Component heavyweight, Component descendant,
353 boolean temporary, boolean focusedWindowChangeAllowed,
354 long time)
355 {
356 try {
357 if (processSynchronousLightweightTransferMethod == null) {
358 processSynchronousLightweightTransferMethod =
359 (Method)AccessController.doPrivileged(
360 new PrivilegedExceptionAction() {
361 public Object run() throws IllegalAccessException, NoSuchMethodException
362 {
363 Method m = KeyboardFocusManager.class.
364 getDeclaredMethod("processSynchronousLightweightTransfer",
365 new Class[] {Component.class, Component.class,
366 Boolean.TYPE, Boolean.TYPE,
367 Long.TYPE});
368 m.setAccessible(true);
369 return m;
370 }
371 });
372 }
373 Object[] params = new Object[] {
374 heavyweight,
375 descendant,
376 Boolean.valueOf(temporary),
377 Boolean.valueOf(focusedWindowChangeAllowed),
378 Long.valueOf(time)
379 };
380 return ((Boolean)processSynchronousLightweightTransferMethod.invoke(null, params)).booleanValue();
381 } catch (PrivilegedActionException pae) {
382 pae.printStackTrace();
383 return false;
384 } catch (IllegalAccessException iae) {
385 iae.printStackTrace();
386 return false;
387 } catch (IllegalArgumentException iaee) {
388 iaee.printStackTrace();
389 return false;
390 } catch (InvocationTargetException ite) {
391 ite.printStackTrace();
392 return false;
393 }
394 }
395
396 static Method requestFocusWithCause;
397
398 static void callRequestFocus(Component target, CausedFocusEvent.Cause cause) {
399 if (requestFocusWithCause == null) {
400 requestFocusWithCause = SunToolkit.getMethod(Component.class, "requestFocus", new Class[] {CausedFocusEvent.Cause.class});
401 }
402 if (requestFocusWithCause != null) {
403 try {
404 requestFocusWithCause.invoke(target, new Object[] {cause});
405 } catch (Exception e) {
406 e.printStackTrace();
407 }
408 }
409 }
410
411 final public boolean requestFocus(Component lightweightChild, boolean temporary,
412 boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause)
413 {
414 if (processSynchronousLightweightTransfer(target, lightweightChild, temporary,
415 focusedWindowChangeAllowed, time))
416 {
417 return true;
418 }
419
420 int result = XKeyboardFocusManagerPeer
421 .shouldNativelyFocusHeavyweight(target, lightweightChild,
422 temporary, focusedWindowChangeAllowed, time, cause);
423
424 switch (result) {
425 case SNFH_FAILURE:
426 return false;
427 case SNFH_SUCCESS_PROCEED:
428 // Currently we just generate focus events like we deal with lightweight instead of calling
429 // XSetInputFocus on native window
430 if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Proceeding with request to " + lightweightChild + " in " + target);
431 /**
432 * The problems with requests in non-focused window arise because shouldNativelyFocusHeavyweight
433 * checks that native window is focused while appropriate WINDOW_GAINED_FOCUS has not yet
434 * been processed - it is in EventQueue. Thus, SNFH allows native request and stores request record
435 * in requests list - and it breaks our requests sequence as first record on WGF should be the last focus
436 * owner which had focus before WLF. So, we should not add request record for such requests
437 * but store this component in mostRecent - and return true as before for compatibility.
438 */
439 Window parentWindow = getContainingWindow(target);
440 if (parentWindow != null) {
441 // and check that it is focused
442 if (!parentWindow.isFocused()) {
443 XWindowPeer wpeer = (XWindowPeer)parentWindow.getPeer();
444 /*
445 * Fix for 6314575.
446 * Shouldn't restore focus on 'actualFocusedWindow'
447 * when a component inside a Frame is requesting it.
448 */
449 wpeer.setActualFocusedWindow(null);
450
451 boolean res = wpeer.requestWindowFocus();
452 if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Requested window focus: " + res);
453 // If parent window can be made focused and has been made focused(synchronously)
454 // then we can proceed with children, otherwise we retreat.
455 if (!(res && parentWindow.isFocused())) {
456 focusLog.finer("Waiting for asynchronous processing of window focus request");
457 KeyboardFocusManagerPeerImpl.removeLastFocusRequest(target);
458 return false;
459 }
460 }
461 } else {
462 if (focusLog.isLoggable(Level.FINER)) focusLog.finer("WARNING: Parent window is null");
463 return false;
464 }
465
466 // NOTE: We simulate heavyweight behavior of Motif - component receives focus right
467 // after request, not after event. Normally, we should better listen for event
468 // by listeners.
469 return XKeyboardFocusManagerPeer.simulateMotifRequestFocus(lightweightChild, target, temporary,
470 focusedWindowChangeAllowed, time, cause);
471 // Motif compatibility code
472 case SNFH_SUCCESS_HANDLED:
473 // Either lightweight or excessive request - all events are generated.
474 return true;
475 }
476 return false;
477 }
478
479 void handleJavaFocusEvent(AWTEvent e) {
480 if (focusLog.isLoggable(Level.FINER)) focusLog.finer(e.toString());
481 if (e.getID() == FocusEvent.FOCUS_GAINED) {
482 focusGained((FocusEvent)e);
483 } else {
484 focusLost((FocusEvent)e);
485 }
486 }
487
488 void handleJavaWindowFocusEvent(AWTEvent e) {
489 }
490
491 /*************************************************
492 * END OF FOCUS STUFF
493 *************************************************/
494
495
496
497 public void setVisible(boolean b) {
498 xSetVisible(b);
499 }
500
501 public void show() {
502 setVisible(true);
503 }
504
505 public void hide() {
506 setVisible(false);
507 }
508
509
510 /**
511 * @see java.awt.peer.ComponentPeer
512 */
513 public void setEnabled(boolean value) {
514 enableLog.log(Level.FINE, "{0}ing {1}", new Object[] {(value?"Enabl":"Disabl"), this});
515 boolean repaintNeeded = (enabled != value);
516 enabled = value;
517 if (target instanceof Container) {
518 Component list[] = ((Container)target).getComponents();
519 for (int i = 0; i < list.length; ++i) {
520 boolean childEnabled = list[i].isEnabled();
521 ComponentPeer p = list[i].getPeer();
522 if ( p != null ) {
523 p.setEnabled(value && childEnabled);
524 }
525 }
526 }
527 if (repaintNeeded) {
528 repaint();
529 }
530 }
531
532 //
533 // public so aw/Window can call it
534 //
535 public boolean isEnabled() {
536 return enabled;
537 }
538
539
540
541 public void enable() {
542 setEnabled(true);
543 }
544
545 public void disable() {
546 setEnabled(false);
547 }
548
549 public void paint(Graphics g) {
550 }
551 public void repaint(long tm, int x, int y, int width, int height) {
552 repaint();
553 }
554
555
556 public Graphics getGraphics() {
557 return getGraphics(surfaceData, getPeerForeground(), getPeerBackground(), getPeerFont());
558 }
559
560
561
562 public void print(Graphics g) {
563 // clear rect here to emulate X clears rect before Expose
564 g.setColor(target.getBackground());
565 g.fillRect(0, 0, target.getWidth(), target.getHeight());
566 g.setColor(target.getForeground());
567 // paint peer
568 paint(g);
569 // allow target to change the picture
570 target.print(g);
571 }
572
573 public void setBounds(int x, int y, int width, int height, int op) {
574 this.x = x;
575 this.y = y;
576 this.width = width;
577 this.height = height;
578 xSetBounds(x,y,width,height);
579 validateSurface();
580 layout();
581 }
582
583 public void reshape(int x, int y, int width, int height) {
584 setBounds(x, y, width, height, SET_BOUNDS);
585 }
586
587 public void coalescePaintEvent(PaintEvent e) {
588 Rectangle r = e.getUpdateRect();
589 if (!(e instanceof IgnorePaintEvent)) {
590 paintArea.add(r, e.getID());
591 }
592 if (true) {
593 switch(e.getID()) {
594 case PaintEvent.UPDATE:
595 log.finer("XCP coalescePaintEvent : UPDATE : add : x = " +
596 r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
597 return;
598 case PaintEvent.PAINT:
599 log.finer("XCP coalescePaintEvent : PAINT : add : x = " +
600 r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
601 return;
602 }
603 }
604 }
605
606 XWindowPeer getParentTopLevel() {
607 Container parent = (target instanceof Container) ? ((Container)target) : (ComponentAccessor.getParent_NoClientCode(target));
608 // Search for parent window
609 while (parent != null && !(parent instanceof Window)) {
610 parent = ComponentAccessor.getParent_NoClientCode(parent);
611 }
612 if (parent != null) {
613 return (XWindowPeer)ComponentAccessor.getPeer(parent);
614 } else {
615 return null;
616 }
617 }
618
619 /* This method is intended to be over-ridden by peers to perform user interaction */
620 void handleJavaMouseEvent(MouseEvent e) {
621 switch (e.getID()) {
622 case MouseEvent.MOUSE_PRESSED:
623 if (target == e.getSource() && shouldFocusOnClick()
624 && !target.isFocusOwner() && canBeFocusedByClick(target))
625 {
626 XWindowPeer parentXWindow = getParentTopLevel();
627 Window parentWindow = ((Window)parentXWindow.getTarget());
628 // Simple windows are non-focusable in X terms but focusable in Java terms.
629 // As X-non-focusable they don't receive any focus events - we should generate them
630 // by ourselfves.
631// if (parentXWindow.isFocusableWindow() /*&& parentXWindow.isSimpleWindow()*/ &&
632// !(getCurrentNativeFocusedWindow() == parentWindow))
633// {
634// setCurrentNativeFocusedWindow(parentWindow);
635// WindowEvent wfg = new WindowEvent(parentWindow, WindowEvent.WINDOW_GAINED_FOCUS);
636// parentWindow.dispatchEvent(wfg);
637// }
638 callRequestFocus(target, CausedFocusEvent.Cause.MOUSE_EVENT);
639 }
640 break;
641 }
642 }
643
644 /* This method is intended to be over-ridden by peers to perform user interaction */
645 void handleJavaKeyEvent(KeyEvent e) {
646 }
647
648 /* This method is intended to be over-ridden by peers to perform user interaction */
649 void handleJavaMouseWheelEvent(MouseWheelEvent e) {
650 }
651
652
653 /* This method is intended to be over-ridden by peers to perform user interaction */
654 void handleJavaInputMethodEvent(InputMethodEvent e) {
655 }
656
657 void handleF10JavaKeyEvent(KeyEvent e) {
658 if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_F10) {
659 XWindowPeer winPeer = this.getToplevelXWindow();
660 if (winPeer instanceof XFramePeer) {
661 XMenuBarPeer mPeer = ((XFramePeer)winPeer).getMenubarPeer();
662 if (mPeer != null) {
663 mPeer.handleF10KeyPress(e);
664 }
665 }
666 }
667 }
668
669 public void handleEvent(java.awt.AWTEvent e) {
670 if ((e instanceof InputEvent) && !((InputEvent)e).isConsumed() && target.isEnabled()) {
671 if (e instanceof MouseEvent) {
672 if (e instanceof MouseWheelEvent) {
673 handleJavaMouseWheelEvent((MouseWheelEvent) e);
674 }
675 else
676 handleJavaMouseEvent((MouseEvent) e);
677 }
678 else if (e instanceof KeyEvent) {
679 handleF10JavaKeyEvent((KeyEvent)e);
680 handleJavaKeyEvent((KeyEvent)e);
681 }
682 }
683 else if (e instanceof KeyEvent && !((InputEvent)e).isConsumed()) {
684 // even if target is disabled.
685 handleF10JavaKeyEvent((KeyEvent)e);
686 }
687 else if (e instanceof InputMethodEvent) {
688 handleJavaInputMethodEvent((InputMethodEvent) e);
689 }
690
691 int id = e.getID();
692
693 switch(id) {
694 case PaintEvent.PAINT:
695 // Got native painting
696 paintPending = false;
697 // Fallthrough to next statement
698 case PaintEvent.UPDATE:
699 // Skip all painting while layouting and all UPDATEs
700 // while waiting for native paint
701 if (!isLayouting && !paintPending) {
702 paintArea.paint(target,false);
703 }
704 return;
705 case FocusEvent.FOCUS_LOST:
706 case FocusEvent.FOCUS_GAINED:
707 handleJavaFocusEvent(e);
708 break;
709 case WindowEvent.WINDOW_LOST_FOCUS:
710 case WindowEvent.WINDOW_GAINED_FOCUS:
711 handleJavaWindowFocusEvent(e);
712 break;
713 default:
714 break;
715 }
716
717 }
718
719 public void handleButtonPressRelease(XEvent xev) {
720 /*
721 * Fix for 6385277.
722 * We request focus on simple Window by click in order
723 * to make it behave like Frame/Dialog in this case and also to unify
724 * the behaviour with what we have on MS Windows.
725 * handleJavaMouseEvent() would be more suitable place to do this
726 * but we want Swing to have this functionality also.
727 */
728 if (xev.get_type() == ButtonPress) {
729 final XWindowPeer parentXWindow = getParentTopLevel();
730 Window parentWindow = (Window)parentXWindow.getTarget();
731 if (parentXWindow.isFocusableWindow() && parentXWindow.isSimpleWindow() &&
732 XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() != parentWindow)
733 {
734 postEvent(new InvocationEvent(parentWindow, new Runnable() {
735 public void run() {
736 // Request focus on the EDT of 'parentWindow' because
737 // XDecoratedPeer.requestWindowFocus() calls client code.
738 parentXWindow.requestXFocus();
739 }
740 }));
741 }
742 }
743 super.handleButtonPressRelease(xev);
744 }
745
746 public Dimension getMinimumSize() {
747 return target.getSize();
748 }
749
750 public Dimension getPreferredSize() {
751 return getMinimumSize();
752 }
753
754 public void layout() {}
755
756 public java.awt.Toolkit getToolkit() {
757 return Toolkit.getDefaultToolkit();
758 }
759
760 void updateMotifColors(Color bg) {
761 int red = bg.getRed();
762 int green = bg.getGreen();
763 int blue = bg.getBlue();
764
765 darkShadow = new Color(MotifColorUtilities.calculateBottomShadowFromBackground(red,green,blue));
766 lightShadow = new Color(MotifColorUtilities.calculateTopShadowFromBackground(red,green,blue));
767 selectColor= new Color(MotifColorUtilities.calculateSelectFromBackground(red,green,blue));
768 }
769
770 /*
771 * Draw a 3D rectangle using the Motif colors.
772 * "Normal" rectangles have shadows on the bottom.
773 * "Depressed" rectangles (such as pressed buttons) have shadows on the top,
774 * in which case true should be passed for topShadow.
775 */
776 public void drawMotif3DRect(Graphics g,
777 int x, int y, int width, int height,
778 boolean topShadow) {
779 g.setColor(topShadow ? darkShadow : lightShadow);
780 g.drawLine(x, y, x+width, y); // top
781 g.drawLine(x, y+height, x, y); // left
782
783 g.setColor(topShadow ? lightShadow : darkShadow );
784 g.drawLine(x+1, y+height, x+width, y+height); // bottom
785 g.drawLine(x+width, y+height, x+width, y+1); // right
786 }
787
788 public void setBackground(Color c) {
789 if (log.isLoggable(Level.FINE)) log.fine("Set background to " + c);
790 synchronized (getStateLock()) {
791 background = c;
792 }
793 super.setBackground(c);
794 repaint();
795 }
796
797 public void setForeground(Color c) {
798 if (log.isLoggable(Level.FINE)) log.fine("Set foreground to " + c);
799 synchronized (getStateLock()) {
800 foreground = c;
801 }
802 repaint();
803 }
804
805 /**
806 * Gets the font metrics for the specified font.
807 * @param font the font for which font metrics is to be
808 * obtained
809 * @return the font metrics for <code>font</code>
810 * @see #getFont
811 * @see #getPeer
812 * @see java.awt.peer.ComponentPeer#getFontMetrics(Font)
813 * @see Toolkit#getFontMetrics(Font)
814 * @since JDK1.0
815 */
816 public FontMetrics getFontMetrics(Font font) {
817 if (fontLog.isLoggable(Level.FINE)) fontLog.fine("Getting font metrics for " + font);
818 return sun.font.FontDesignMetrics.getMetrics(font);
819 }
820
821 public void setFont(Font f) {
822 synchronized (getStateLock()) {
823 if (f == null) {
824 f = defaultFont;
825 }
826 font = f;
827 }
828 // as it stands currently we dont need to do layout or repaint since
829 // layout is done in the Component upon setFont.
830 //layout();
831 // target.repaint();
832 //repaint()?
833 }
834
835 public Font getFont() {
836 return font;
837 }
838
839 public void updateCursorImmediately() {
840 XGlobalCursorManager.getCursorManager().updateCursorImmediately();
841 }
842
843 public void pSetCursor(Cursor cursor) {
844 XToolkit.awtLock();
845 try {
846 long xcursor = XGlobalCursorManager.getCursor(cursor);
847
848 XSetWindowAttributes xwa = new XSetWindowAttributes();
849 xwa.set_cursor(xcursor);
850
851 long valuemask = XlibWrapper.CWCursor;
852
853 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),getWindow(),valuemask,xwa.pData);
854 XlibWrapper.XFlush(XToolkit.getDisplay());
855 xwa.dispose();
856 } finally {
857 XToolkit.awtUnlock();
858 }
859 }
860
861 public Image createImage(ImageProducer producer) {
862 return new ToolkitImage(producer);
863 }
864
865 public Image createImage(int width, int height) {
866 return graphicsConfig.createAcceleratedImage(target, width, height);
867 }
868
869 public VolatileImage createVolatileImage(int width, int height) {
870 return new SunVolatileImage(target, width, height);
871 }
872
873 public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
874 return getToolkit().prepareImage(img, w, h, o);
875 }
876
877 public int checkImage(Image img, int w, int h, ImageObserver o) {
878 return getToolkit().checkImage(img, w, h, o);
879 }
880
881 public Dimension preferredSize() {
882 return getPreferredSize();
883 }
884
885 public Dimension minimumSize() {
886 return getMinimumSize();
887 }
888
889 public Insets getInsets() {
890 return new Insets(0, 0, 0, 0);
891 }
892
893 public void beginValidate() {
894 }
895
896 public void endValidate() {
897 }
898
899
900 /**
901 * DEPRECATED: Replaced by getInsets().
902 */
903
904 public Insets insets() {
905 return getInsets();
906 }
907
908 // Returns true if we are inside begin/endLayout and
909 // are waiting for native painting
910 public boolean isPaintPending() {
911 return paintPending && isLayouting;
912 }
913
914 public boolean handlesWheelScrolling() {
915 return false;
916 }
917
918 public void beginLayout() {
919 // Skip all painting till endLayout
920 isLayouting = true;
921
922 }
923
924 public void endLayout() {
925 if (!paintPending && !paintArea.isEmpty()
926 && !ComponentAccessor.getIgnoreRepaint(target))
927 {
928 // if not waiting for native painting repaint damaged area
929 postEvent(new PaintEvent(target, PaintEvent.PAINT,
930 new Rectangle()));
931 }
932 isLayouting = false;
933 }
934
935 public Color getWinBackground() {
936 return getPeerBackground();
937 }
938
939 static int[] getRGBvals(Color c) {
940
941 int rgbvals[] = new int[3];
942
943 rgbvals[0] = c.getRed();
944 rgbvals[1] = c.getGreen();
945 rgbvals[2] = c.getBlue();
946
947 return rgbvals;
948 }
949
950 static final int BACKGROUND_COLOR = 0;
951 static final int HIGHLIGHT_COLOR = 1;
952 static final int SHADOW_COLOR = 2;
953 static final int FOREGROUND_COLOR = 3;
954
955 public Color[] getGUIcolors() {
956 Color c[] = new Color[4];
957 float backb, highb, shadowb, hue, saturation;
958 c[BACKGROUND_COLOR] = getWinBackground();
959 if (c[BACKGROUND_COLOR] == null) {
960 c[BACKGROUND_COLOR] = super.getWinBackground();
961 }
962 if (c[BACKGROUND_COLOR] == null) {
963 c[BACKGROUND_COLOR] = Color.lightGray;
964 }
965
966 int[] rgb = getRGBvals(c[BACKGROUND_COLOR]);
967
968 float[] hsb = Color.RGBtoHSB(rgb[0],rgb[1],rgb[2],null);
969
970 hue = hsb[0];
971 saturation = hsb[1];
972 backb = hsb[2];
973
974
975/* Calculate Highlight Brightness */
976
977 highb = backb + 0.2f;
978 shadowb = backb - 0.4f;
979 if ((highb > 1.0) ) {
980 if ((1.0 - backb) < 0.05) {
981 highb = shadowb + 0.25f;
982 } else {
983 highb = 1.0f;
984 }
985 } else {
986 if (shadowb < 0.0) {
987 if ((backb - 0.0) < 0.25) {
988 highb = backb + 0.75f;
989 shadowb = highb - 0.2f;
990 } else {
991 shadowb = 0.0f;
992 }
993 }
994 }
995 c[HIGHLIGHT_COLOR] = Color.getHSBColor(hue,saturation,highb);
996 c[SHADOW_COLOR] = Color.getHSBColor(hue,saturation,shadowb);
997
998
999/*
1000 c[SHADOW_COLOR] = c[BACKGROUND_COLOR].darker();
1001 int r2 = c[SHADOW_COLOR].getRed();
1002 int g2 = c[SHADOW_COLOR].getGreen();
1003 int b2 = c[SHADOW_COLOR].getBlue();
1004*/
1005
1006 c[FOREGROUND_COLOR] = getPeerForeground();
1007 if (c[FOREGROUND_COLOR] == null) {
1008 c[FOREGROUND_COLOR] = Color.black;
1009 }
1010/*
1011 if ((c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR]))
1012 && (c[BACKGROUND_COLOR].equals(c[SHADOW_COLOR]))) {
1013 c[SHADOW_COLOR] = new Color(c[BACKGROUND_COLOR].getRed() + 75,
1014 c[BACKGROUND_COLOR].getGreen() + 75,
1015 c[BACKGROUND_COLOR].getBlue() + 75);
1016 c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR].brighter();
1017 } else if (c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR])) {
1018 c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR];
1019 c[SHADOW_COLOR] = c[SHADOW_COLOR].darker();
1020 }
1021*/
1022 if (! isEnabled()) {
1023 c[BACKGROUND_COLOR] = c[BACKGROUND_COLOR].darker();
1024 // Reduce the contrast
1025 // Calculate the NTSC gray (NB: REC709 L* might be better!)
1026 // for foreground and background; then multiply the foreground
1027 // by the average lightness
1028
1029
1030 Color tc = c[BACKGROUND_COLOR];
1031 int bg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11;
1032
1033 tc = c[FOREGROUND_COLOR];
1034 int fg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11;
1035
1036 float ave = (float) ((fg + bg) / 51000.0);
1037 // 255 * 100 * 2
1038
1039 Color newForeground = new Color((int) (tc.getRed() * ave),
1040 (int) (tc.getGreen() * ave),
1041 (int) (tc.getBlue() * ave));
1042
1043 if (newForeground.equals(c[FOREGROUND_COLOR])) {
1044 // This probably means the foreground color is black or white
1045 newForeground = new Color(ave, ave, ave);
1046 }
1047 c[FOREGROUND_COLOR] = newForeground;
1048
1049 }
1050
1051
1052 return c;
1053 }
1054
1055 /**
1056 * Returns an array of Colors similar to getGUIcolors(), but using the
1057 * System colors. This is useful if pieces of a Component (such as
1058 * the integrated scrollbars of a List) should retain the System color
1059 * instead of the background color set by Component.setBackground().
1060 */
1061 static Color[] getSystemColors() {
1062 if (systemColors == null) {
1063 systemColors = new Color[4];
1064 systemColors[BACKGROUND_COLOR] = SystemColor.window;
1065 systemColors[HIGHLIGHT_COLOR] = SystemColor.controlLtHighlight;
1066 systemColors[SHADOW_COLOR] = SystemColor.controlShadow;
1067 systemColors[FOREGROUND_COLOR] = SystemColor.windowText;
1068 }
1069 return systemColors;
1070 }
1071
1072 /**
1073 * Draw a 3D oval.
1074 */
1075 public void draw3DOval(Graphics g, Color colors[],
1076 int x, int y, int w, int h, boolean raised)
1077 {
1078 Color c = g.getColor();
1079 g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]);
1080 g.drawArc(x, y, w, h, 45, 180);
1081 g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]);
1082 g.drawArc(x, y, w, h, 225, 180);
1083 g.setColor(c);
1084 }
1085
1086 public void draw3DRect(Graphics g, Color colors[],
1087 int x, int y, int width, int height, boolean raised)
1088 {
1089 Color c = g.getColor();
1090 g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]);
1091 g.drawLine(x, y, x, y + height);
1092 g.drawLine(x + 1, y, x + width - 1, y);
1093 g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]);
1094 g.drawLine(x + 1, y + height, x + width, y + height);
1095 g.drawLine(x + width, y, x + width, y + height - 1);
1096 g.setColor(c);
1097 }
1098
1099 /*
1100 * drawXXX() methods are used to print the native components by
1101 * rendering the Motif look ourselves.
1102 * ToDo(aim): needs to query native motif for more accurate color
1103 * information.
1104 */
1105 void draw3DOval(Graphics g, Color bg,
1106 int x, int y, int w, int h, boolean raised)
1107 {
1108 Color c = g.getColor();
1109 Color shadow = bg.darker();
1110 Color highlight = bg.brighter();
1111
1112 g.setColor(raised ? highlight : shadow);
1113 g.drawArc(x, y, w, h, 45, 180);
1114 g.setColor(raised ? shadow : highlight);
1115 g.drawArc(x, y, w, h, 225, 180);
1116 g.setColor(c);
1117 }
1118
1119 void draw3DRect(Graphics g, Color bg,
1120 int x, int y, int width, int height,
1121 boolean raised) {
1122 Color c = g.getColor();
1123 Color shadow = bg.darker();
1124 Color highlight = bg.brighter();
1125
1126 g.setColor(raised ? highlight : shadow);
1127 g.drawLine(x, y, x, y + height);
1128 g.drawLine(x + 1, y, x + width - 1, y);
1129 g.setColor(raised ? shadow : highlight);
1130 g.drawLine(x + 1, y + height, x + width, y + height);
1131 g.drawLine(x + width, y, x + width, y + height - 1);
1132 g.setColor(c);
1133 }
1134
1135 void drawScrollbar(Graphics g, Color bg, int thickness, int length,
1136 int min, int max, int val, int vis, boolean horizontal) {
1137 Color c = g.getColor();
1138 double f = (double)(length - 2*(thickness-1)) / Math.max(1, ((max - min) + vis));
1139 int v1 = thickness + (int)(f * (val - min));
1140 int v2 = (int)(f * vis);
1141 int w2 = thickness-4;
1142 int tpts_x[] = new int[3];
1143 int tpts_y[] = new int[3];
1144
1145 if (length < 3*w2 ) {
1146 v1 = v2 = 0;
1147 if (length < 2*w2 + 2) {
1148 w2 = (length-2)/2;
1149 }
1150 } else if (v2 < 7) {
1151 // enforce a minimum handle size
1152 v1 = Math.max(0, v1 - ((7 - v2)>>1));
1153 v2 = 7;
1154 }
1155
1156 int ctr = thickness/2;
1157 int sbmin = ctr - w2/2;
1158 int sbmax = ctr + w2/2;
1159
1160 // paint the background slightly darker
1161 {
1162 Color d = new Color((int) (bg.getRed() * 0.85),
1163 (int) (bg.getGreen() * 0.85),
1164 (int) (bg.getBlue() * 0.85));
1165
1166 g.setColor(d);
1167 if (horizontal) {
1168 g.fillRect(0, 0, length, thickness);
1169 } else {
1170 g.fillRect(0, 0, thickness, length);
1171 }
1172 }
1173
1174 // paint the thumb and arrows in the normal background color
1175 g.setColor(bg);
1176 if (v1 > 0) {
1177 if (horizontal) {
1178 g.fillRect(v1, 3, v2, thickness-3);
1179 } else {
1180 g.fillRect(3, v1, thickness-3, v2);
1181 }
1182 }
1183
1184 tpts_x[0] = ctr; tpts_y[0] = 2;
1185 tpts_x[1] = sbmin; tpts_y[1] = w2;
1186 tpts_x[2] = sbmax; tpts_y[2] = w2;
1187 if (horizontal) {
1188 g.fillPolygon(tpts_y, tpts_x, 3);
1189 } else {
1190 g.fillPolygon(tpts_x, tpts_y, 3);
1191 }
1192
1193 tpts_y[0] = length-2;
1194 tpts_y[1] = length-w2;
1195 tpts_y[2] = length-w2;
1196 if (horizontal) {
1197 g.fillPolygon(tpts_y, tpts_x, 3);
1198 } else {
1199 g.fillPolygon(tpts_x, tpts_y, 3);
1200 }
1201
1202 Color highlight = bg.brighter();
1203
1204 // // // // draw the "highlighted" edges
1205 g.setColor(highlight);
1206
1207 // outline & arrows
1208 if (horizontal) {
1209 g.drawLine(1, thickness, length - 1, thickness);
1210 g.drawLine(length - 1, 1, length - 1, thickness);
1211
1212 // arrows
1213 g.drawLine(1, ctr, w2, sbmin);
1214 g.drawLine(length - w2, sbmin, length - w2, sbmax);
1215 g.drawLine(length - w2, sbmin, length - 2, ctr);
1216
1217 } else {
1218 g.drawLine(thickness, 1, thickness, length - 1);
1219 g.drawLine(1, length - 1, thickness, length - 1);
1220
1221 // arrows
1222 g.drawLine(ctr, 1, sbmin, w2);
1223 g.drawLine(sbmin, length - w2, sbmax, length - w2);
1224 g.drawLine(sbmin, length - w2, ctr, length - 2);
1225 }
1226
1227 // thumb
1228 if (v1 > 0) {
1229 if (horizontal) {
1230 g.drawLine(v1, 2, v1 + v2, 2);
1231 g.drawLine(v1, 2, v1, thickness-3);
1232 } else {
1233 g.drawLine(2, v1, 2, v1 + v2);
1234 g.drawLine(2, v1, thickness-3, v1);
1235 }
1236 }
1237
1238 Color shadow = bg.darker();
1239
1240 // // // // draw the "shadowed" edges
1241 g.setColor(shadow);
1242
1243 // outline && arrows
1244 if (horizontal) {
1245 g.drawLine(0, 0, 0, thickness);
1246 g.drawLine(0, 0, length - 1, 0);
1247
1248 // arrows
1249 g.drawLine(w2, sbmin, w2, sbmax);
1250 g.drawLine(w2, sbmax, 1, ctr);
1251 g.drawLine(length-2, ctr, length-w2, sbmax);
1252
1253 } else {
1254 g.drawLine(0, 0, thickness, 0);
1255 g.drawLine(0, 0, 0, length - 1);
1256
1257 // arrows
1258 g.drawLine(sbmin, w2, sbmax, w2);
1259 g.drawLine(sbmax, w2, ctr, 1);
1260 g.drawLine(ctr, length-2, sbmax, length-w2);
1261 }
1262
1263 // thumb
1264 if (v1 > 0) {
1265 if (horizontal) {
1266 g.drawLine(v1 + v2, 2, v1 + v2, thickness-2);
1267 g.drawLine(v1, thickness-2, v1 + v2, thickness-2);
1268 } else {
1269 g.drawLine(2, v1 + v2, thickness-2, v1 + v2);
1270 g.drawLine(thickness-2, v1, thickness-2, v1 + v2);
1271 }
1272 }
1273 g.setColor(c);
1274 }
1275
1276 /**
1277 * The following multibuffering-related methods delegate to our
1278 * associated GraphicsConfig (X11 or GLX) to handle the appropriate
1279 * native windowing system specific actions.
1280 */
1281
1282 public void createBuffers(int numBuffers, BufferCapabilities caps)
1283 throws AWTException
1284 {
1285 if (buffersLog.isLoggable(Level.FINE)) {
1286 buffersLog.fine("createBuffers(" + numBuffers + ", " + caps + ")");
1287 }
1288 backBuffer = graphicsConfig.createBackBuffer(this, numBuffers, caps);
1289 xBackBuffer = graphicsConfig.createBackBufferImage(target,
1290 backBuffer);
1291 }
1292
1293 public void flip(BufferCapabilities.FlipContents flipAction) {
1294 if (buffersLog.isLoggable(Level.FINE)) {
1295 buffersLog.fine("flip(" + flipAction + ")");
1296 }
1297 if (backBuffer == 0) {
1298 throw new IllegalStateException("Buffers have not been created");
1299 }
1300 graphicsConfig.flip(this, target, xBackBuffer, flipAction);
1301 }
1302
1303 public Image getBackBuffer() {
1304 if (buffersLog.isLoggable(Level.FINE)) {
1305 buffersLog.fine("getBackBuffer()");
1306 }
1307 if (backBuffer == 0) {
1308 throw new IllegalStateException("Buffers have not been created");
1309 }
1310 return xBackBuffer;
1311 }
1312
1313 public void destroyBuffers() {
1314 if (buffersLog.isLoggable(Level.FINE)) {
1315 buffersLog.fine("destroyBuffers()");
1316 }
1317 graphicsConfig.destroyBackBuffer(backBuffer);
1318 backBuffer = 0;
1319 xBackBuffer = null;
1320 }
1321
1322 // End of multi-buffering
1323
1324 public void notifyTextComponentChange(boolean add){
1325 Container parent = ComponentAccessor.getParent_NoClientCode(target);
1326 while(!(parent == null ||
1327 parent instanceof java.awt.Frame ||
1328 parent instanceof java.awt.Dialog)) {
1329 parent = ComponentAccessor.getParent_NoClientCode(parent);
1330 }
1331
1332/* FIX ME - FIX ME need to implement InputMethods
1333 if (parent instanceof java.awt.Frame ||
1334 parent instanceof java.awt.Dialog) {
1335 if (add)
1336 ((MInputMethodControl)parent.getPeer()).addTextComponent((MComponentPeer)this);
1337 else
1338 ((MInputMethodControl)parent.getPeer()).removeTextComponent((MComponentPeer)this);
1339 }
1340*/
1341 }
1342
1343 /**
1344 * Returns true if this event is disabled and shouldn't be processed by window
1345 * Currently if target component is disabled the following event will be disabled on window:
1346 * ButtonPress, ButtonRelease, KeyPress, KeyRelease, EnterNotify, LeaveNotify, MotionNotify
1347 */
1348 protected boolean isEventDisabled(XEvent e) {
1349 enableLog.log(Level.FINEST, "Component is {1}, checking for disabled event {0}", new Object[] {e, (isEnabled()?"enabled":"disable")});
1350 if (!isEnabled()) {
1351 switch (e.get_type()) {
1352 case ButtonPress:
1353 case ButtonRelease:
1354 case KeyPress:
1355 case KeyRelease:
1356 case EnterNotify:
1357 case LeaveNotify:
1358 case MotionNotify:
1359 enableLog.log(Level.FINER, "Event {0} is disable", new Object[] {e});
1360 return true;
1361 }
1362 }
1363 switch(e.get_type()) {
1364 case MapNotify:
1365 case UnmapNotify:
1366 return true;
1367 }
1368 return super.isEventDisabled(e);
1369 }
1370
1371 Color getPeerBackground() {
1372 return background;
1373 }
1374
1375 Color getPeerForeground() {
1376 return foreground;
1377 }
1378
1379 Font getPeerFont() {
1380 return font;
1381 }
1382
1383 Dimension getPeerSize() {
1384 return new Dimension(width,height);
1385 }
1386
1387 public void setBoundsOperation(int operation) {
1388 synchronized(getStateLock()) {
1389 if (boundsOperation == DEFAULT_OPERATION) {
1390 boundsOperation = operation;
1391 } else if (operation == RESET_OPERATION) {
1392 boundsOperation = DEFAULT_OPERATION;
1393 }
1394 }
1395 }
1396
1397 static String operationToString(int operation) {
1398 switch (operation) {
1399 case SET_LOCATION:
1400 return "SET_LOCATION";
1401 case SET_SIZE:
1402 return "SET_SIZE";
1403 case SET_CLIENT_SIZE:
1404 return "SET_CLIENT_SIZE";
1405 default:
1406 case SET_BOUNDS:
1407 return "SET_BOUNDS";
1408 }
1409 }
1410
1411 public void restack() {
1412 synchronized(target.getTreeLock()) {
1413 // Build the list of X windows in the window corresponding to this container
1414 // This list is already in correct Java stacking order
1415 Container cont = (Container)target;
1416 Vector order = new Vector(cont.getComponentCount());
1417 HashSet set = new HashSet();
1418
1419 addTree(order, set, cont);
1420
1421 XToolkit.awtLock();
1422 try {
1423 // Get the current list of X window in X window. Some of the windows
1424 // might be only native
1425 XQueryTree qt = new XQueryTree(getContentWindow());
1426 try {
1427 if (qt.execute() != 0) {
1428 if (qt.get_nchildren() != 0) {
1429 long pchildren = qt.get_children();
1430 int j = 0; // index to insert
1431 for (int i = 0; i < qt.get_nchildren(); i++) {
1432 Long w = Long.valueOf(Native.getLong(pchildren, i));
1433 if (!set.contains(w)) {
1434 set.add(w);
1435 order.add(j++, w);
1436 }
1437 }
1438 }
1439 }
1440
1441 if (order.size() != 0) {
1442 // Create native array of the windows
1443 long windows = Native.allocateLongArray(order.size());
1444 Native.putLong(windows, order);
1445
1446 // Restack native window according to the new order
1447 XlibWrapper.XRestackWindows(XToolkit.getDisplay(), windows, order.size());
1448
1449 XlibWrapper.unsafe.freeMemory(windows);
1450 }
1451 } finally {
1452 qt.dispose();
1453 }
1454 } finally {
1455 XToolkit.awtUnlock();
1456 }
1457 }
1458 }
1459
1460 public boolean isRestackSupported() {
1461 return true;
1462 }
1463
1464 private void addTree(Collection order, Set set, Container cont) {
1465 for (int i = 0; i < cont.getComponentCount(); i++) {
1466 Component comp = cont.getComponent(i);
1467 ComponentPeer peer = comp.getPeer();
1468 if (peer instanceof XComponentPeer) {
1469 Long window = Long.valueOf(((XComponentPeer)peer).getWindow());
1470 if (!set.contains(window)) {
1471 set.add(window);
1472 order.add(window);
1473 }
1474 } else if (comp instanceof Container) {
1475 // It is lightweight container, it might contain heavyweight components attached to this
1476 // peer
1477 addTree(order, set, (Container)comp);
1478 }
1479 }
1480 }
1481
1482 /****** DropTargetPeer implementation ********************/
1483
1484 public void addDropTarget(DropTarget dt) {
1485 Component comp = target;
1486 while(!(comp == null || comp instanceof Window)) {
1487 comp = comp.getParent();
1488 }
1489
1490 if (comp instanceof Window) {
1491 XWindowPeer wpeer = (XWindowPeer)(comp.getPeer());
1492 if (wpeer != null) {
1493 wpeer.addDropTarget();
1494 }
1495 }
1496 }
1497
1498 public void removeDropTarget(DropTarget dt) {
1499 Component comp = target;
1500 while(!(comp == null || comp instanceof Window)) {
1501 comp = comp.getParent();
1502 }
1503
1504 if (comp instanceof Window) {
1505 XWindowPeer wpeer = (XWindowPeer)(comp.getPeer());
1506 if (wpeer != null) {
1507 wpeer.removeDropTarget();
1508 }
1509 }
1510 }
1511
1512 /**
1513 * Applies the shape to the X-window.
1514 * @since 1.7
1515 */
1516 public void applyShape(Region shape) {
1517 if (XlibUtil.isShapingSupported()) {
1518 if (shapeLog.isLoggable(Level.FINER)) {
1519 shapeLog.finer(
1520 "*** INFO: Setting shape: PEER: " + this
1521 + "; WINDOW: " + getWindow()
1522 + "; TARGET: " + target
1523 + "; SHAPE: " + shape);
1524 }
1525 XToolkit.awtLock();
1526 try {
1527 XlibWrapper.SetRectangularShape(
1528 XToolkit.getDisplay(),
1529 getWindow(),
1530 shape.getLoX(), shape.getLoY(),
1531 shape.getHiX(), shape.getHiY(),
1532 (shape.isRectangular() ? null : shape)
1533 );
1534 } finally {
1535 XToolkit.awtUnlock();
1536 }
1537 } else {
1538 if (shapeLog.isLoggable(Level.FINER)) {
1539 shapeLog.finer("*** WARNING: Shaping is NOT supported!");
1540 }
1541 }
1542 }
1543}