xref: /titanic_41/usr/src/cmd/krb5/kadmin/gui/visualrt/sunsoft/jws/visual/rt/awt/VJPanel.java (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * ident	"%Z%%M%	%I%	%E% SMI"
24  *
25  * Copyright (c) 2000 by Sun Microsystems, Inc.
26  * All rights reserved.
27  */
28 
29 /*
30  *        Copyright (C) 1996  Active Software, Inc.
31  *                  All rights reserved.
32  *
33  * @(#) VJPanel.java 1.31 - last change made 08/25/97
34  */
35 
36 package sunsoft.jws.visual.rt.awt;
37 
38 import sunsoft.jws.visual.rt.base.*;
39 import java.awt.*;
40 import java.util.Hashtable;
41 
42 public class VJPanel extends Panel {
43     // Relief constants
44     public static final int RELIEF_FLAT   = Util.RELIEF_FLAT;
45     public static final int RELIEF_RAISED = Util.RELIEF_RAISED;
46     public static final int RELIEF_SUNKEN = Util.RELIEF_SUNKEN;
47     public static final int RELIEF_RIDGE  = Util.RELIEF_RIDGE;
48     public static final int RELIEF_GROOVE = Util.RELIEF_GROOVE;
49     public static final int WIN95_RAISED = Util.WIN95_RAISED;
50     public static final int WIN95_SUNKEN = Util.WIN95_SUNKEN;
51     /* BEGIN JSTYLED */
52     public static final int WIN95_FIELD_BORDER = Util.WIN95_FIELD_BORDER;
53     public static final int WIN95_WINDOW_BORDER = Util.WIN95_WINDOW_BORDER;
54     /* END JSTYLED */
55     public static final int BLACK_BORDER = Util.BLACK_BORDER;
56 
57     // Alignment constants
58     public static final int LEFT = Label.LEFT;
59     public static final int CENTER = Label.CENTER;
60     public static final int RIGHT = Label.RIGHT;
61 
62     // Drawing constants
63     private static final int labelpadx = 10;
64     private static final int labelipadx = 4;
65     private static final int labelpadtop = 2;
66 
67     // Maker event
68     private static final int MARKER_EVENT = 83250;
69 
70     // Multiply factor for darker color
71     private static double FACTOR = 0.85;
72 
73     // request focus workaround for Windows
74     static boolean isMouseDown;
75 
76     // click count adjustment
77     private static final int CLICK_TIMEOUT = 400;
78     private static final int CLICK_DISTANCE = 2;
79     private static int clickCount = 1;
80     private static long clickTime = 0;
81     private static long clickWhen = -1;
82     private static int clickX, clickY;
83 
84     // Relief
85     private int relief;
86 
87     // Border width
88     int borderWidth;
89 
90     // Label for the upper border of the panel
91     private String borderLabel;
92 
93     // Alignment for the borderLabel
94     private int labelAlignment;
95 
96     // Insets between the border decoration and the child components
97     private Insets borderInsets;
98 
99     //
100     // Event forwarding to groups.
101     //
102     // The MARKER_EVENT stuff is necessary because AWT is broken.  For
103     // example, say a key is pressed in a textfield.  All of the parents
104     // of the textfield get a chance at the event before the textfield's
105     // peer.  If any of the parents returns true from handleEvent, then
106     // the peer never sees the event.
107     //
108     // VJPanel overrides postEvent instead of handleEvent.  handleEvent
109     // would have been overridden if it we possible to return true from
110     // handleEvent and not screw up AWT.  Since this is not the case, it
111     // becomes necessary to override postEvent instead of handleEvent,
112     // to ensure that all AWT event handling has taken place everywhere
113     // before the event is forwarded to the shadow (and from there to
114     // the group).
115     //
116     // The panel cannot return true from postEvent or else no one
117     // will ever see the event.  Therefore, postEvent returns false,
118     // and the MARKER_EVENT stuff ensures that the event doesn't get
119     // delivered twice.
120     //
121     //
122 
123     /**
124      * markEvent - Marks events that should be forwarded to the shadow.
125      *
126      * Returns true if the event has been marked, false otherwise.
127      */
markEvent(Event evt, Component comp)128     public static boolean markEvent(Event evt, Component comp) {
129         //
130         // Check for events that are already marked
131         //
132         Event e = evt.evt;
133         while (e != null) {
134             if (e.id == MARKER_EVENT)
135                 return false;
136             e = e.evt;
137         }
138 
139         //
140         // Figure out the mgr to send the mesage to, and also figure
141         // out the target for the message.
142         //
143         Object messageTarget = null;
144         AttributeManager mgr = null;
145         Hashtable shadowTable = DesignerAccess.getShadowTable();
146 
147         if (evt.target != null) {
148             mgr = (AttributeManager)shadowTable.get(evt.target);
149             messageTarget = mgr;
150         }
151         if (mgr == null) {
152             mgr = (AttributeManager)shadowTable.get(comp);
153             messageTarget = evt.target;
154         }
155 
156         //
157         // If we found a mgr, then mark the event and return true.
158         // Otherwise, return false.
159         //
160         if (mgr != null) {
161             Message msg = new Message(messageTarget, /* NOI18N */"AWT",
162 				      evt, true);
163 
164             e = evt;
165             while (e.evt != null)
166                 e = e.evt;
167             e.evt = new Event(mgr, MARKER_EVENT, msg);
168 
169             e.evt.x = e.x;
170             e.evt.y = e.y;
171 
172             return true;
173         } else {
174             return false;
175         }
176     }
177 
178     /**
179      * forwardEvent - Forwards marked events to the shadow
180      */
forwardEvent(Event evt, Component comp)181     public static void forwardEvent(Event evt, Component comp) {
182         // Find the marker event and remove it
183         Event p = evt;
184         Event e = evt;
185         while (e.evt != null) {
186             p = e;
187             e = e.evt;
188         }
189         p.evt = null;
190 
191         // Make sure we have a marked event
192         if (e.id != MARKER_EVENT) {
193             throw new Error(
194 			    /* JSTYLED */
195 			    Global.fmtMsg("sunsoft.jws.visual.rt.awt.VJPanel.UnmarkedEvent", "forwardEvent"));
196         }
197 
198         // Need to untranslate the (x,y) for the event.
199         evt.x = e.x;
200         evt.y = e.y;
201 
202         Component target = null;
203         if (evt.target instanceof Component)
204             target = (Component)evt.target;
205 
206         while (target != null && target != comp) {
207             Container parent = target.getParent();
208             if (parent == null) {
209                 // We didn't hit comp on the way up the tree,
210                 // so don't translate
211                 evt.x = e.x;
212                 evt.y = e.y;
213                 break;
214             }
215 
216             translateEvent(evt, target, parent, true);
217             target = parent;
218         }
219 
220         // Fix the click count
221         fixClickCount(evt);
222 
223         // Send the message
224         AttributeManager mgr = (AttributeManager)e.target;
225         mgr.postMessage((Message)e.arg);
226     }
227 
228     // Windows workaround:  The location of most
229     // components gets totally
230     // screwed up on Windows.  The solution is to
231     // use the location in the
232     // GBConstraints instead.  This version of
233     // postEvent translates events
234     // according to the GBConstraints location variable.
postEvent(Event e)235     public boolean postEvent(Event e) {
236         // Fix the click count
237         fixClickCount(e);
238 
239         if (e.id == Event.MOUSE_DOWN)
240             VJPanel.isMouseDown = true;
241         else if (e.id == Event.MOUSE_UP)
242             VJPanel.isMouseDown = false;
243 
244         boolean marked = markEvent(e, this);
245         boolean handled = doPostEvent(e);
246         if (marked)
247             VJPanel.forwardEvent(e, this);
248 
249         return handled;
250     }
251 
doPostEvent(Event e)252     private boolean doPostEvent(Event e) {
253         boolean handled = false;
254 
255         if (Global.isWindows()) {
256             if (handleEvent(e)) {
257                 handled = true;
258             } else {
259                 Container parent = getParent();
260                 if (parent != null) {
261                     translateEvent(e, this, parent);
262 
263                     if (parent.postEvent(e)) {
264                         handled = true;
265                     }
266                 }
267             }
268         } else {
269             handled = super.postEvent(e);
270         }
271 
272         return handled;
273     }
274 
275 
276     //
277     // This is a workaround for two different problems.
278     //
279     // The first problem is that on Motif, the
280     // click count sometimes does
281     // not work.  Sometimes is does sort of work,
282     // but you have to double-
283     // click REALLY fast.  This workaround adjusts
284     // the clickCount according
285     // to a reasonable click timeout.
286     //
287     // The second problem is that on Windows you can get double-clicks
288     // even if the second click is at a different x,y
289     // location than the first
290     // click.  This workaround makes sure that
291     // if the clicks are far apart,
292     // then it isn't a double click.
293     //
294 
fixClickCount(Event evt)295     static void fixClickCount(Event evt) {
296         if (evt.id != Event.MOUSE_DOWN || evt.when == clickWhen)
297             return;
298 
299         if (Global.isMotif()) {
300             long curtime = System.currentTimeMillis();
301             if (evt.when == 0)
302                 evt.when = curtime;
303 
304             int d = Math.abs(clickX - evt.x) + Math.abs(clickY - evt.y);
305 
306             if ((curtime - clickTime) < CLICK_TIMEOUT
307 		&& (d <= CLICK_DISTANCE)) {
308                 clickCount++;
309                 evt.clickCount = clickCount;
310             } else {
311                 clickCount = 1;
312             }
313 
314             if (evt.clickCount == 1)
315                 evt.clickCount = clickCount;
316             clickTime = curtime;
317             clickWhen = evt.when;
318             clickX = evt.x;
319             clickY = evt.y;
320         } else if (Global.isWindows()) {
321             long curtime = System.currentTimeMillis();
322             if (evt.when == 0)
323                 evt.when = curtime;
324 
325             int d = Math.abs(clickX - evt.x) + Math.abs(clickY - evt.y);
326 
327             if (d > CLICK_DISTANCE) {
328                 evt.clickCount = 1;
329             }
330 
331             clickWhen = evt.when;
332             clickX = evt.x;
333             clickY = evt.y;
334         }
335     }
336 
translateEvent(Event e, Component child, Container parent)337     public void translateEvent(Event e, Component child,
338 			       Container parent) {
339         translateEvent(e, child, parent, false);
340     }
341 
translateEvent(Event e, Component child, Container parent, boolean negate)342     private static void translateEvent(Event e,
343 				       Component child, Container parent,
344 				       boolean negate) {
345 
346         LayoutManager parentMgr = parent.getLayout();
347 
348         // Translate the event using the location
349         // from the GridBagLayout,
350         // if available.  This solves the location problem if you use
351         // GridBagLayout for all your containers.
352         if (parentMgr instanceof GBLayout) {
353             GBLayout gb = (GBLayout)parentMgr;
354             GBConstraints c = gb.getConstraints(child);
355 
356             Point p = null;
357             if (c != null)
358                 p = c.location;
359             if (p == null)
360                 p = child.location();
361 
362             if (negate)
363                 e.translate(-p.x, -p.y);
364             else
365                 e.translate(p.x, p.y);
366         } else {
367             Point p = child.location();
368             if (negate)
369                 e.translate(-p.x, -p.y);
370             else
371                 e.translate(p.x, p.y);
372         }
373     }
374 
375     //
376     // Constructor
377     //
378 
VJPanel()379     public VJPanel() {
380         relief = Util.RELIEF_FLAT;
381         borderLabel = null;
382         borderWidth = 2;
383         borderInsets = new Insets(5, 5, 5, 5);
384         labelAlignment = LEFT;
385     }
386 
VJPanel(int relief)387     public VJPanel(int relief) {
388         this();
389         setRelief(relief);
390     }
391 
VJPanel(int relief, String label)392     public VJPanel(int relief, String label) {
393         this(relief);
394         setBorderLabel(label);
395     }
396 
VJPanel(int relief, String label, int borderWidth, Insets borderInsets)397     public VJPanel(int relief, String label,
398 		   int borderWidth, Insets borderInsets) {
399         this(relief, label);
400         setBorderWidth(borderWidth);
401         setBorderInsets(borderInsets);
402     }
403 
404     //
405     // Children that are not visible should
406     // not be layed out.  The reason
407     // for this is that layout managers ignore non-visible components,
408     // therefore non-visible components do not get reshaped.
409     //
410     // In the case of a non-visible, non-container component, there is
411     // no problem.  But if you have a non-visible container, then the
412     // layout method should not be called on that container.   But AWT
413     // ignores visibility and calls layout on
414     // all containers regardless.
415     //
416     // The problem with this is that a non-visible container will not
417     // have been reshaped when its parent was layed out.  Therefore,
418     // calling layout on this container causes it to do a layout based
419     // on its own bogus size.  This means that all the child components
420     // get reshaped and validated with incorrect sizes!  If the
421     // non-visible container is later made
422     // visible, all of its components
423     // are already valid so they don't get layed out again.  But these
424     // components have incorrect sizes.
425     //
426     // This workaround ensures that layout is not called on non-visible
427     // children of the container.
428     //
validate()429     public void validate() {
430         if (!isValid() && getPeer() != null) {
431             layout();
432 
433             // Unfortunately, we don't have access to the valid flag.
434             // Fortunately, it is okay to leave the component invalid.
435             //
436             // Components in an AWT application
437             // are invalid most of the time
438             // anyways, because if any child component invalidate, then
439             // all the parents are invalidated.  And there are many
440             // situations where a child calls
441             // invalidate where you don't
442             // want to call validate again.  So many components end up
443             // invalid all the time.  This is okay, because
444             // it just means
445             // that if you do call validate, then everything will get
446             // layed out again.
447 
448             // valid = true;
449         }
450 
451         int ncomponents = countComponents();
452         for (int i = 0; i < ncomponents; i++) {
453             Component comp = getComponent(i);
454             if (!comp.isValid() && comp.getPeer() !=
455 		null && comp.isVisible()) {
456                 comp.validate();
457             }
458         }
459     }
460 
validateTree()461     protected void validateTree() {
462         if (!isValid() && getPeer() != null) {
463             layout();
464 
465             int ncomponents = countComponents();
466             for (int i = 0; i < ncomponents; ++i) {
467                 Component comp = getComponent(i);
468                 if ((comp instanceof Container) &&
469 		    !(comp instanceof Window) &&
470 		    (!comp.isValid() && comp.getPeer() != null) &&
471 		    comp.isVisible()) {
472                     ((Container)comp).validate();
473                 }
474             }
475         }
476     }
477 
478     // Workaround for idiotic JDK1.1 bug where if you add a
479     // component to a container that it is already in, then
480     // the component will be removed from the container!
481     //
482     // #ifdef JDK1.1
addImpl(Component comp, Object constraints, int index)483     protected void addImpl(Component comp, Object constraints,
484 			   int index) {
485         if (comp.getParent() != this)
486             super.addImpl(comp, constraints, index);
487     }
488     // #endif
489 
setRelief(int relief)490     public void setRelief(int relief) {
491         this.relief = relief;
492 
493         // Need to invalidate because changing
494         // from a flat relief to something
495         // else will cause the preferredSize to change.
496 	invalidate();
497         repaint();
498     }
499 
getRelief()500     public int getRelief() {
501         return relief;
502     }
503 
setBorderWidth(int borderWidth)504     public void setBorderWidth(int borderWidth) {
505         if (borderWidth != this.borderWidth) {
506             this.borderWidth = borderWidth;
507             invalidate();
508             repaint();
509         }
510     }
511 
getBorderWidth()512     public int getBorderWidth() {
513         return borderWidth;
514     }
515 
setBorderLabel(String label)516     public void setBorderLabel(String label) {
517         borderLabel = label;
518         invalidate();
519         repaint();
520     }
521 
getBorderLabel()522     public String getBorderLabel() {
523         return borderLabel;
524     }
525 
setLabelAlignment(int alignment)526     public void setLabelAlignment(int alignment) {
527         labelAlignment = alignment;
528         repaint();
529     }
530 
getLabelAlignment()531     public int getLabelAlignment() {
532         return labelAlignment;
533     }
534 
setBorderInsets(Insets insets)535     public void setBorderInsets(Insets insets) {
536         if (insets == null)
537             this.borderInsets = new Insets(0, 0, 0, 0);
538         else
539             this.borderInsets = (Insets)insets.clone();
540         invalidate();
541     }
542 
getBorderInsets()543     public Insets getBorderInsets() {
544         return (Insets)borderInsets.clone();
545     }
546 
insets()547     public Insets insets() {
548         int bd = getBD();
549         int h = getLabelAdjustedTop();
550         Insets insets = getAdjustedInsets();
551 
552         return new Insets(h + insets.top,
553 			  bd + insets.left,
554 			  bd + insets.bottom,
555 			  bd + insets.right);
556     }
557 
minimumSize()558     public Dimension minimumSize() {
559         Dimension d = super.minimumSize();
560         int w = getLabelAdjustedMinWidth();
561         if (w > d.width)
562             d = new Dimension(w, d.height);
563         return d;
564     }
565 
preferredSize()566     public Dimension preferredSize() {
567         Dimension d = super.preferredSize();
568         int w = getLabelAdjustedMinWidth();
569         if (w > d.width)
570             d = new Dimension(w, d.height);
571         return d;
572     }
573 
getBD()574     private int getBD() {
575         int bd = 0;
576         if (relief != Util.RELIEF_FLAT || borderLabel != null)
577             bd = borderWidth;
578         return bd;
579     }
580 
getAdjustedInsets()581     private Insets getAdjustedInsets() {
582         Insets insets;
583         if (relief == Util.RELIEF_FLAT && borderLabel == null)
584             insets = new Insets(0, 0, 0, 0);
585         else
586             insets = borderInsets;
587         return insets;
588     }
589 
getLabelAdjustedTop()590     private int getLabelAdjustedTop() {
591         if (relief == Util.RELIEF_FLAT && borderLabel == null)
592             return 0;
593 
594         int bd = borderWidth;
595         int top = bd;
596         Font font = getFont();
597 
598         if (borderLabel != null && font != null) {
599             FontMetrics fm = getFontMetrics(font);
600             top = fm.getAscent() + fm.getDescent() + labelpadtop;
601 
602             if (!isLabelInBorder())
603                 top += bd;
604             else if (top < bd)
605                 top = bd;
606         }
607 
608         return top;
609     }
610 
getLabelAdjustedMinWidth()611     private int getLabelAdjustedMinWidth() {
612         if (relief == Util.RELIEF_FLAT && borderLabel == null)
613             return 0;
614 
615         int bd = borderWidth;
616         int w = 2*bd + borderInsets.left + borderInsets.right;
617 
618         Font font = getFont();
619         if (borderLabel != null && font != null) {
620             FontMetrics fm = getFontMetrics(font);
621             w = Math.max(w, 2*bd + fm.stringWidth(borderLabel)
622 			 + labelpadx + labelipadx);
623         }
624 
625         return w;
626     }
627 
isLabelInBorder()628     private boolean isLabelInBorder() {
629         switch (relief) {
630 	case Util.RELIEF_RAISED:
631 	case Util.RELIEF_SUNKEN:
632 	case Util.WIN95_RAISED:
633 	case Util.WIN95_SUNKEN:
634 	case Util.WIN95_FIELD_BORDER:
635 	case Util.WIN95_WINDOW_BORDER:
636             return false;
637 
638 	case Util.RELIEF_GROOVE:
639 	case Util.RELIEF_RIDGE:
640 	case Util.BLACK_BORDER:
641 	case Util.RELIEF_FLAT:
642 	default:
643             return true;
644         }
645     }
646 
update(Graphics g)647     public void update(Graphics g) {
648         if (Global.isWindows())
649             g = getGraphics();
650         Dimension size = size();
651         Insets insets = insets();
652 
653         g.setColor(getBackground());
654         if (insets.left > 0)
655             g.fillRect(0, 0, insets.left, size.height);
656         if (insets.top > 0)
657             g.fillRect(0, 0, size.width, insets.top);
658         if (insets.bottom > 0)
659             g.fillRect(0, size.height-insets.bottom,
660 		       size.width, insets.bottom);
661         if (insets.right > 0)
662             g.fillRect(size.width-insets.right, 0,
663 		       insets.right, size.height);
664 
665         paint(g);
666     }
667 
paint(Graphics g)668     public void paint(Graphics g) {
669         // XXX This workaround is needed for both
670         // Windows and Solaris to ensure
671         //     all lightweight components contained
672         // within VJPanel are repainted
673         //     correctly;  For some reasons, VJPanel
674         // is entirely filled with
675         //     the background color whenever update()
676         // is called.  If only the
677         //     components within the clip region
678         // of the "Graphics g" parameter
679         //     is repainted, then the other lightweight
680         // components become
681         //     invisible because they get painted
682         // over with the VJPanel background.
683         //     The obvious suspect for filling
684         // the VJPanel background is the
685         //     fillRect calls in update(), but
686         // the problem exists even when
687         //     those fillRect calls are not executed.  See bug 4074362.
688         g = getGraphics();
689         // end of workaround
690 
691         super.paint(g);
692 
693         Dimension size = size();
694         Insets insets = insets();
695         int bd = borderWidth;
696 
697         FontMetrics fm = null;
698         if (borderLabel != null) {
699             fm = getFontMetrics(getFont());
700         }
701 
702         // Draw the border
703         if (relief != Util.RELIEF_FLAT && bd > 0) {
704             switch (relief) {
705 	    case Util.RELIEF_FLAT:
706 	    case Util.RELIEF_RAISED:
707 	    case Util.RELIEF_SUNKEN:
708 	    case Util.RELIEF_RIDGE:
709 	    case Util.RELIEF_GROOVE:
710 	    case Util.WIN95_RAISED:
711 	    case Util.WIN95_SUNKEN:
712 	    case Util.BLACK_BORDER:
713                 g.setColor(getBackground());
714                 break;
715 
716 	    case Util.WIN95_FIELD_BORDER:
717 	    case Util.WIN95_WINDOW_BORDER:
718                 g.setColor(getParent().getBackground());
719                 break;
720             }
721             int yoff = 0;
722             if (borderLabel != null) {
723                 int ascent = fm.getAscent();
724                 int descent = fm.getDescent();
725 
726                 if (isLabelInBorder())
727                     yoff = (ascent + descent + labelpadtop - bd)/2;
728                 else
729                     yoff = ascent + descent + labelpadtop;
730 
731                 if (yoff < 0)
732                     yoff = 0;
733             }
734 
735             Global.util.draw3DRect(g, 0, yoff,
736 				   size.width-1, size.height-1-yoff,
737 				   relief, bd);
738         }
739 
740         // Draw the label
741         if (borderLabel != null) {
742             int stringWidth = fm.stringWidth(borderLabel);
743             int ascent = fm.getAscent();
744             int descent = fm.getDescent();
745             int x, y, h;
746 
747             switch (labelAlignment) {
748 	    case LEFT:
749 	    default:
750                 x = bd + (labelpadx + labelipadx)/2;
751                 break;
752 	    case CENTER:
753                 x = (size.width - stringWidth)/2;
754                 break;
755 	    case RIGHT:
756                 x = size.width - (stringWidth + (labelpadx
757 						 + labelipadx)/2 + bd);
758                 break;
759             }
760 
761             y = labelpadtop + ascent;
762             h = labelpadtop + ascent + descent;
763 
764             if (isLabelInBorder() && bd > h) {
765                 y = (bd - h)/2 + (labelpadtop + ascent);
766                 h = bd;
767             }
768 
769             g.setColor(getBackground());
770             g.fillRect(x - labelipadx/2, 0, stringWidth +
771 		       labelipadx, h);
772 
773             g.setColor(getForeground());
774             g.setFont(getFont());
775             g.drawString(borderLabel, x, y-1);
776         }
777     }
778 
779     //
780     // Workaround for Windows95 AWT bug:  If you call
781     // request focus while
782     // the mouse is pressed, you get spurious
783     // mouse down events.  Not only
784     // that, but the spurious events have
785     // clickCount set to 2, so you end
786     // up with spurious double clicks.  On Windows95 the component
787     // automatically gets the focus when you press the mouse inside it.
788     // Therefore, it isn't necessary to call
789     // requestFocus at all if running
790     // on Windows and the mouse is down (and this avoids the bug).
791     //
requestFocus()792     public void requestFocus() {
793         if (!Global.isWindows() || !VJPanel.isMouseDown)
794             super.requestFocus();
795     }
796 }
797