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