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.70 diff -u -r1.70 ToolItem.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java 26 Jun 2007 19:52:07 -0000 1.70 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java 2 Jul 2007 10:39:09 -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 context 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.3 + */ +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. @@ -254,6 +283,24 @@ } /** + * 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 + */ +public Menu getMenu () { + checkWidget(); + return menu; +} + +/** * Returns true if the receiver is enabled, and * false otherwise. A disabled control is typically * not selectable from the user interface and draws with an @@ -435,6 +482,33 @@ /** * Removes the listener from the collection of listeners who will + * be notified when the platform-specific context menu trigger has + * occurred. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException + * @exception SWTException + * + * @see MenuDetectListener + * @see #addMenuDetectListener + * + * @since 3.3 + */ +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 @@ -638,6 +712,29 @@ } /** + * 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 is pressed. + * Attempts to set a drop-dwn menu for a receiver that does not have the {@link SWT#DROP_DOWN} + * style are ignored. + *

+ * + * @param menu the drop-down menu to be displayed when the receiver's arrow is pressed + * @exception SWTException + */ +public void setMenu (Menu menu) { + checkWidget(); + this.menu = menu; +} + +/** * Sets the receiver's hot image to the argument, which may be * null indicating that no hot image should be displayed. *

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.117 diff -u -r1.117 ToolBar.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java 26 Jun 2007 19:52:06 -0000 1.117 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java 2 Jul 2007 10:39:09 -0000 @@ -44,6 +44,7 @@ ToolItem [] items; boolean ignoreResize, ignoreMouse; ImageList imageList, disabledImageList, hotImageList; + boolean showingPushItemMenu; static final int ToolBarProc; static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true); static { @@ -1119,6 +1120,16 @@ * application the opportunity to cancel the operation. */ return LRESULT.ZERO; + case OS.VK_DOWN: + case OS.VK_UP: + /* + * SWT.DROPDOWN menus are automatically triggered by Windows on the + * UP and DOWN keys. Here we mirror this behavior for PUSH items. + */ + int itemIndex = OS.SendMessage(handle, OS.TB_GETHOTITEM, 0, 0); + if (handlePushItemMenu(itemIndex)) { + return LRESULT.ZERO; + } } return result; } @@ -1131,8 +1142,33 @@ return super.WM_KILLFOCUS (wParam, lParam); } +LRESULT WM_LBUTTONDBLCLK(int wParam, int lParam) { + POINT point = new POINT (); + point.x = OS.GET_X_LPARAM (lParam); + point.y = OS.GET_Y_LPARAM (lParam); + int itemIndex = OS.SendMessage (handle, OS.TB_HITTEST, 0, point); + if (handlePushItemMenu (itemIndex)) { + return LRESULT.ZERO; + } + return super.WM_LBUTTONDBLCLK(wParam, lParam); +} + LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { + if (!showingPushItemMenu) { + POINT point = new POINT (); + point.x = OS.GET_X_LPARAM (lParam); + point.y = OS.GET_Y_LPARAM (lParam); + int itemIndex = OS.SendMessage (handle, OS.TB_HITTEST, 0, point); + if (handlePushItemMenu (itemIndex)) { + return LRESULT.ZERO; + } + } else { + showingPushItemMenu = false; + return LRESULT.ZERO; + } + if (ignoreMouse) return null; + return super.WM_LBUTTONDOWN (wParam, lParam); } @@ -1306,7 +1342,15 @@ 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)) { + // 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(); + showItemMenu (child, rect); + } else { + child.postEvent (SWT.Selection, event); + } } break; case OS.NM_CUSTOMDRAW: @@ -1363,4 +1407,64 @@ return super.wmNotifyChild (hdr, wParam, lParam); } +private boolean handlePushItemMenu(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); + ToolItem child = items[button.idCommand]; + // 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 = OS.SendMessage (handle, OS.TB_GETSTATE, button.idCommand, 0); + // Only attempt to show a menu if the item is enabled + if ((itemState & OS.TBSTATE_ENABLED) != 0) { + RECT rect = new RECT (); + OS.SendMessage (handle, OS.TB_GETITEMRECT, itemIndex, rect); + if (sendItemMenuDetectEvent (child, rect, 0)) { + // Press item + itemState |= OS.TBSTATE_PRESSED; + OS.SendMessage (handle, OS.TB_SETSTATE, button.idCommand, itemState); + // Show menu + showingPushItemMenu = true; + showItemMenu (child, rect); + // Unpress item - reload item state since it may have changed + itemState = OS.SendMessage (handle, OS.TB_GETSTATE, button.idCommand, 0); + itemState &= ~OS.TBSTATE_PRESSED; + OS.SendMessage (handle, OS.TB_SETSTATE, button.idCommand, itemState); + // Allow the mouse event that cancelled the menu to be eaten away + // since on reentrance to the method showingPushItemMenu will still be true. + // This allows the menu to be closed on a second click. + if (display != null && !display.isDisposed ()) { + display.readAndDispatch (); + } + showingPushItemMenu = false; + return true; + } + } + } + } + return false; +} + +private void showItemMenu (ToolItem child, RECT rect) { + Menu menu = child.menu; + OS.MapWindowPoints (handle, 0, rect, 2); + menu.setLocation (rect.left, rect.bottom); + menu._setVisible (true, rect, OS.TPM_VERTICAL); +} + +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(); +} + } 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.110 diff -u -r1.110 Menu.java --- Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java 26 Jun 2007 19:52:07 -0000 1.110 +++ Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java 2 Jul 2007 10:39:07 -0000 @@ -195,7 +195,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 hwndParent = parent.handle; if (visible) { @@ -206,6 +210,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 (); @@ -225,7 +230,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 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.90 diff -u -r1.90 os_stats.c --- Eclipse SWT PI/win32/library/os_stats.c 26 Jun 2007 19:52:07 -0000 1.90 +++ Eclipse SWT PI/win32/library/os_stats.c 2 Jul 2007 10:38:46 -0000 @@ -14,8 +14,8 @@ #ifdef NATIVE_STATS -int OS_nativeFunctionCount = 883; -int OS_nativeFunctionCallCount[883]; +int OS_nativeFunctionCount = 884; +int OS_nativeFunctionCallCount[884]; char * OS_nativeFunctionNames[] = { "ACCEL_1sizeof", "ACTCTX_1sizeof", @@ -867,6 +867,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.46 diff -u -r1.46 os_structs.h --- Eclipse SWT PI/win32/library/os_structs.h 24 Apr 2007 22:42:37 -0000 1.46 +++ Eclipse SWT PI/win32/library/os_structs.h 2 Jul 2007 10:39:00 -0000 @@ -1427,6 +1427,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.90 diff -u -r1.90 os_stats.h --- Eclipse SWT PI/win32/library/os_stats.h 26 Jun 2007 19:52:07 -0000 1.90 +++ Eclipse SWT PI/win32/library/os_stats.h 2 Jul 2007 10:38:47 -0000 @@ -875,6 +875,7 @@ ToUnicode_FUNC, TrackMouseEvent_FUNC, TrackPopupMenu_FUNC, + TrackPopupMenuEx_FUNC, TranslateAcceleratorA_FUNC, TranslateAcceleratorW_FUNC, TranslateCharsetInfo_FUNC, 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.54 diff -u -r1.54 os_structs.c --- Eclipse SWT PI/win32/library/os_structs.c 24 Apr 2007 22:42:37 -0000 1.54 +++ Eclipse SWT PI/win32/library/os_structs.c 2 Jul 2007 10:38:58 -0000 @@ -6523,6 +6523,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/library/os.c =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c,v retrieving revision 1.131 diff -u -r1.131 os.c --- Eclipse SWT PI/win32/library/os.c 27 Jun 2007 15:38:17 -0000 1.131 +++ Eclipse SWT PI/win32/library/os.c 2 Jul 2007 10:38:45 -0000 @@ -13506,6 +13506,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) @@ -13660,6 +13672,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(arg0, arg1, arg2, arg3, 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/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.346 diff -u -r1.346 OS.java --- Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java 27 Jun 2007 15:38:17 -0000 1.346 +++ Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java 2 Jul 2007 10:39:06 -0000 @@ -1548,6 +1548,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); @@ -1618,6 +1619,7 @@ 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_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; @@ -2138,6 +2140,7 @@ public static final native int TEXTMETRICA_sizeof (); public static final native int TEXTMETRICW_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 (); @@ -3858,6 +3861,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 (); +}