jdk/src/solaris/classes/sun/awt/X11/XMenuBarPeer.java
changeset 2 90ce3da70b43
child 3938 ef327bd847c0
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     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  */
       
    25 package sun.awt.X11;
       
    26 
       
    27 import java.awt.*;
       
    28 import java.awt.peer.*;
       
    29 import java.awt.event.*;
       
    30 
       
    31 import java.lang.reflect.Field;
       
    32 import java.util.Vector;
       
    33 import java.util.logging.*;
       
    34 import sun.awt.SunToolkit;
       
    35 
       
    36 public class XMenuBarPeer extends XBaseMenuWindow implements MenuBarPeer {
       
    37 
       
    38     /************************************************
       
    39      *
       
    40      * Data members
       
    41      *
       
    42      ************************************************/
       
    43 
       
    44     private static Logger log = Logger.getLogger("sun.awt.X11.XMenuBarPeer");
       
    45 
       
    46     /*
       
    47      * Primary members
       
    48      */
       
    49     private XFramePeer framePeer;
       
    50     private MenuBar menuBarTarget;
       
    51 
       
    52     /*
       
    53      * Index of help menu
       
    54      */
       
    55     private XMenuPeer helpMenu = null;
       
    56 
       
    57     /*
       
    58      * dimension constants
       
    59      */
       
    60     private final static int BAR_SPACING_TOP = 3;
       
    61     private final static int BAR_SPACING_BOTTOM = 3;
       
    62     private final static int BAR_SPACING_LEFT = 3;
       
    63     private final static int BAR_SPACING_RIGHT = 3;
       
    64     private final static int BAR_ITEM_SPACING = 2;
       
    65     private final static int BAR_ITEM_MARGIN_LEFT = 10;
       
    66     private final static int BAR_ITEM_MARGIN_RIGHT = 10;
       
    67     private final static int BAR_ITEM_MARGIN_TOP = 2;
       
    68     private final static int BAR_ITEM_MARGIN_BOTTOM = 2;
       
    69 
       
    70     //fields
       
    71     private static Field f_helpMenu;
       
    72     private static Field f_menus;
       
    73 
       
    74     static {
       
    75         f_helpMenu = SunToolkit.getField(MenuBar.class, "helpMenu");
       
    76         f_menus = SunToolkit.getField(MenuBar.class, "menus");
       
    77     }
       
    78 
       
    79     /************************************************
       
    80      *
       
    81      * Mapping data
       
    82      *
       
    83      ************************************************/
       
    84 
       
    85     /**
       
    86      * XBaseMenuWindow's mappingData is extended with
       
    87      * desired height of menu bar
       
    88      */
       
    89     static class MappingData extends XBaseMenuWindow.MappingData {
       
    90         int desiredHeight;
       
    91 
       
    92         MappingData(XMenuItemPeer[] items, int desiredHeight) {
       
    93             super(items);
       
    94             this.desiredHeight = desiredHeight;
       
    95         }
       
    96 
       
    97         /**
       
    98          * Constructs MappingData without items
       
    99          * This constructor should be used in case of errors
       
   100          */
       
   101         MappingData() {
       
   102             this.desiredHeight = 0;
       
   103         }
       
   104 
       
   105         public int getDesiredHeight() {
       
   106             return this.desiredHeight;
       
   107         }
       
   108     }
       
   109 
       
   110     /************************************************
       
   111      *
       
   112      * Construction
       
   113      *
       
   114      ************************************************/
       
   115     XMenuBarPeer(MenuBar menuBarTarget) {
       
   116         this.menuBarTarget = menuBarTarget;
       
   117     }
       
   118 
       
   119     /************************************************
       
   120      *
       
   121      * Implementaion of interface methods
       
   122      *
       
   123      ************************************************/
       
   124 
       
   125     /*
       
   126      * From MenuComponentPeer
       
   127      */
       
   128     public void setFont(Font f) {
       
   129         resetMapping();
       
   130         setItemsFont(f);
       
   131         postPaintEvent();
       
   132     }
       
   133 
       
   134     /*
       
   135      * From MenuBarPeer
       
   136      */
       
   137 
       
   138     /*
       
   139      * Functions addMenu, delMenu, addHelpMenu
       
   140      * need to have somewhat strange behaivour
       
   141      * deduced from java.awt.MenuBar.
       
   142      * We can not get index of particular item in
       
   143      * MenuBar.menus array, because MenuBar firstly
       
   144      * performs array operations and then calls peer.
       
   145      * So we need to synchronize indicies in 'items'
       
   146      * array with MenuBar.menus. We have to follow
       
   147      * these rules:
       
   148      * 1. Menus are always added to the end of array,
       
   149      * even when helpMenu is present
       
   150      * 2. Removal of any menu item acts as casual
       
   151      * remove from array
       
   152      * 3. MenuBar.setHelpMenu _firstly_ removes
       
   153      * previous helpMenu by calling delMenu() if
       
   154      * necessary, then it performs addMenu(),
       
   155      * and then - addHelpMenu().
       
   156      *
       
   157      * Note that these functions don't perform
       
   158      * type checks and checks for nulls or duplicates
       
   159      */
       
   160     public void addMenu(Menu m) {
       
   161         addItem(m);
       
   162         postPaintEvent();
       
   163     }
       
   164 
       
   165     public void delMenu(int index) {
       
   166         synchronized(getMenuTreeLock()) {
       
   167             XMenuItemPeer item = getItem(index);
       
   168             if (item != null && item == helpMenu) {
       
   169                 helpMenu = null;
       
   170             }
       
   171             delItem(index);
       
   172         }
       
   173         postPaintEvent();
       
   174     }
       
   175 
       
   176     public void addHelpMenu(Menu m) {
       
   177         XMenuPeer mp = (XMenuPeer)m.getPeer();
       
   178         synchronized(getMenuTreeLock()) {
       
   179             helpMenu = mp;
       
   180         }
       
   181         postPaintEvent();
       
   182     }
       
   183 
       
   184     /************************************************
       
   185      *
       
   186      * Initialization
       
   187      *
       
   188      ************************************************/
       
   189     /**
       
   190      * called from XFramePeer.setMenuBar
       
   191      */
       
   192     public void init(Frame frame) {
       
   193         this.target = frame;
       
   194         this.framePeer = (XFramePeer)frame.getPeer();
       
   195         XCreateWindowParams params = getDelayedParams();
       
   196         params.remove(DELAYED);
       
   197         params.add(PARENT_WINDOW, framePeer.getShell());
       
   198         params.add(TARGET, frame);
       
   199         init(params);
       
   200     }
       
   201 
       
   202     /**
       
   203      * Overriden initialization
       
   204      */
       
   205     void postInit(XCreateWindowParams params) {
       
   206         super.postInit(params);
       
   207         Vector targetMenuVector = null;
       
   208         Menu targetHelpMenu = null;
       
   209         try {
       
   210             // Get menus from the target.
       
   211             targetMenuVector = (Vector)f_menus.get(menuBarTarget);
       
   212             targetHelpMenu = (Menu)f_helpMenu.get(menuBarTarget);
       
   213             reloadItems(targetMenuVector);
       
   214         } catch (IllegalAccessException iae) {
       
   215             iae.printStackTrace();
       
   216         }
       
   217         if (targetHelpMenu != null) {
       
   218             addHelpMenu(targetHelpMenu);
       
   219         }
       
   220         xSetVisible(true);
       
   221         toFront();
       
   222     }
       
   223 
       
   224     /************************************************
       
   225      *
       
   226      * Implementation of abstract methods
       
   227      *
       
   228      ************************************************/
       
   229 
       
   230     /**
       
   231      * Menu bar is always root window in menu window's
       
   232      * hierarchy
       
   233      */
       
   234     protected XBaseMenuWindow getParentMenuWindow() {
       
   235         return null;
       
   236     }
       
   237 
       
   238     /**
       
   239      * @see XBaseMenuWindow.map
       
   240      */
       
   241     protected MappingData map() {
       
   242         XMenuItemPeer[] itemVector = copyItems();
       
   243         int itemCnt = itemVector.length;
       
   244         XMenuItemPeer helpMenu = this.helpMenu;
       
   245         int helpMenuPos = -1;
       
   246         //find helpMenu and move it to the end of array
       
   247         if (helpMenu != null) {
       
   248             //Fixed 6270847: PIT: HELP menu is not shown at the right place when normal menus added to MB are removed, XToolkit
       
   249             for (int i = 0; i < itemCnt; i++) {
       
   250                 if (itemVector[i] == helpMenu) {
       
   251                     helpMenuPos = i;
       
   252                     break;
       
   253                 }
       
   254             }
       
   255             if (helpMenuPos != -1 && helpMenuPos != itemCnt - 1) {
       
   256                 System.arraycopy(itemVector, helpMenuPos + 1, itemVector, helpMenuPos, itemCnt - 1 - helpMenuPos);
       
   257                 itemVector[itemCnt - 1] = helpMenu;
       
   258             }
       
   259         }
       
   260         //We need maximum height before calculating item's bounds
       
   261         int maxHeight = 0;
       
   262         XMenuItemPeer.TextMetrics[] itemMetrics = new XMenuItemPeer.TextMetrics[itemCnt];
       
   263         for (int i = 0; i < itemCnt; i++) {
       
   264             itemMetrics[i] = itemVector[i].getTextMetrics();
       
   265             Dimension dim = itemMetrics[i].getTextDimension();
       
   266             if (dim != null) {
       
   267                 maxHeight = Math.max(maxHeight, dim.height);
       
   268             }
       
   269         }
       
   270         //Calculate bounds
       
   271         int nextOffset = 0;
       
   272         int itemHeight = BAR_ITEM_MARGIN_TOP + maxHeight + BAR_ITEM_MARGIN_BOTTOM;
       
   273         int mappedCnt = itemCnt;
       
   274         for (int i = 0; i < itemCnt; i++) {
       
   275             XMenuItemPeer item = itemVector[i];
       
   276             XMenuItemPeer.TextMetrics metrics = itemMetrics[i];
       
   277             Dimension dim = metrics.getTextDimension();
       
   278             if (dim != null) {
       
   279                 int itemWidth = BAR_ITEM_MARGIN_LEFT + dim.width + BAR_ITEM_MARGIN_RIGHT;
       
   280                 //Fix for 6270757: PIT: Menus and Sub-menus are shown outside the frame, XToolkit
       
   281                 //Cut-off items that don't fit in window
       
   282                 //At least one item must remain in menu
       
   283                 if ((nextOffset + itemWidth > this.width) && (i > 0)) {
       
   284                     mappedCnt = i;
       
   285                     break;
       
   286                 }
       
   287                 //If this item is help menu, move it to the right edge
       
   288                 if ((i == itemCnt - 1) && helpMenuPos != -1) {
       
   289                     nextOffset = Math.max(nextOffset, this.width - itemWidth - BAR_SPACING_RIGHT);
       
   290                 }
       
   291                 Rectangle bounds = new Rectangle(nextOffset, BAR_SPACING_TOP, itemWidth, itemHeight);
       
   292                 //text should be centered vertically in menu item's bounds
       
   293                 int y = (maxHeight + dim.height) / 2  - metrics.getTextBaseline();
       
   294                 Point textOrigin = new Point(nextOffset + BAR_ITEM_MARGIN_LEFT, BAR_SPACING_TOP + BAR_ITEM_MARGIN_TOP + y);
       
   295                 nextOffset += itemWidth + BAR_ITEM_SPACING;
       
   296                 item.map(bounds, textOrigin);
       
   297             } else {
       
   298                 Rectangle bounds = new Rectangle(nextOffset, BAR_SPACING_TOP, 0, 0);
       
   299                 Point textOrigin = new Point(nextOffset + BAR_ITEM_MARGIN_LEFT, BAR_SPACING_TOP + BAR_ITEM_MARGIN_TOP);
       
   300             }
       
   301         }
       
   302         XMenuItemPeer mappedVector[] = new XMenuItemPeer[mappedCnt];
       
   303         System.arraycopy(itemVector, 0, mappedVector, 0, mappedCnt);
       
   304         MappingData mappingData = new MappingData(mappedVector, BAR_SPACING_TOP + itemHeight + BAR_SPACING_BOTTOM);
       
   305         return mappingData;
       
   306     }
       
   307 
       
   308     /**
       
   309      * @see XBaseMenuWindow.getSubmenuBounds
       
   310      */
       
   311     protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) {
       
   312         Rectangle globalBounds = toGlobal(itemBounds);
       
   313         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
       
   314         Rectangle res;
       
   315         res = fitWindowBelow(globalBounds, windowSize, screenSize);
       
   316         if (res != null) {
       
   317             return res;
       
   318         }
       
   319         res = fitWindowAbove(globalBounds, windowSize, screenSize);
       
   320         if (res != null) {
       
   321             return res;
       
   322         }
       
   323         res = fitWindowRight(globalBounds, windowSize, screenSize);
       
   324         if (res != null) {
       
   325             return res;
       
   326         }
       
   327         res = fitWindowLeft(globalBounds, windowSize, screenSize);
       
   328         if (res != null) {
       
   329             return res;
       
   330         }
       
   331         return fitWindowToScreen(windowSize, screenSize);
       
   332     }
       
   333 
       
   334     /**
       
   335      * This function is called when it's likely that
       
   336      * size of items has changed.
       
   337      * Invokes framePeer's updateChildrenSizes()
       
   338      */
       
   339     protected void updateSize() {
       
   340         resetMapping();
       
   341         if (framePeer != null) {
       
   342             framePeer.reshapeMenubarPeer();
       
   343         }
       
   344     }
       
   345 
       
   346     /************************************************
       
   347      *
       
   348      * Utility functions
       
   349      *
       
   350      ************************************************/
       
   351 
       
   352     /**
       
   353      * Returns desired height of menu bar
       
   354      */
       
   355     int getDesiredHeight() {
       
   356         MappingData mappingData = (MappingData)getMappingData();
       
   357         return mappingData.getDesiredHeight();
       
   358     }
       
   359 
       
   360     /**
       
   361      * Returns true if framePeer is not null and is enabled
       
   362      * Used to fix 6185057: Disabling a frame does not disable
       
   363      * the menus on the frame, on solaris/linux
       
   364      */
       
   365     boolean isFramePeerEnabled() {
       
   366         if (framePeer != null) {
       
   367             return framePeer.isEnabled();
       
   368         }
       
   369         return false;
       
   370     }
       
   371 
       
   372     /************************************************
       
   373      *
       
   374      * Overriden XBaseMenuWindow functions
       
   375      *
       
   376      ************************************************/
       
   377 
       
   378     /**
       
   379      * @see XBaseMenuWindow.doDispose()
       
   380      */
       
   381     protected void doDispose() {
       
   382         super.doDispose();
       
   383         XToolkit.targetDisposedPeer(menuBarTarget, this);
       
   384     }
       
   385 
       
   386     /************************************************
       
   387      *
       
   388      * Overriden XWindow general-purpose functions
       
   389      *
       
   390      ************************************************/
       
   391 
       
   392     /**
       
   393      * For menu bars this function is called from framePeer's
       
   394      * reshape(...) and updateChildrenSizes()
       
   395      */
       
   396     public void reshape(int x, int y, int width, int height) {
       
   397         if ((width != this.width) || (height != this.height)) {
       
   398             resetMapping();
       
   399         }
       
   400         super.reshape(x, y, width, height);
       
   401     }
       
   402 
       
   403     /**
       
   404      * Performs ungrabbing of input
       
   405      * @see XBaseWindow.ungrabInputImpl()
       
   406      */
       
   407     void ungrabInputImpl() {
       
   408         selectItem(null, false);
       
   409         super.ungrabInputImpl();
       
   410         postPaintEvent();
       
   411     }
       
   412 
       
   413     /************************************************
       
   414      *
       
   415      * Overriden XWindow painting & printing
       
   416      *
       
   417      ************************************************/
       
   418     public void paint(Graphics g) {
       
   419         resetColors();
       
   420         /* Calculate menubar dimension. */
       
   421         int width = getWidth();
       
   422         int height = getHeight();
       
   423 
       
   424         flush();
       
   425         //Fill background of rectangle
       
   426         g.setColor(getBackgroundColor());
       
   427         g.fillRect(1, 1, width - 2, height - 2);
       
   428 
       
   429         draw3DRect(g, 0, 0, width, height, true);
       
   430 
       
   431         //Paint menus
       
   432         MappingData mappingData = (MappingData)getMappingData();
       
   433         XMenuItemPeer[] itemVector = mappingData.getItems();
       
   434         XMenuItemPeer selectedItem = getSelectedItem();
       
   435         for (int i = 0; i < itemVector.length; i++) {
       
   436             XMenuItemPeer item = itemVector[i];
       
   437             //paint item
       
   438             g.setFont(item.getTargetFont());
       
   439             Rectangle bounds = item.getBounds();
       
   440             Point textOrigin = item.getTextOrigin();
       
   441             if (item == selectedItem) {
       
   442                 g.setColor(getSelectedColor());
       
   443                 g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
       
   444                 draw3DRect(g, bounds.x, bounds.y, bounds.width, bounds.height, false);
       
   445             }
       
   446             if (isFramePeerEnabled() && item.isTargetItemEnabled()) {
       
   447                 g.setColor(getForegroundColor());
       
   448             } else {
       
   449                 g.setColor(getDisabledColor());
       
   450             }
       
   451             g.drawString(item.getTargetLabel(), textOrigin.x, textOrigin.y);
       
   452         }
       
   453         flush();
       
   454     }
       
   455 
       
   456     static final int W_DIFF = (XFramePeer.CROSSHAIR_INSET + 1) * 2;
       
   457     static final int H_DIFF = XFramePeer.BUTTON_Y + XFramePeer.BUTTON_H;
       
   458 
       
   459     void print(Graphics g) {
       
   460         //TODO:Implement
       
   461     }
       
   462 
       
   463     /************************************************
       
   464      *
       
   465      * Overriden XBaseMenuWindow event handling
       
   466      *
       
   467      ************************************************/
       
   468     protected void handleEvent(AWTEvent event) {
       
   469         // explicitly block all events except PaintEvent.PAINT for menus,
       
   470         // that are in the modal blocked window
       
   471         if ((framePeer != null) &&
       
   472             (event.getID() != PaintEvent.PAINT))
       
   473         {
       
   474             if (framePeer.isModalBlocked()) {
       
   475                 return;
       
   476             }
       
   477         }
       
   478         switch(event.getID()) {
       
   479         case MouseEvent.MOUSE_PRESSED:
       
   480         case MouseEvent.MOUSE_RELEASED:
       
   481         case MouseEvent.MOUSE_CLICKED:
       
   482         case MouseEvent.MOUSE_MOVED:
       
   483         case MouseEvent.MOUSE_ENTERED:
       
   484         case MouseEvent.MOUSE_EXITED:
       
   485         case MouseEvent.MOUSE_DRAGGED:
       
   486             //Fix for 6185057: Disabling a frame does not disable
       
   487             //the menus on the frame, on solaris/linux
       
   488             if (isFramePeerEnabled()) {
       
   489                 doHandleJavaMouseEvent((MouseEvent)event);
       
   490             }
       
   491             break;
       
   492         case KeyEvent.KEY_PRESSED:
       
   493         case KeyEvent.KEY_RELEASED:
       
   494             //Fix for 6185057: Disabling a frame does not disable
       
   495             //the menus on the frame, on solaris/linux
       
   496             if (isFramePeerEnabled()) {
       
   497                 doHandleJavaKeyEvent((KeyEvent)event);
       
   498             }
       
   499             break;
       
   500         default:
       
   501             super.handleEvent(event);
       
   502             break;
       
   503         }
       
   504     }
       
   505 
       
   506 
       
   507 
       
   508     /************************************************
       
   509      *
       
   510      * Overriden XWindow keyboard processing
       
   511      *
       
   512      ************************************************/
       
   513 
       
   514     /*
       
   515      * This function is called from XWindow
       
   516      * @see XWindow.handleF10onEDT()
       
   517      */
       
   518     void handleF10KeyPress(KeyEvent event) {
       
   519         int keyState = event.getModifiers();
       
   520         if (((keyState & InputEvent.ALT_MASK) != 0) ||
       
   521             ((keyState & InputEvent.SHIFT_MASK) != 0) ||
       
   522             ((keyState & InputEvent.CTRL_MASK) != 0)) {
       
   523             return;
       
   524         }
       
   525         grabInput();
       
   526         selectItem(getFirstSelectableItem(), true);
       
   527     }
       
   528 
       
   529     /*
       
   530      * In previous version keys were handled in handleKeyPress.
       
   531      * Now we override this function do disable F10 explicit
       
   532      * processing. All processing is done using KeyEvent.
       
   533      */
       
   534     public void handleKeyPress(XEvent xev) {
       
   535         XKeyEvent xkey = xev.get_xkey();
       
   536         if (log.isLoggable(Level.FINE)) log.fine(xkey.toString());
       
   537         if (isEventDisabled(xev)) {
       
   538             return;
       
   539         }
       
   540         final Component currentSource = (Component)getEventSource();
       
   541         //This is the only difference from XWindow.handleKeyPress
       
   542         //Ancestor's function can invoke handleF10KeyPress here
       
   543         handleKeyPress(xkey);
       
   544     }
       
   545 
       
   546 } //class XMenuBarPeer