1 /* 2 * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.awt.X11; 26 27 import java.awt.*; 28 import java.awt.peer.*; 29 import java.awt.event.*; 30 31 import java.util.Vector; 32 import sun.awt.AWTAccessor; 33 import sun.util.logging.PlatformLogger; 34 35 public class XPopupMenuPeer extends XMenuWindow implements PopupMenuPeer { 36 37 /************************************************ 38 * 39 * Data members 40 * 41 ************************************************/ 42 private static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XBaseMenuWindow"); 43 44 /* 45 * Primary members 46 */ 47 private XComponentPeer componentPeer; 48 private PopupMenu popupMenuTarget; 49 50 /* 51 * If mouse button is clicked on item showing submenu 52 * we have to hide its submenu. 53 * This member saves the submenu under cursor 54 * Only if it's showing 55 */ 56 private XMenuPeer showingMousePressedSubmenu = null; 57 58 /* 59 * Painting constants 60 */ 61 private final static int CAPTION_MARGIN_TOP = 4; 62 private final static int CAPTION_SEPARATOR_HEIGHT = 6; 63 64 /************************************************ 65 * 66 * Construction 67 * 68 ************************************************/ 69 XPopupMenuPeer(PopupMenu target) { 70 super(null); 71 this.popupMenuTarget = target; 72 } 73 74 /************************************************ 75 * 76 * Implementation of interface methods 77 * 78 ************************************************/ 79 /* 80 * From MenuComponentPeer 81 */ 82 public void setFont(Font f) { 83 resetMapping(); 84 setItemsFont(f); 85 postPaintEvent(); 86 } 87 88 /* 89 * From MenuItemPeer 90 */ 91 public void setLabel(String label) { 92 resetMapping(); 93 postPaintEvent(); 94 } 95 96 97 public void setEnabled(boolean enabled) { 98 postPaintEvent(); 99 } 100 101 /** 102 * DEPRECATED: Replaced by setEnabled(boolean). 103 * @see java.awt.peer.MenuItemPeer 104 */ 105 public void enable() { 106 setEnabled( true ); 107 } 108 109 /** 110 * DEPRECATED: Replaced by setEnabled(boolean). 111 * @see java.awt.peer.MenuItemPeer 112 */ 113 public void disable() { 114 setEnabled( false ); 115 } 116 117 /* 118 * From MenuPeer 119 */ 120 /** 121 * addSeparator routines are not used 122 * in peers. Shared code invokes addItem("-") 123 * for adding separators 124 */ 125 public void addSeparator() { 126 if (log.isLoggable(PlatformLogger.FINER)) log.finer("addSeparator is not implemented"); 127 } 128 129 /* 130 * From PopupMenuPeer 131 */ 132 public void show(Event e) { 133 target = (Component)e.target; 134 // Get menus from the target. 135 Vector targetItemVector = getMenuTargetItems(); 136 if (targetItemVector != null) { 137 reloadItems(targetItemVector); 138 //Fix for 6287092: JCK15a: api/java_awt/interactive/event/EventTests.html#EventTest0015 fails, mustang 139 Point tl = target.getLocationOnScreen(); 140 Point pt = new Point(tl.x + e.x, tl.y + e.y); 141 //Fixed 6266513: Incorrect key handling in XAWT popup menu 142 //No item should be selected when showing popup menu 143 if (!ensureCreated()) { 144 return; 145 } 146 Dimension dim = getDesiredSize(); 147 //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened 148 //near the periphery of the screen, XToolkit 149 Rectangle bounds = getWindowBounds(pt, dim); 150 reshape(bounds); 151 xSetVisible(true); 152 toFront(); 153 selectItem(null, false); 154 grabInput(); 155 } 156 } 157 158 /************************************************ 159 * 160 * Access to target's fields 161 * 162 ************************************************/ 163 164 //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit 165 Font getTargetFont() { 166 if (popupMenuTarget == null) { 167 return XWindow.getDefaultFont(); 168 } 169 return AWTAccessor.getMenuComponentAccessor() 170 .getFont_NoClientCode(popupMenuTarget); 171 } 172 173 //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit 174 String getTargetLabel() { 175 if (target == null) { 176 return ""; 177 } 178 return AWTAccessor.getMenuItemAccessor().getLabel(popupMenuTarget); 179 } 180 181 //Fix for 6184485: Popup menu is not disabled on XToolkit even when calling setEnabled (false) 182 boolean isTargetEnabled() { 183 if (popupMenuTarget == null) { 184 return false; 185 } 186 return AWTAccessor.getMenuItemAccessor().isEnabled(popupMenuTarget); 187 } 188 189 Vector getMenuTargetItems() { 190 if (popupMenuTarget == null) { 191 return null; 192 } 193 return AWTAccessor.getMenuAccessor().getItems(popupMenuTarget); 194 } 195 196 /************************************************ 197 * 198 * Utility functions 199 * 200 ************************************************/ 201 202 //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened 203 //near the periphery of the screen, XToolkit 204 205 /** 206 * Calculates placement of popup menu window 207 * given origin in global coordinates and 208 * size of menu window. Returns suggested 209 * rectangle for menu window in global coordinates 210 * @param origin the origin point specified in show() 211 * function converted to global coordinates 212 * @param windowSize the desired size of menu's window 213 */ 214 protected Rectangle getWindowBounds(Point origin, Dimension windowSize) { 215 Rectangle globalBounds = new Rectangle(origin.x, origin.y, 0, 0); 216 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 217 Rectangle res; 218 res = fitWindowRight(globalBounds, windowSize, screenSize); 219 if (res != null) { 220 return res; 221 } 222 res = fitWindowLeft(globalBounds, windowSize, screenSize); 223 if (res != null) { 224 return res; 225 } 226 res = fitWindowBelow(globalBounds, windowSize, screenSize); 227 if (res != null) { 228 return res; 229 } 230 res = fitWindowAbove(globalBounds, windowSize, screenSize); 231 if (res != null) { 232 return res; 233 } 234 return fitWindowToScreen(windowSize, screenSize); 235 } 236 237 /************************************************ 238 * 239 * Overriden XMenuWindow caption-painting functions 240 * Necessary to fix 6267144: PIT: Popup menu label is not shown, XToolkit 241 * 242 ************************************************/ 243 /** 244 * Returns height of menu window's caption. 245 * Can be overriden for popup menus and tear-off menus 246 */ 247 protected Dimension getCaptionSize() { 248 String s = getTargetLabel(); 249 if (s.equals("")) { 250 return null; 251 } 252 Graphics g = getGraphics(); 253 if (g == null) { 254 return null; 255 } 256 try { 257 g.setFont(getTargetFont()); 258 FontMetrics fm = g.getFontMetrics(); 259 String str = getTargetLabel(); 260 int width = fm.stringWidth(str); 261 int height = CAPTION_MARGIN_TOP + fm.getHeight() + CAPTION_SEPARATOR_HEIGHT; 262 Dimension textDimension = new Dimension(width, height); 263 return textDimension; 264 } finally { 265 g.dispose(); 266 } 267 } 268 269 /** 270 * Paints menu window's caption. 271 * Can be overriden for popup menus and tear-off menus. 272 * Default implementation does nothing 273 */ 274 protected void paintCaption(Graphics g, Rectangle rect) { 275 String s = getTargetLabel(); 276 if (s.equals("")) { 277 return; 278 } 279 g.setFont(getTargetFont()); 280 FontMetrics fm = g.getFontMetrics(); 281 String str = getTargetLabel(); 282 int width = fm.stringWidth(str); 283 int textx = rect.x + (rect.width - width) / 2; 284 int texty = rect.y + CAPTION_MARGIN_TOP + fm.getAscent(); 285 int sepy = rect.y + rect.height - CAPTION_SEPARATOR_HEIGHT / 2; 286 g.setColor(isTargetEnabled() ? getForegroundColor() : getDisabledColor()); 287 g.drawString(s, textx, texty); 288 draw3DRect(g, rect.x, sepy, rect.width, 2, false); 289 } 290 291 /************************************************ 292 * 293 * Overriden XBaseMenuWindow functions 294 * 295 ************************************************/ 296 protected void doDispose() { 297 super.doDispose(); 298 XToolkit.targetDisposedPeer(popupMenuTarget, this); 299 } 300 301 protected void handleEvent(AWTEvent event) { 302 switch(event.getID()) { 303 case MouseEvent.MOUSE_PRESSED: 304 case MouseEvent.MOUSE_RELEASED: 305 case MouseEvent.MOUSE_CLICKED: 306 case MouseEvent.MOUSE_MOVED: 307 case MouseEvent.MOUSE_ENTERED: 308 case MouseEvent.MOUSE_EXITED: 309 case MouseEvent.MOUSE_DRAGGED: 310 doHandleJavaMouseEvent((MouseEvent)event); 311 break; 312 case KeyEvent.KEY_PRESSED: 313 case KeyEvent.KEY_RELEASED: 314 doHandleJavaKeyEvent((KeyEvent)event); 315 break; 316 default: 317 super.handleEvent(event); 318 break; 319 } 320 } 321 322 /************************************************ 323 * 324 * Overriden XWindow general-purpose functions 325 * 326 ************************************************/ 327 void ungrabInputImpl() { 328 hide(); 329 } 330 331 /************************************************ 332 * 333 * Overriden XWindow keyboard processing 334 * 335 ************************************************/ 336 337 /* 338 * In previous version keys were handled in handleKeyPress. 339 * Now we override this function do disable F10 explicit 340 * processing. All processing is done using KeyEvent. 341 */ 342 public void handleKeyPress(XEvent xev) { 343 XKeyEvent xkey = xev.get_xkey(); 344 if (log.isLoggable(PlatformLogger.FINE)) { 345 log.fine(xkey.toString()); 346 } 347 if (isEventDisabled(xev)) { 348 return; 349 } 350 final Component currentSource = (Component)getEventSource(); 351 handleKeyPress(xkey); 352 } 353 354 }