/*
 * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package sun.awt.X11;

import java.awt.*;
import java.awt.peer.*;
import java.awt.event.*;

import java.util.Vector;
import sun.util.logging.PlatformLogger;
import sun.awt.AWTAccessor;

public class XMenuBarPeer extends XBaseMenuWindow implements MenuBarPeer {

    
Data members
/************************************************ * * Data members * ************************************************/
private static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XMenuBarPeer"); /* * Primary members */ private XFramePeer framePeer; private MenuBar menuBarTarget; /* * Index of help menu */ private XMenuPeer helpMenu = null; /* * dimension constants */ private static final int BAR_SPACING_TOP = 3; private static final int BAR_SPACING_BOTTOM = 3; private static final int BAR_SPACING_LEFT = 3; private static final int BAR_SPACING_RIGHT = 3; private static final int BAR_ITEM_SPACING = 2; private static final int BAR_ITEM_MARGIN_LEFT = 10; private static final int BAR_ITEM_MARGIN_RIGHT = 10; private static final int BAR_ITEM_MARGIN_TOP = 2; private static final int BAR_ITEM_MARGIN_BOTTOM = 2; /************************************************ * * Mapping data * ************************************************/
XBaseMenuWindow's mappingData is extended with desired height of menu bar
/** * XBaseMenuWindow's mappingData is extended with * desired height of menu bar */
static class MappingData extends XBaseMenuWindow.MappingData { int desiredHeight; MappingData(XMenuItemPeer[] items, int desiredHeight) { super(items); this.desiredHeight = desiredHeight; }
Constructs MappingData without items This constructor should be used in case of errors
/** * Constructs MappingData without items * This constructor should be used in case of errors */
MappingData() { this.desiredHeight = 0; } public int getDesiredHeight() { return this.desiredHeight; } }
Construction
/************************************************ * * Construction * ************************************************/
XMenuBarPeer(MenuBar menuBarTarget) { this.menuBarTarget = menuBarTarget; }
Implementaion of interface methods
/************************************************ * * Implementaion of interface methods * ************************************************/
/* * From MenuComponentPeer */ public void setFont(Font f) { resetMapping(); setItemsFont(f); postPaintEvent(); } /* * From MenuBarPeer */ /* * Functions addMenu, delMenu, addHelpMenu * need to have somewhat strange behaivour * deduced from java.awt.MenuBar. * We can not get index of particular item in * MenuBar.menus array, because MenuBar firstly * performs array operations and then calls peer. * So we need to synchronize indicies in 'items' * array with MenuBar.menus. We have to follow * these rules: * 1. Menus are always added to the end of array, * even when helpMenu is present * 2. Removal of any menu item acts as casual * remove from array * 3. MenuBar.setHelpMenu _firstly_ removes * previous helpMenu by calling delMenu() if * necessary, then it performs addMenu(), * and then - addHelpMenu(). * * Note that these functions don't perform * type checks and checks for nulls or duplicates */ public void addMenu(Menu m) { addItem(m); postPaintEvent(); } public void delMenu(int index) { synchronized(getMenuTreeLock()) { XMenuItemPeer item = getItem(index); if (item != null && item == helpMenu) { helpMenu = null; } delItem(index); } postPaintEvent(); } public void addHelpMenu(Menu m) { XMenuPeer mp = AWTAccessor.getMenuComponentAccessor().getPeer(m); synchronized(getMenuTreeLock()) { helpMenu = mp; } postPaintEvent(); } /************************************************ * * Initialization * ************************************************/
called from XFramePeer.setMenuBar
/** * called from XFramePeer.setMenuBar */
public void init(Frame frame) { this.target = frame; this.framePeer = AWTAccessor.getComponentAccessor().getPeer(frame); XCreateWindowParams params = getDelayedParams(); params.remove(DELAYED); params.add(PARENT_WINDOW, framePeer.getShell()); params.add(TARGET, frame); init(params); }
Overriden initialization
/** * Overriden initialization */
void postInit(XCreateWindowParams params) { super.postInit(params); // Get menus from the target. Vector<Menu> targetMenuVector = AWTAccessor.getMenuBarAccessor() .getMenus(menuBarTarget); Menu targetHelpMenu = AWTAccessor.getMenuBarAccessor() .getHelpMenu(menuBarTarget); reloadItems(targetMenuVector); if (targetHelpMenu != null) { addHelpMenu(targetHelpMenu); } xSetVisible(true); toFront(); } /************************************************ * * Implementation of abstract methods * ************************************************/
Menu bar is always root window in menu window's hierarchy
/** * Menu bar is always root window in menu window's * hierarchy */
protected XBaseMenuWindow getParentMenuWindow() { return null; }
See Also:
  • map.map
/** * @see XBaseMenuWindow#map */
protected MappingData map() { XMenuItemPeer[] itemVector = copyItems(); int itemCnt = itemVector.length; XMenuItemPeer helpMenu = this.helpMenu; int helpMenuPos = -1; //find helpMenu and move it to the end of array if (helpMenu != null) { //Fixed 6270847: PIT: HELP menu is not shown at the right place when normal menus added to MB are removed, XToolkit for (int i = 0; i < itemCnt; i++) { if (itemVector[i] == helpMenu) { helpMenuPos = i; break; } } if (helpMenuPos != -1 && helpMenuPos != itemCnt - 1) { System.arraycopy(itemVector, helpMenuPos + 1, itemVector, helpMenuPos, itemCnt - 1 - helpMenuPos); itemVector[itemCnt - 1] = helpMenu; } } //We need maximum height before calculating item's bounds int maxHeight = 0; XMenuItemPeer.TextMetrics[] itemMetrics = new XMenuItemPeer.TextMetrics[itemCnt]; for (int i = 0; i < itemCnt; i++) { itemMetrics[i] = itemVector[i].getTextMetrics(); if (itemMetrics[i] != null) { Dimension dim = itemMetrics[i].getTextDimension(); if (dim != null) { maxHeight = Math.max(maxHeight, dim.height); } } } //Calculate bounds int nextOffset = 0; int itemHeight = BAR_ITEM_MARGIN_TOP + maxHeight + BAR_ITEM_MARGIN_BOTTOM; int mappedCnt = itemCnt; for (int i = 0; i < itemCnt; i++) { XMenuItemPeer item = itemVector[i]; XMenuItemPeer.TextMetrics metrics = itemMetrics[i]; if (metrics == null) { continue; } Dimension dim = metrics.getTextDimension(); if (dim != null) { int itemWidth = BAR_ITEM_MARGIN_LEFT + dim.width + BAR_ITEM_MARGIN_RIGHT; //Fix for 6270757: PIT: Menus and Sub-menus are shown outside the frame, XToolkit //Cut-off items that don't fit in window //At least one item must remain in menu if ((nextOffset + itemWidth > this.width) && (i > 0)) { mappedCnt = i; break; } //If this item is help menu, move it to the right edge if ((i == itemCnt - 1) && helpMenuPos != -1) { nextOffset = Math.max(nextOffset, this.width - itemWidth - BAR_SPACING_RIGHT); } Rectangle bounds = new Rectangle(nextOffset, BAR_SPACING_TOP, itemWidth, itemHeight); //text should be centered vertically in menu item's bounds int y = (maxHeight + dim.height) / 2 - metrics.getTextBaseline(); Point textOrigin = new Point(nextOffset + BAR_ITEM_MARGIN_LEFT, BAR_SPACING_TOP + BAR_ITEM_MARGIN_TOP + y); nextOffset += itemWidth + BAR_ITEM_SPACING; item.map(bounds, textOrigin); } } XMenuItemPeer mappedVector[] = new XMenuItemPeer[mappedCnt]; System.arraycopy(itemVector, 0, mappedVector, 0, mappedCnt); MappingData mappingData = new MappingData(mappedVector, BAR_SPACING_TOP + itemHeight + BAR_SPACING_BOTTOM); return mappingData; }
See Also:
  • getSubmenuBounds.getSubmenuBounds
/** * @see XBaseMenuWindow#getSubmenuBounds */
protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) { Rectangle globalBounds = toGlobal(itemBounds); Rectangle screenBounds = getCurrentGraphicsConfiguration().getBounds(); Rectangle res; res = fitWindowBelow(globalBounds, windowSize, screenBounds); if (res != null) { return res; } res = fitWindowAbove(globalBounds, windowSize, screenBounds); if (res != null) { return res; } res = fitWindowRight(globalBounds, windowSize, screenBounds); if (res != null) { return res; } res = fitWindowLeft(globalBounds, windowSize, screenBounds); if (res != null) { return res; } return fitWindowToScreen(windowSize, screenBounds); }
This function is called when it's likely that size of items has changed. Invokes framePeer's updateChildrenSizes()
/** * This function is called when it's likely that * size of items has changed. * Invokes framePeer's updateChildrenSizes() */
protected void updateSize() { resetMapping(); if (framePeer != null) { framePeer.reshapeMenubarPeer(); } } /************************************************ * * Utility functions * ************************************************/
Returns desired height of menu bar
/** * Returns desired height of menu bar */
int getDesiredHeight() { MappingData mappingData = (MappingData)getMappingData(); return mappingData.getDesiredHeight(); }
Returns true if framePeer is not null and is enabled Used to fix 6185057: Disabling a frame does not disable the menus on the frame, on solaris/linux
/** * Returns true if framePeer is not null and is enabled * Used to fix 6185057: Disabling a frame does not disable * the menus on the frame, on solaris/linux */
boolean isFramePeerEnabled() { if (framePeer != null) { return framePeer.isEnabled(); } return false; } /************************************************ * * Overriden XBaseMenuWindow functions * ************************************************/
See Also:
  • doDispose.doDispose()
/** * @see XBaseMenuWindow#doDispose() */
protected void doDispose() { super.doDispose(); XToolkit.targetDisposedPeer(menuBarTarget, this); } /************************************************ * * Overriden XWindow general-purpose functions * ************************************************/
For menu bars this function is called from framePeer's reshape(...) and updateChildrenSizes()
/** * For menu bars this function is called from framePeer's * reshape(...) and updateChildrenSizes() */
public void reshape(int x, int y, int width, int height) { if ((width != this.width) || (height != this.height)) { resetMapping(); } super.reshape(x, y, width, height); }
Performs ungrabbing of input
See Also:
  • ungrabInputImpl.ungrabInputImpl()
/** * Performs ungrabbing of input * @see XBaseWindow#ungrabInputImpl() */
void ungrabInputImpl() { selectItem(null, false); super.ungrabInputImpl(); postPaintEvent(); }
Overriden XWindow painting & printing
/************************************************ * * Overriden XWindow painting & printing * ************************************************/
public void paintPeer(Graphics g) { resetColors(); /* Calculate menubar dimension. */ int width = getWidth(); int height = getHeight(); flush(); //Fill background of rectangle g.setColor(getBackgroundColor()); g.fillRect(1, 1, width - 2, height - 2); draw3DRect(g, 0, 0, width, height, true); //Paint menus MappingData mappingData = (MappingData)getMappingData(); XMenuItemPeer[] itemVector = mappingData.getItems(); XMenuItemPeer selectedItem = getSelectedItem(); for (int i = 0; i < itemVector.length; i++) { XMenuItemPeer item = itemVector[i]; //paint item g.setFont(item.getTargetFont()); Rectangle bounds = item.getBounds(); Point textOrigin = item.getTextOrigin(); if (item == selectedItem) { g.setColor(getSelectedColor()); g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); draw3DRect(g, bounds.x, bounds.y, bounds.width, bounds.height, false); } if (isFramePeerEnabled() && item.isTargetItemEnabled()) { g.setColor(getForegroundColor()); } else { g.setColor(getDisabledColor()); } g.drawString(item.getTargetLabel(), textOrigin.x, textOrigin.y); } flush(); } static final int W_DIFF = (XFramePeer.CROSSHAIR_INSET + 1) * 2; static final int H_DIFF = XFramePeer.BUTTON_Y + XFramePeer.BUTTON_H; void print(Graphics g) { //TODO:Implement }
Overriden XBaseMenuWindow event handling
/************************************************ * * Overriden XBaseMenuWindow event handling * ************************************************/
protected void handleEvent(AWTEvent event) { // explicitly block all events except PaintEvent.PAINT for menus, // that are in the modal blocked window if ((framePeer != null) && (event.getID() != PaintEvent.PAINT)) { if (framePeer.isModalBlocked()) { return; } } switch(event.getID()) { case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_RELEASED: case MouseEvent.MOUSE_CLICKED: case MouseEvent.MOUSE_MOVED: case MouseEvent.MOUSE_ENTERED: case MouseEvent.MOUSE_EXITED: case MouseEvent.MOUSE_DRAGGED: //Fix for 6185057: Disabling a frame does not disable //the menus on the frame, on solaris/linux if (isFramePeerEnabled()) { doHandleJavaMouseEvent((MouseEvent)event); } break; case KeyEvent.KEY_PRESSED: case KeyEvent.KEY_RELEASED: //Fix for 6185057: Disabling a frame does not disable //the menus on the frame, on solaris/linux if (isFramePeerEnabled()) { doHandleJavaKeyEvent((KeyEvent)event); } break; default: super.handleEvent(event); break; } }
Overriden XWindow keyboard processing
/************************************************ * * Overriden XWindow keyboard processing * ************************************************/
/* * This function is called from XWindow * @see XWindow.handleF10onEDT() */ @SuppressWarnings("deprecation") void handleF10KeyPress(KeyEvent event) { int keyState = event.getModifiers(); if (((keyState & InputEvent.ALT_MASK) != 0) || ((keyState & InputEvent.SHIFT_MASK) != 0) || ((keyState & InputEvent.CTRL_MASK) != 0)) { return; } grabInput(); selectItem(getFirstSelectableItem(), true); } /* * In previous version keys were handled in handleKeyPress. * Now we override this function do disable F10 explicit * processing. All processing is done using KeyEvent. */ public void handleKeyPress(XEvent xev) { XKeyEvent xkey = xev.get_xkey(); if (log.isLoggable(PlatformLogger.Level.FINE)) { log.fine(xkey.toString()); } if (isEventDisabled(xev)) { return; } final Component currentSource = getEventSource(); //This is the only difference from XWindow.handleKeyPress //Ancestor's function can invoke handleF10KeyPress here handleKeyPress(xkey); } } //class XMenuBarPeer