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