### Eclipse Workspace Patch 1.0 #P org.eclipse.swt.snippets Index: src/org/eclipse/swt/snippets/Snippet140.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet140.java,v retrieving revision 1.4 diff -u -r1.4 Snippet140.java --- src/org/eclipse/swt/snippets/Snippet140.java 16 Sep 2005 19:24:39 -0000 1.4 +++ src/org/eclipse/swt/snippets/Snippet140.java 5 Mar 2008 06:33:25 -0000 @@ -51,47 +51,44 @@ coolItem.setMinimumSize(minWidth, coolSize.y); coolItem.setPreferredSize(coolSize); coolItem.setSize(coolSize); - coolItem.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent event) { - if (event.detail == SWT.ARROW) { - CoolItem item = (CoolItem) event.widget; - Rectangle itemBounds = item.getBounds (); - Point pt = coolBar.toDisplay(new Point(itemBounds.x, itemBounds.y)); - itemBounds.x = pt.x; - itemBounds.y = pt.y; - ToolBar bar = (ToolBar) item.getControl (); - ToolItem[] tools = bar.getItems (); + coolItem.addMenuDetectListener(new MenuDetectListener() { + public void menuDetected(MenuDetectEvent event) { + CoolItem item = (CoolItem) event.widget; + Rectangle itemBounds = item.getBounds (); + Point pt = coolBar.toDisplay(new Point(itemBounds.x, itemBounds.y)); + itemBounds.x = pt.x; + itemBounds.y = pt.y; + ToolBar bar = (ToolBar) item.getControl (); + ToolItem[] tools = bar.getItems (); + + int i = 0; + while (i < tools.length) { + Rectangle toolBounds = tools[i].getBounds (); + pt = bar.toDisplay(new Point(toolBounds.x, toolBounds.y)); + toolBounds.x = pt.x; + toolBounds.y = pt.y; - int i = 0; - while (i < tools.length) { - Rectangle toolBounds = tools[i].getBounds (); - pt = bar.toDisplay(new Point(toolBounds.x, toolBounds.y)); - toolBounds.x = pt.x; - toolBounds.y = pt.y; - - /* Figure out the visible portion of the tool by looking at the - * intersection of the tool bounds with the cool item bounds. */ - Rectangle intersection = itemBounds.intersection (toolBounds); - - /* If the tool is not completely within the cool item bounds, then it - * is partially hidden, and all remaining tools are completely hidden. */ - if (!intersection.equals (toolBounds)) break; - i++; - } + /* Figure out the visible portion of the tool by looking at the + * intersection of the tool bounds with the cool item bounds. */ + Rectangle intersection = itemBounds.intersection (toolBounds); - /* Create a menu with items for each of the completely hidden buttons. */ - if (chevronMenu != null) chevronMenu.dispose(); - chevronMenu = new Menu (coolBar); - for (int j = i; j < tools.length; j++) { - MenuItem menuItem = new MenuItem (chevronMenu, SWT.PUSH); - menuItem.setText (tools[j].getText()); - } - - /* Drop down the menu below the chevron, with the left edges aligned. */ - pt = coolBar.toDisplay(new Point(event.x, event.y)); - chevronMenu.setLocation (pt.x, pt.y); - chevronMenu.setVisible (true); + /* If the tool is not completely within the cool item bounds, then it + * is partially hidden, and all remaining tools are completely hidden. */ + if (!intersection.equals (toolBounds)) break; + i++; + } + + /* Create a menu with items for each of the completely hidden buttons. */ + if (chevronMenu != null) chevronMenu.dispose(); + chevronMenu = new Menu (coolBar); + for (int j = i; j < tools.length; j++) { + MenuItem menuItem = new MenuItem (chevronMenu, SWT.PUSH); + menuItem.setText (tools[j].getText()); } + + /* Drop down the menu below the chevron, with the left edges aligned. */ + pt = coolBar.toDisplay(new Point(event.x, event.y)); + item.setMenu(chevronMenu); } }); Index: src/org/eclipse/swt/snippets/Snippet67.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet67.java,v retrieving revision 1.3 diff -u -r1.3 Snippet67.java --- src/org/eclipse/swt/snippets/Snippet67.java 16 Sep 2005 19:24:37 -0000 1.3 +++ src/org/eclipse/swt/snippets/Snippet67.java 5 Mar 2008 06:33:25 -0000 @@ -32,17 +32,7 @@ item.setText ("Item " + i); } final ToolItem item = new ToolItem (toolBar, SWT.DROP_DOWN); - item.addListener (SWT.Selection, new Listener () { - public void handleEvent (Event event) { - if (event.detail == SWT.ARROW) { - Rectangle rect = item.getBounds (); - Point pt = new Point (rect.x, rect.y + rect.height); - pt = toolBar.toDisplay (pt); - menu.setLocation (pt.x, pt.y); - menu.setVisible (true); - } - } - }); + item.setMenu(menu); toolBar.pack (); shell.pack (); shell.open (); Index: src/org/eclipse/swt/snippets/Snippet67x.java =================================================================== RCS file: src/org/eclipse/swt/snippets/Snippet67x.java diff -N src/org/eclipse/swt/snippets/Snippet67x.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/swt/snippets/Snippet67x.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.snippets; + +/* + * ToolBar example snippet: place a drop down menu in a tool bar + * + * For a list of all SWT example snippets see + * http://www.eclipse.org/swt/snippets/ + */ +import java.util.Date; +import java.util.Random; + +import org.eclipse.swt.*; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.MenuDetectEvent; +import org.eclipse.swt.events.MenuDetectListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.widgets.*; + +public class Snippet67x { + +public static void main (String [] args) { + final Display display = new Display (); + final Shell shell = new Shell (display); + final ToolBar toolBar = new ToolBar (shell, SWT.FLAT); + toolBar.addMouseListener(new MouseAdapter() { + + public void mouseDown(MouseEvent e) { + long time = e.time & 0xFFFFFFFFL; + System.out.println("mousedown " + new Date(time)); + } + + public void mouseDoubleClick(MouseEvent e) { + long time = e.time & 0xFFFFFFFFL; + System.out.println("mousedblclick"); + } + + public void mouseUp(MouseEvent e) { + long time = e.time & 0xFFFFFFFFL; + System.out.println("mouseup " + new Date(time)); + } + + }); + toolBar.addKeyListener(new KeyAdapter() { + + public void keyPressed(KeyEvent e) { + System.out.println("keypressed"); + } + + public void keyReleased(KeyEvent e) { + System.out.println("keyreleased"); + } + + }); + final Menu menu = new Menu (shell, SWT.POP_UP); + for (int i=0; i<8; i++) { + MenuItem item = new MenuItem (menu, SWT.PUSH); + item.setText ("Item " + i); + } + final ToolItem item = new ToolItem (toolBar, SWT.DROP_DOWN); + item.addMenuDetectListener(new MenuDetectListener() { + + public void menuDetected(MenuDetectEvent e) { + System.out.println("menudetectdropdown"); + } + + }); + item.setText("My Item"); + item.setMenu(menu); + final ToolItem item2 = new ToolItem (toolBar, SWT.PUSH, 0); + item2.setText("theone"); + item2.addSelectionListener(new SelectionListener() { + + public void widgetSelected(SelectionEvent e) { + System.out.println("sel"); + } + + public void widgetDefaultSelected(SelectionEvent e) { + System.out.println("default sel"); + } + + }); + item2.addMenuDetectListener(new MenuDetectListener(){ + + public void menuDetected(MenuDetectEvent event) { + System.out.println("menudetect"); + if (false) { + event.doit = false; + } else { + if (item2.getMenu() != null) { + item2.getMenu().dispose(); + } + final Menu menu = new Menu (shell, SWT.POP_UP); + for (int i=0; i<8; i++) { + MenuItem item = new MenuItem (menu, SWT.PUSH); + item.setText ("Item " + new Random().nextInt(10)); + } + item2.setMenu(menu); + } + } + + }); + toolBar.pack (); + + Button btn = new Button(shell, SWT.PUSH); + btn.setLocation(120, 00); + btn.setText("Hello"); + btn.pack(); + + shell.pack (); + shell.open (); + while (!shell.isDisposed ()) { + if (!display.readAndDispatch ()) display.sleep (); + } + menu.dispose (); + display.dispose (); +} +} #P org.eclipse.swt.tools Index: JNI Generation/org/eclipse/swt/tools/internal/org.eclipse.swt.internal.win32.OS.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/org.eclipse.swt.internal.win32.OS.properties,v retrieving revision 1.131 diff -u -r1.131 org.eclipse.swt.internal.win32.OS.properties --- JNI Generation/org/eclipse/swt/tools/internal/org.eclipse.swt.internal.win32.OS.properties 11 Jan 2008 16:20:40 -0000 1.131 +++ JNI Generation/org/eclipse/swt/tools/internal/org.eclipse.swt.internal.win32.OS.properties 5 Mar 2008 06:33:26 -0000 @@ -4757,6 +4757,8 @@ OS_TOOLINFO_sizeof= +OS_TPMPARAMS_sizeof= + OS_TRACKMOUSEEVENT_sizeof= OS_TRIVERTEX_sizeof= @@ -4798,6 +4800,14 @@ OS_TrackPopupMenu_5=cast=(HWND) OS_TrackPopupMenu_6= +OS_TrackPopupMenuEx= +OS_TrackPopupMenuEx_0=cast=(HMENU) +OS_TrackPopupMenuEx_1= +OS_TrackPopupMenuEx_2= +OS_TrackPopupMenuEx_3= +OS_TrackPopupMenuEx_4=cast=(HWND) +OS_TrackPopupMenuEx_5= + OS_TranslateAcceleratorA= OS_TranslateAcceleratorA_0=cast=(HWND) OS_TranslateAcceleratorA_1=cast=(HACCEL) @@ -5450,6 +5460,13 @@ TOOLINFO_lParam= TOOLINFO_lpReserved=cast=(void *) +org_eclipse_swt_internal_win32_TPMPARAMS= +TPMPARAMS_cbSize= +TPMPARAMS_left=accessor=rcExclude.left +TPMPARAMS_top=accessor=rcExclude.top +TPMPARAMS_right=accessor=rcExclude.right +TPMPARAMS_bottom=accessor=rcExclude.bottom + org_eclipse_swt_internal_win32_TRACKMOUSEEVENT= TRACKMOUSEEVENT_cbSize= TRACKMOUSEEVENT_dwFlags= #P org.eclipse.swt Index: Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java,v retrieving revision 1.71 diff -u -r1.71 ToolItem.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java 10 Jul 2007 15:46:19 -0000 1.71 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java 5 Mar 2008 06:33:35 -0000 @@ -39,6 +39,7 @@ String toolTipText; Image disabledImage, hotImage; Image disabledImage2; + Menu menu; int id; /** @@ -125,6 +126,34 @@ /** * Adds the listener to the collection of listeners who will + * be notified when the platform-specific drop-down menu trigger + * has occurred, by sending it one of the messages defined in + * the MenuDetectListener interface. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException + * @exception SWTException + * + * @see MenuDetectListener + * @see #removeMenuDetectListener + * + * @since 3.4 + */ +public void addMenuDetectListener (MenuDetectListener listener) { + checkWidget (); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (SWT.MenuDetect, typedListener); +} + +/** + * Adds the listener to the collection of listeners who will * be notified when the control is selected by the user, by sending * it one of the messages defined in the SelectionListener * interface. @@ -298,6 +327,26 @@ } /** + * Returns the receiver's drop-down menu if it has one, or null + * if it does not. + *

+ * The drop-down menu is activated when the arrow of an {@link SWT#DROP_DOWN}-styled receiver is pressed. + *

+ * + * @return the receiver's drop-down menu + * @exception SWTException + * + * @since 3.4 + */ +public Menu getMenu () { + checkWidget(); + return menu; +} + +/** * Returns the receiver's parent, which must be a ToolBar. * * @return the receiver's parent @@ -394,6 +443,10 @@ void releaseWidget () { super.releaseWidget (); releaseImages (); + if (menu != null && !menu.isDisposed ()) { + menu.dispose (); + } + menu = null; control = null; toolTipText = null; disabledImage = hotImage = null; @@ -435,6 +488,33 @@ /** * Removes the listener from the collection of listeners who will + * be notified when the platform-specific drop-down menu trigger has + * occurred. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException + * @exception SWTException + * + * @see MenuDetectListener + * @see #addMenuDetectListener + * + * @since 3.4 + */ +public void removeMenuDetectListener (MenuDetectListener listener) { + checkWidget (); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) return; + eventTable.unhook (SWT.MenuDetect, listener); +} + +/** + * Removes the listener from the collection of listeners who will * be notified when the control is selected by the user. * * @param listener the listener which should no longer be notified @@ -670,6 +750,39 @@ updateImages (getEnabled () && parent.getEnabled ()); } +/** + * Sets the receiver's drop-down menu to the argument, which may be + * null indicating that no drop-down menu should be displayed. + *

+ * If this property is null a drop-down menu can still be displayed manually by adding a + * {@link SelectionListener} to the receiver and handling{@link SWT#ARROW} events. + *

+ * The drop-down menu is activated when the arrow of an {@link SWT#DROP_DOWN}-styled + * receiver or any portion of an {@link SWT#PUSH}-styled receiver is pressed. + *

+ * + * @param menu the drop-down menu to be displayed when the receiver's arrow is pressed + * @exception SWTException + * + * @since 3.4 + */ +public void setMenu (Menu menu) { + checkWidget(); + if (menu != null) { + if (menu.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if ((menu.style & SWT.POP_UP) == 0) { + error (SWT.ERROR_MENU_NOT_POP_UP); + } + if (menu.parent != parent.menuShell ()) { + error (SWT.ERROR_INVALID_PARENT); + } + } + this.menu = menu; +} + boolean setRadioSelection (boolean value) { if ((style & SWT.RADIO) == 0) return false; if (getSelection () != value) { Index: Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java,v retrieving revision 1.118 diff -u -r1.118 ToolBar.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java 10 Jul 2007 15:46:19 -0000 1.118 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java 5 Mar 2008 06:33:35 -0000 @@ -44,6 +44,7 @@ ToolItem [] items; boolean ignoreResize, ignoreMouse; ImageList imageList, disabledImageList, hotImageList; + boolean showingPushItemMenu; static final int /*long*/ ToolBarProc; static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true); static { @@ -1018,6 +1019,9 @@ } LRESULT WM_CAPTURECHANGED (int /*long*/ wParam, int /*long*/ lParam) { + // Do not unpress the selected item while its menu is showing + // (if we call the super method, the ToolBar window procedure will unpress the item too). + if (showingPushItemMenu) return LRESULT.ZERO; LRESULT result = super.WM_CAPTURECHANGED (wParam, lParam); if (result != null) return result; /* @@ -1119,6 +1123,22 @@ * application the opportunity to cancel the operation. */ return LRESULT.ZERO; + case OS.VK_DOWN: + case OS.VK_UP: + /* + * Menus of SWT.DROPDOWN items are automatically triggered by Windows on the + * UP and DOWN keys. Here we mirror this behavior for PUSH items. + */ + int itemIndex = (int)/*64*/OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0); + ToolItem child = getEnabledPushItem (itemIndex); + if (child != null) { + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, itemIndex, rect); + if (sendItemMenuDetectEvent (child, rect, 0)) { + showPushItemMenu (child, rect); + return LRESULT.ZERO; + } + } } return result; } @@ -1131,7 +1151,42 @@ return super.WM_KILLFOCUS (wParam, lParam); } +LRESULT WM_LBUTTONDBLCLK (int /*long*/ wParam, int /*long*/ lParam) { + // Handle menu display for push items + POINT point = new POINT (); + point.x = OS.GET_X_LPARAM (lParam); + point.y = OS.GET_Y_LPARAM (lParam); + int itemIndex = (int)/*64*/OS.SendMessage (handle, OS.TB_HITTEST, 0, point); + ToolItem child = getEnabledPushItem (itemIndex); + if (child != null) { + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, itemIndex, rect); + if (sendItemMenuDetectEvent (child, rect, 0)) { + super.WM_LBUTTONDBLCLK (wParam, lParam); + showPushItemMenu (child, rect); + return LRESULT.ZERO; + } + } + return super.WM_LBUTTONDBLCLK (wParam, lParam); +} + LRESULT WM_LBUTTONDOWN (int /*long*/ wParam, int /*long*/ lParam) { + // Handle menu display for push items + POINT point = new POINT (); + point.x = OS.GET_X_LPARAM (lParam); + point.y = OS.GET_Y_LPARAM (lParam); + int itemIndex = (int)/*64*/OS.SendMessage (handle, OS.TB_HITTEST, 0, point); + ToolItem child = getEnabledPushItem (itemIndex); + if (child != null) { + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, itemIndex, rect); + if (sendItemMenuDetectEvent (child, rect, 0)) { + super.WM_LBUTTONDOWN (wParam, lParam); + showPushItemMenu (child, rect); + return LRESULT.ZERO; + } + } + if (ignoreMouse) return null; return super.WM_LBUTTONDOWN (wParam, lParam); } @@ -1299,14 +1354,18 @@ OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof); ToolItem child = items [lpnmtb.iItem]; if (child != null) { - Event event = new Event (); - event.detail = SWT.ARROW; int index = (int)/*64*/OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmtb.iItem, 0); RECT rect = new RECT (); OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect); - event.x = rect.left; - event.y = rect.bottom; - child.postEvent (SWT.Selection, event); + if (sendItemMenuDetectEvent (child, rect, SWT.ARROW)) { + showItemMenu (child, rect); + } else { + Event event = new Event (); + event.detail = SWT.ARROW; + event.x = rect.left; + event.y = rect.bottom; + child.postEvent (SWT.Selection, event); + } } break; case OS.NM_CUSTOMDRAW: @@ -1363,4 +1422,69 @@ return super.wmNotifyChild (hdr, wParam, lParam); } +private ToolItem getEnabledPushItem (int itemIndex) { + // Inspect non-separator item under the cursor + if (itemIndex >= 0) { + // Get item instance + TBBUTTON button = new TBBUTTON (); + OS.SendMessage (handle, OS.TB_GETBUTTON, itemIndex, button); + int buttonId = button.idCommand; + ToolItem child = items[buttonId]; + // Only allow menu display for PUSH items + final int toolItemStyleMask = SWT.PUSH | SWT.CHECK | SWT.RADIO + | SWT.SEPARATOR | SWT.DROP_DOWN; + if ((child.style & toolItemStyleMask) == SWT.PUSH) { + // Get item state + int itemState = (int)/*64*/OS.SendMessage (handle, OS.TB_GETSTATE, buttonId, 0); + // Only attempt to show a menu if the item is enabled + if ((itemState & OS.TBSTATE_ENABLED) != 0) { + return child; + } + } + } + return null; +} + +private void showPushItemMenu (ToolItem child, RECT rect) { + // Press item + int itemState = (int)/*64*/OS.SendMessage (handle, OS.TB_GETSTATE, child.id, 0); + itemState |= OS.TBSTATE_PRESSED; + OS.SendMessage (handle, OS.TB_SETSTATE, child.id, itemState); + // Show menu + showingPushItemMenu = true; + showItemMenu (child, rect); + showingPushItemMenu = false; + // Unpress item - reload item state since it may have changed + itemState = (int)/*64*/OS.SendMessage (handle, OS.TB_GETSTATE, child.id, 0); + itemState &= ~OS.TBSTATE_PRESSED; + OS.SendMessage (handle, OS.TB_SETSTATE, child.id, itemState); + // If the menu was cancelled by an LBUTTONDOWN event on the control, discard that event. + // This allows the menu to be closed on a second click. + OS.PeekMessage (new MSG (), handle, OS.WM_LBUTTONDOWN, OS.WM_LBUTTONDOWN, OS.PM_REMOVE); + // Force a redraw of the item. Otherwise, if the user cancels the menu by clicking and holding + // the left mouse button over the (non-client) title bar of a window + // that belongs to this application, the item will only get unpressed after a short delay. + OS.RedrawWindow (handle, rect, 0, OS.RDW_UPDATENOW); +} + +private boolean sendItemMenuDetectEvent (ToolItem child, RECT rect, int detail) { + Event event = new Event (); + event.detail = detail; + event.x = rect.left; + event.y = rect.bottom; + child.sendEvent (SWT.MenuDetect, event); + Menu menu = child.menu; + return event.doit && menu != null && !menu.isDisposed (); +} + +private void showItemMenu (ToolItem child, RECT rect) { + Menu menu = child.menu; + // Without this call, an lbuttondown event that triggers the menu + // will not be delivered to EventListeners until after the menu has been closed. + display.runDeferredEvents (); + OS.MapWindowPoints (handle, 0, rect, 2); + menu.setLocation (rect.left, rect.bottom); + menu._setVisible (true, rect, OS.TPM_VERTICAL); +} + } Index: Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java,v retrieving revision 1.117 diff -u -r1.117 Menu.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java 20 Dec 2007 03:08:18 -0000 1.117 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java 5 Mar 2008 06:33:34 -0000 @@ -213,7 +213,11 @@ createWidget (); } -void _setVisible (boolean visible) { +public void _setVisible (boolean visible) { + _setVisible(visible, null, 0); +} + +void _setVisible (boolean visible, RECT excludeRect, int extraFlags) { if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return; int /*long*/ hwndParent = parent.handle; if (visible) { @@ -224,6 +228,7 @@ flags &= ~OS.TPM_RIGHTALIGN; if ((style & SWT.LEFT_TO_RIGHT) != 0) flags |= OS.TPM_RIGHTALIGN; } + flags |= extraFlags; int nX = x, nY = y; if (!hasLocation) { int pos = OS.GetMessagePos (); @@ -243,7 +248,18 @@ * the case when TrackPopupMenu() fails and the number of items in * the menu is zero and issue a fake WM_MENUSELECT. */ - boolean success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null); + boolean success; + if (excludeRect == null) { + success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null); + } else { + TPMPARAMS lptpm = new TPMPARAMS(); + lptpm.cbSize = TPMPARAMS.sizeof; + lptpm.left = excludeRect.left; + lptpm.top = excludeRect.top; + lptpm.right = excludeRect.right; + lptpm.bottom = excludeRect.bottom; + success = OS.TrackPopupMenuEx (handle, flags, nX, nY, hwndParent, lptpm); + } if (!success && GetMenuItemCount (handle) == 0) { OS.SendMessage (hwndParent, OS.WM_MENUSELECT, OS.MAKEWPARAM (0, 0xFFFF), 0); } Index: Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java,v retrieving revision 1.103 diff -u -r1.103 CoolBar.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java 10 Jul 2007 15:46:18 -0000 1.103 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/CoolBar.java 5 Mar 2008 06:33:34 -0000 @@ -1156,7 +1156,23 @@ event.x = lpnm.left; event.y = lpnm.bottom; } - item.postEvent (SWT.Selection, event); + + if (sendItemMenuDetectEvent (item, event.x, event.y, SWT.ARROW)) { + // Without this call, an lbuttondown event that triggers the menu + // will not be delivered to EventListeners until after the menu has been closed. + display.runDeferredEvents (); + RECT rect = new RECT (); + rect.top = lpnm.top; + rect.bottom = lpnm.bottom; + rect.left = lpnm.left; + rect.right = lpnm.right; + showItemMenu (item, rect); + // If the menu was cancelled by an LBUTTONDOWN event on the control, discard that event. + // This allows the menu to be closed on a second click. + OS.PeekMessage (new MSG (), handle, OS.WM_LBUTTONDOWN, OS.WM_LBUTTONDOWN, OS.PM_REMOVE); + } else { + item.postEvent (SWT.Selection, event); + } } break; } @@ -1184,4 +1200,33 @@ } return super.wmNotifyChild (hdr, wParam, lParam); } + +private void showItemMenu (CoolItem child, RECT rect) { + Menu menu = child.menu; + OS.MapWindowPoints (handle, 0, rect, 2); + int x, y; + int menuPosition; + if ((style & SWT.VERTICAL) != 0) { + x = rect.right; + y = rect.top; + menuPosition = OS.TPM_HORIZONTAL; + } else { + x = rect.left; + y = rect.bottom; + menuPosition = OS.TPM_VERTICAL; + } + menu.setLocation (x, y); + menu._setVisible (true, rect, menuPosition); +} + +private boolean sendItemMenuDetectEvent (CoolItem child, int x, int y, int detail) { + Event event = new Event (); + event.detail = detail; + event.x = x; + event.y = y; + child.sendEvent (SWT.MenuDetect, event); + Menu menu = child.menu; + return event.doit && menu != null && !menu.isDisposed (); +} + } Index: Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java,v retrieving revision 1.54 diff -u -r1.54 CoolItem.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java 10 Jul 2007 15:46:18 -0000 1.54 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java 5 Mar 2008 06:33:34 -0000 @@ -34,6 +34,7 @@ public class CoolItem extends Item { CoolBar parent; Control control; + Menu menu; int id; boolean ideal, minimum; @@ -112,6 +113,34 @@ } /** + * Adds the listener to the collection of listeners who will + * be notified when the platform-specific chevron menu trigger + * has occurred, by sending it one of the messages defined in + * the MenuDetectListener interface. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException + * @exception SWTException + * + * @see MenuDetectListener + * @see #removeMenuDetectListener + * + * @since 3.4 + */ +public void addMenuDetectListener (MenuDetectListener listener) { + checkWidget (); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (SWT.MenuDetect, typedListener); +} + +/** * Adds the listener to the collection of listeners that will * be notified when the control is selected by the user, by sending it one * of the messages defined in the SelectionListener @@ -279,6 +308,23 @@ } /** + * Returns the receiver's chevron menu if it has one, or null + * if it does not. + * + * @return the receiver's drop-down menu + * @exception SWTException + * + * @since 3.4 + */ +public Menu getMenu () { + checkWidget(); + return menu; +} + +/** * Returns the receiver's parent, which must be a CoolBar. * * @return the receiver's parent @@ -293,6 +339,14 @@ return parent; } +void releaseWidget () { + super.releaseWidget (); + if (menu != null && !menu.isDisposed ()) { + menu.dispose (); + } + menu = null; +} + void releaseHandle () { super.releaseHandle (); parent = null; @@ -357,6 +411,35 @@ } /** + * Sets the receiver's chevron menu to the argument, which may be + * null indicating that no drop-down menu should be displayed. + *

+ * If this property is null a drop-down menu can still be displayed manually by adding a + * {@link SelectionListener} to the receiver and handling{@link SWT#ARROW} events. + * + * @param menu the drop-down menu to be displayed when the receiver's arrow is pressed + * @exception SWTException

+ * + * @since 3.4 + */ +public void setMenu (Menu menu) { + checkWidget(); + if (menu != null) { + if (menu.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if ((menu.style & SWT.POP_UP) == 0) { + error (SWT.ERROR_MENU_NOT_POP_UP); + } + if (menu.parent != parent.menuShell ()) { + error (SWT.ERROR_INVALID_PARENT); + } + } + this.menu = menu; +} + +/** * Returns a point describing the receiver's ideal size. * The x coordinate of the result is the ideal width of the receiver. * The y coordinate of the result is the ideal height of the receiver. @@ -685,6 +768,33 @@ } /** + * Removes the listener from the collection of listeners who will + * be notified when the platform-specific chevron menu trigger has + * occurred. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException + * @exception SWTException + * + * @see MenuDetectListener + * @see #addMenuDetectListener + * + * @since 3.4 + */ +public void removeMenuDetectListener (MenuDetectListener listener) { + checkWidget (); + if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable == null) return; + eventTable.unhook (SWT.MenuDetect, listener); +} + +/** * Removes the listener from the collection of listeners that * will be notified when the control is selected by the user. * Index: Eclipse SWT PI/win32/library/os_stats.c =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.c,v retrieving revision 1.109 diff -u -r1.109 os_stats.c --- Eclipse SWT PI/win32/library/os_stats.c 25 Jan 2008 17:04:04 -0000 1.109 +++ Eclipse SWT PI/win32/library/os_stats.c 5 Mar 2008 06:33:30 -0000 @@ -14,8 +14,8 @@ #ifdef NATIVE_STATS -int OS_nativeFunctionCount = 930; -int OS_nativeFunctionCallCount[930]; +int OS_nativeFunctionCount = 932; +int OS_nativeFunctionCallCount[932]; char * OS_nativeFunctionNames[] = { "ACCEL_1sizeof", "ACTCTX_1sizeof", @@ -896,6 +896,7 @@ "TF_1DA_1COLOR_1sizeof", "TF_1DISPLAYATTRIBUTE_1sizeof", "TOOLINFO_1sizeof", + "TPMPARAMS_1sizeof", "TRACKMOUSEEVENT_1sizeof", "TRIVERTEX_1sizeof", "TVHITTESTINFO_1sizeof", @@ -907,6 +908,7 @@ "ToUnicode", "TrackMouseEvent", "TrackPopupMenu", + "TrackPopupMenuEx", "TranslateAcceleratorA", "TranslateAcceleratorW", "TranslateCharsetInfo", Index: Eclipse SWT PI/win32/library/os_structs.h =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.h,v retrieving revision 1.54 diff -u -r1.54 os_structs.h --- Eclipse SWT PI/win32/library/os_structs.h 26 Nov 2007 21:22:05 -0000 1.54 +++ Eclipse SWT PI/win32/library/os_structs.h 5 Mar 2008 06:33:32 -0000 @@ -1559,6 +1559,18 @@ #define TOOLINFO_sizeof() 0 #endif +#ifndef NO_TPMPARAMS +void cacheTPMPARAMSFields(JNIEnv *env, jobject lpObject); +TPMPARAMS *getTPMPARAMSFields(JNIEnv *env, jobject lpObject, TPMPARAMS *lpStruct); +void setTPMPARAMSFields(JNIEnv *env, jobject lpObject, TPMPARAMS *lpStruct); +#define TPMPARAMS_sizeof() sizeof(TPMPARAMS) +#else +#define cacheTPMPARAMSFields(a,b) +#define getTPMPARAMSFields(a,b,c) NULL +#define setTPMPARAMSFields(a,b,c) +#define TPMPARAMS_sizeof() 0 +#endif + #ifndef NO_TRACKMOUSEEVENT void cacheTRACKMOUSEEVENTFields(JNIEnv *env, jobject lpObject); TRACKMOUSEEVENT *getTRACKMOUSEEVENTFields(JNIEnv *env, jobject lpObject, TRACKMOUSEEVENT *lpStruct); Index: Eclipse SWT PI/win32/library/os_stats.h =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.h,v retrieving revision 1.109 diff -u -r1.109 os_stats.h --- Eclipse SWT PI/win32/library/os_stats.h 25 Jan 2008 17:04:04 -0000 1.109 +++ Eclipse SWT PI/win32/library/os_stats.h 5 Mar 2008 06:33:30 -0000 @@ -904,6 +904,7 @@ TF_1DA_1COLOR_1sizeof_FUNC, TF_1DISPLAYATTRIBUTE_1sizeof_FUNC, TOOLINFO_1sizeof_FUNC, + TPMPARAMS_1sizeof_FUNC, TRACKMOUSEEVENT_1sizeof_FUNC, TRIVERTEX_1sizeof_FUNC, TVHITTESTINFO_1sizeof_FUNC, @@ -915,6 +916,7 @@ ToUnicode_FUNC, TrackMouseEvent_FUNC, TrackPopupMenu_FUNC, + TrackPopupMenuEx_FUNC, TranslateAcceleratorA_FUNC, TranslateAcceleratorW_FUNC, TranslateCharsetInfo_FUNC, Index: Eclipse SWT PI/win32/library/os.c =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c,v retrieving revision 1.154 diff -u -r1.154 os.c --- Eclipse SWT PI/win32/library/os.c 25 Jan 2008 17:04:04 -0000 1.154 +++ Eclipse SWT PI/win32/library/os.c 5 Mar 2008 06:33:30 -0000 @@ -14133,6 +14133,18 @@ } #endif +#ifndef NO_TPMPARAMS_1sizeof +JNIEXPORT jint JNICALL OS_NATIVE(TPMPARAMS_1sizeof) + (JNIEnv *env, jclass that) +{ + jint rc = 0; + OS_NATIVE_ENTER(env, that, TPMPARAMS_1sizeof_FUNC); + rc = (jint)TPMPARAMS_sizeof(); + OS_NATIVE_EXIT(env, that, TPMPARAMS_1sizeof_FUNC); + return rc; +} +#endif + #ifndef NO_TRACKMOUSEEVENT_1sizeof JNIEXPORT jint JNICALL OS_NATIVE(TRACKMOUSEEVENT_1sizeof) (JNIEnv *env, jclass that) @@ -14287,6 +14299,22 @@ } #endif +#ifndef NO_TrackPopupMenuEx +JNIEXPORT jboolean JNICALL OS_NATIVE(TrackPopupMenuEx) + (JNIEnv *env, jclass that, jint arg0, jint arg1, jint arg2, jint arg3, jint arg4, jobject arg5) +{ + TPMPARAMS _arg5, *lparg5=NULL; + jboolean rc = 0; + OS_NATIVE_ENTER(env, that, TrackPopupMenuEx_FUNC); + if (arg5) if ((lparg5 = getTPMPARAMSFields(env, arg5, &_arg5)) == NULL) goto fail; + rc = (jboolean)TrackPopupMenuEx((HMENU)arg0, arg1, arg2, arg3, (HWND)arg4, lparg5); +fail: + if (arg5 && lparg5) setTPMPARAMSFields(env, arg5, lparg5); + OS_NATIVE_EXIT(env, that, TrackPopupMenuEx_FUNC); + return rc; +} +#endif + #ifndef NO_TranslateAcceleratorA JNIEXPORT jint JNICALL OS_NATIVE(TranslateAcceleratorA) (JNIEnv *env, jclass that, jint arg0, jint arg1, jobject arg2) Index: Eclipse SWT PI/win32/library/os_structs.c =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.c,v retrieving revision 1.65 diff -u -r1.65 os_structs.c --- Eclipse SWT PI/win32/library/os_structs.c 26 Nov 2007 21:22:05 -0000 1.65 +++ Eclipse SWT PI/win32/library/os_structs.c 5 Mar 2008 06:33:32 -0000 @@ -7386,6 +7386,49 @@ } #endif +#ifndef NO_TPMPARAMS +typedef struct TPMPARAMS_FID_CACHE { + int cached; + jclass clazz; + jfieldID cbSize, left, top, right, bottom; +} TPMPARAMS_FID_CACHE; + +TPMPARAMS_FID_CACHE TPMPARAMSFc; + +void cacheTPMPARAMSFields(JNIEnv *env, jobject lpObject) +{ + if (TPMPARAMSFc.cached) return; + TPMPARAMSFc.clazz = (*env)->GetObjectClass(env, lpObject); + TPMPARAMSFc.cbSize = (*env)->GetFieldID(env, TPMPARAMSFc.clazz, "cbSize", "I"); + TPMPARAMSFc.left = (*env)->GetFieldID(env, TPMPARAMSFc.clazz, "left", "I"); + TPMPARAMSFc.top = (*env)->GetFieldID(env, TPMPARAMSFc.clazz, "top", "I"); + TPMPARAMSFc.right = (*env)->GetFieldID(env, TPMPARAMSFc.clazz, "right", "I"); + TPMPARAMSFc.bottom = (*env)->GetFieldID(env, TPMPARAMSFc.clazz, "bottom", "I"); + TPMPARAMSFc.cached = 1; +} + +TPMPARAMS *getTPMPARAMSFields(JNIEnv *env, jobject lpObject, TPMPARAMS *lpStruct) +{ + if (!TPMPARAMSFc.cached) cacheTPMPARAMSFields(env, lpObject); + lpStruct->cbSize = (*env)->GetIntField(env, lpObject, TPMPARAMSFc.cbSize); + lpStruct->rcExclude.left = (*env)->GetIntField(env, lpObject, TPMPARAMSFc.left); + lpStruct->rcExclude.top = (*env)->GetIntField(env, lpObject, TPMPARAMSFc.top); + lpStruct->rcExclude.right = (*env)->GetIntField(env, lpObject, TPMPARAMSFc.right); + lpStruct->rcExclude.bottom = (*env)->GetIntField(env, lpObject, TPMPARAMSFc.bottom); + return lpStruct; +} + +void setTPMPARAMSFields(JNIEnv *env, jobject lpObject, TPMPARAMS *lpStruct) +{ + if (!TPMPARAMSFc.cached) cacheTPMPARAMSFields(env, lpObject); + (*env)->SetIntField(env, lpObject, TPMPARAMSFc.cbSize, (jint)lpStruct->cbSize); + (*env)->SetIntField(env, lpObject, TPMPARAMSFc.left, (jint)lpStruct->rcExclude.left); + (*env)->SetIntField(env, lpObject, TPMPARAMSFc.top, (jint)lpStruct->rcExclude.top); + (*env)->SetIntField(env, lpObject, TPMPARAMSFc.right, (jint)lpStruct->rcExclude.right); + (*env)->SetIntField(env, lpObject, TPMPARAMSFc.bottom, (jint)lpStruct->rcExclude.bottom); +} +#endif + #ifndef NO_TRACKMOUSEEVENT typedef struct TRACKMOUSEEVENT_FID_CACHE { int cached; Index: Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java,v retrieving revision 1.380 diff -u -r1.380 OS.java --- Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java 25 Jan 2008 17:04:04 -0000 1.380 +++ Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java 5 Mar 2008 06:33:34 -0000 @@ -1580,6 +1580,7 @@ public static final int TB_GETROWS = 0x428; public static final int TB_GETSTATE = 0x412; public static final int TB_GETTOOLTIPS = 0x423; + public static final int TB_HITTEST = 0x445; public static final int TB_INSERTBUTTON = IsUnicode ? 0x443 : 0x415; public static final int TB_LOADIMAGES = 0x432; public static final int TB_MAPACCELERATOR = 0x0400 + (IsUnicode ? 90 : 78); @@ -1665,6 +1666,8 @@ public static final int TPM_LEFTBUTTON = 0x0; public static final int TPM_RIGHTBUTTON = 0x2; public static final int TPM_RIGHTALIGN = 0x8; + public static final int TPM_HORIZONTAL = 0x00; + public static final int TPM_VERTICAL = 0x40; public static final String TRACKBAR_CLASS = "msctls_trackbar32"; //$NON-NLS-1$ public static final int TRANSPARENT = 0x1; public static final int TREIS_DISABLED = 4; @@ -2207,6 +2210,7 @@ public static final native int TF_DA_COLOR_sizeof (); public static final native int TF_DISPLAYATTRIBUTE_sizeof (); public static final native int TOOLINFO_sizeof (); +public static final native int TPMPARAMS_sizeof (); public static final native int TRACKMOUSEEVENT_sizeof (); public static final native int TRIVERTEX_sizeof (); public static final native int TVHITTESTINFO_sizeof (); @@ -3962,6 +3966,7 @@ public static final native boolean TreeView_GetItemRect (int /*long*/ hwndTV, int /*long*/ hitem, RECT prc, boolean fItemRect); public static final native boolean TrackMouseEvent (TRACKMOUSEEVENT lpEventTrack); public static final native boolean TrackPopupMenu (int /*long*/ hMenu, int uFlags, int x, int y, int nReserved, int /*long*/ hWnd, RECT prcRect); +public static final native boolean TrackPopupMenuEx (int /*long*/ hMenu, int uFlags, int x, int y, int /*long*/ hWnd, TPMPARAMS lptpm); public static final native int TranslateAcceleratorW (int /*long*/ hWnd, int /*long*/ hAccTable, MSG lpMsg); public static final native int TranslateAcceleratorA (int /*long*/ hWnd, int /*long*/ hAccTable, MSG lpMsg); public static final native boolean TranslateCharsetInfo (int /*long*/ lpSrc, int [] lpCs, int dwFlags); Index: Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/TPMPARAMS.java =================================================================== RCS file: Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/TPMPARAMS.java diff -N Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/TPMPARAMS.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/TPMPARAMS.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,8 @@ +package org.eclipse.swt.internal.win32; + +public class TPMPARAMS { + public int cbSize; +// public RECT rcExclude; + public int left, top, right, bottom; + public static int sizeof = OS.TPMPARAMS_sizeof (); +}