1 /* 2 * Copyright (c) 2002, 2014, 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 static final int CAPTION_MARGIN_TOP = 4; 62 private static final 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.Level.FINER)) { 127 log.finer("addSeparator is not implemented"); 128 } 129 } 130 131 /* 132 * From PopupMenuPeer 133 */ 134 public void show(Event e) { 135 target = (Component)e.target; 136 // Get menus from the target. 137 Vector<MenuItem> targetItemVector = getMenuTargetItems(); 138 if (targetItemVector != null) { 139 reloadItems(targetItemVector); 140 //Fix for 6287092: JCK15a: api/java_awt/interactive/event/EventTests.html#EventTest0015 fails, mustang 141 Point tl = target.getLocationOnScreen(); 142 Point pt = new Point(tl.x + e.x, tl.y + e.y); 143 //Fixed 6266513: Incorrect key handling in XAWT popup menu 144 //No item should be selected when showing popup menu 145 if (!ensureCreated()) { 146 return; 147 } 148 Dimension dim = getDesiredSize(); 149 //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened 150 //near the periphery of the screen, XToolkit 151 Rectangle bounds = getWindowBounds(pt, dim); 152 reshape(bounds); 153 xSetVisible(true); 154 toFront(); 155 selectItem(null, false); 156 grabInput(); 157 } 158 } 159 160 /************************************************ 161 * 162 * Access to target's fields 163 * 164 ************************************************/ 165 166 //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit 167 Font getTargetFont() { 168 if (popupMenuTarget == null) { 169 return XWindow.getDefaultFont(); 170 } 171 return AWTAccessor.getMenuComponentAccessor() 172 .getFont_NoClientCode(popupMenuTarget); 173 } 174 175 //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit 176 String getTargetLabel() { 177 if (target == null) { 178 return ""; 179 } 180 return AWTAccessor.getMenuItemAccessor().getLabel(popupMenuTarget); 181 } 182 183 //Fix for 6184485: Popup menu is not disabled on XToolkit even when calling setEnabled (false) 184 boolean isTargetEnabled() { 185 if (popupMenuTarget == null) { 186 return false; 187 } 188 return AWTAccessor.getMenuItemAccessor().isEnabled(popupMenuTarget); 189 } 190 191 Vector<MenuItem> getMenuTargetItems() { 192 if (popupMenuTarget == null) { 193 return null; 194 } 195 return AWTAccessor.getMenuAccessor().getItems(popupMenuTarget); 196 } 197 198 /************************************************ 199 * 200 * Utility functions 201 * 202 ************************************************/ 203 204 //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened 205 //near the periphery of the screen, XToolkit 206 207 /** 208 * Calculates placement of popup menu window 209 * given origin in global coordinates and 210 * size of menu window. Returns suggested 211 * rectangle for menu window in global coordinates 212 * @param origin the origin point specified in show() 213 * function converted to global coordinates 214 * @param windowSize the desired size of menu's window 215 */ 216 protected Rectangle getWindowBounds(Point origin, Dimension windowSize) { 217 Rectangle globalBounds = new Rectangle(origin.x, origin.y, 0, 0); 218 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 219 Rectangle res; 220 res = fitWindowRight(globalBounds, windowSize, screenSize); 221 if (res != null) { 222 return res; 223 } 224 res = fitWindowLeft(globalBounds, windowSize, screenSize); 225 if (res != null) { 226 return res; 227 } 228 res = fitWindowBelow(globalBounds, windowSize, screenSize); 229 if (res != null) { 230 return res; 231 } 232 res = fitWindowAbove(globalBounds, windowSize, screenSize); 233 if (res != null) { 234 return res; 235 } 236 return fitWindowToScreen(windowSize, screenSize); 237 } 238 239 /************************************************ 240 * 241 * Overriden XMenuWindow caption-painting functions 242 * Necessary to fix 6267144: PIT: Popup menu label is not shown, XToolkit 243 * 244 ************************************************/ 245 /** 246 * Returns height of menu window's caption. 247 * Can be overriden for popup menus and tear-off menus 248 */ 249 protected Dimension getCaptionSize() { 250 String s = getTargetLabel(); 251 if (s.equals("")) { 252 return null; 253 } 254 Graphics g = getGraphics(); 255 if (g == null) { 256 return null; 257 } 258 try { 259 g.setFont(getTargetFont()); 260 FontMetrics fm = g.getFontMetrics(); 261 String str = getTargetLabel(); 262 int width = fm.stringWidth(str); 263 int height = CAPTION_MARGIN_TOP + fm.getHeight() + CAPTION_SEPARATOR_HEIGHT; 264 Dimension textDimension = new Dimension(width, height); 265 return textDimension; 266 } finally { 267 g.dispose(); 268 } 269 } 270 271 /** 272 * Paints menu window's caption. 273 * Can be overriden for popup menus and tear-off menus. 274 * Default implementation does nothing 275 */ 276 protected void paintCaption(Graphics g, Rectangle rect) { 277 String s = getTargetLabel(); 278 if (s.equals("")) { 279 return; 280 } 281 g.setFont(getTargetFont()); 282 FontMetrics fm = g.getFontMetrics(); 283 String str = getTargetLabel(); 284 int width = fm.stringWidth(str); 285 int textx = rect.x + (rect.width - width) / 2; 286 int texty = rect.y + CAPTION_MARGIN_TOP + fm.getAscent(); 287 int sepy = rect.y + rect.height - CAPTION_SEPARATOR_HEIGHT / 2; 288 g.setColor(isTargetEnabled() ? getForegroundColor() : getDisabledColor()); 289 g.drawString(s, textx, texty); 290 draw3DRect(g, rect.x, sepy, rect.width, 2, false); 291 } 292 293 /************************************************ 294 * 295 * Overriden XBaseMenuWindow functions 296 * 297 ************************************************/ 298 protected void doDispose() { 299 super.doDispose(); 300 XToolkit.targetDisposedPeer(popupMenuTarget, this); 301 } 302 303 protected void handleEvent(AWTEvent event) { 304 switch(event.getID()) { 305 case MouseEvent.MOUSE_PRESSED: 306 case MouseEvent.MOUSE_RELEASED: 307 case MouseEvent.MOUSE_CLICKED: 308 case MouseEvent.MOUSE_MOVED: 309 case MouseEvent.MOUSE_ENTERED: 310 case MouseEvent.MOUSE_EXITED: 311 case MouseEvent.MOUSE_DRAGGED: 312 doHandleJavaMouseEvent((MouseEvent)event); 313 break; 314 case KeyEvent.KEY_PRESSED: 315 case KeyEvent.KEY_RELEASED: 316 doHandleJavaKeyEvent((KeyEvent)event); 317 break; 318 default: 319 super.handleEvent(event); 320 break; 321 } 322 } 323 324 /************************************************ 325 * 326 * Overriden XWindow general-purpose functions 327 * 328 ************************************************/ 329 void ungrabInputImpl() { 330 hide(); 331 } 332 333 /************************************************ 334 * 335 * Overriden XWindow keyboard processing 336 * 337 ************************************************/ 338 339 /* 340 * In previous version keys were handled in handleKeyPress. 341 * Now we override this function do disable F10 explicit 342 * processing. All processing is done using KeyEvent. 343 */ 344 public void handleKeyPress(XEvent xev) { 345 XKeyEvent xkey = xev.get_xkey(); 346 if (log.isLoggable(PlatformLogger.Level.FINE)) { 347 log.fine(xkey.toString()); 348 } 349 if (isEventDisabled(xev)) { 350 return; 351 } 352 final Component currentSource = getEventSource(); 353 handleKeyPress(xkey); 354 } 355 356 }