1 /*
2  * Copyright (c) 2002, 2013, 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      ************************************************/
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      */
setFont(Font f)82     public void setFont(Font f) {
83         resetMapping();
84         setItemsFont(f);
85         postPaintEvent();
86     }
87 
88     /*
89      * From MenuItemPeer
90      */
setLabel(String label)91     public void setLabel(String label) {
92         resetMapping();
93         postPaintEvent();
94     }
95 
96 
setEnabled(boolean enabled)97     public void setEnabled(boolean enabled) {
98         postPaintEvent();
99     }
100 
101     /**
102      * DEPRECATED:  Replaced by setEnabled(boolean).
103      * @see java.awt.peer.MenuItemPeer
104      */
enable()105     public void enable() {
106         setEnabled( true );
107     }
108 
109     /**
110      * DEPRECATED:  Replaced by setEnabled(boolean).
111      * @see java.awt.peer.MenuItemPeer
112      */
disable()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      */
addSeparator()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      */
show(Event e)134     public void show(Event e) {
135         target = (Component)e.target;
136         // Get menus from the target.
137         Vector 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
getTargetFont()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
getTargetLabel()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)
isTargetEnabled()184     boolean isTargetEnabled() {
185         if (popupMenuTarget == null) {
186             return false;
187         }
188         return AWTAccessor.getMenuItemAccessor().isEnabled(popupMenuTarget);
189     }
190 
getMenuTargetItems()191     Vector 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      */
getWindowBounds(Point origin, Dimension windowSize)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      */
getCaptionSize()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      */
paintCaption(Graphics g, Rectangle rect)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      ************************************************/
doDispose()298     protected void doDispose() {
299         super.doDispose();
300         XToolkit.targetDisposedPeer(popupMenuTarget, this);
301     }
302 
handleEvent(AWTEvent event)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      ************************************************/
ungrabInputImpl()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      */
handleKeyPress(XEvent xev)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 = (Component)getEventSource();
353         handleKeyPress(xkey);
354     }
355 
356 }
357