jdk/src/solaris/native/sun/awt/awt_PopupMenu.c
changeset 1203 3e5496df0d2b
parent 1202 5a725d2f0daa
parent 1201 e87f9c042699
child 1211 b659a7cee935
equal deleted inserted replaced
1202:5a725d2f0daa 1203:3e5496df0d2b
     1 /*
       
     2  * Copyright 1996-2004 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 #ifdef HEADLESS
       
    27     #error This file should not be included in headless library
       
    28 #endif
       
    29 
       
    30 #include "awt_p.h"
       
    31 #include <Xm/Separator.h>
       
    32 #include <Xm/MenuShell.h>
       
    33 #include <Xm/RowColumn.h>
       
    34 #include "color.h"
       
    35 #include "java_awt_PopupMenu.h"
       
    36 #include "java_awt_Component.h"
       
    37 #include "java_awt_Event.h"
       
    38 #include "sun_awt_motif_MPopupMenuPeer.h"
       
    39 #include "sun_awt_motif_MComponentPeer.h"
       
    40 
       
    41 #include "awt_PopupMenu.h"
       
    42 #include "awt_MenuItem.h"
       
    43 #include "awt_Component.h"
       
    44 #include "awt_MenuComponent.h"
       
    45 #include "awt_Menu.h"
       
    46 #include "awt_Event.h"
       
    47 
       
    48 #include "multi_font.h"
       
    49 #include <jni.h>
       
    50 #include <jni_util.h>
       
    51 
       
    52 extern struct MMenuItemPeerIDs mMenuItemPeerIDs;
       
    53 extern struct MComponentPeerIDs mComponentPeerIDs;
       
    54 extern struct MenuComponentIDs menuComponentIDs;
       
    55 extern struct MenuItemIDs menuItemIDs;
       
    56 extern struct MenuIDs menuIDs;
       
    57 extern AwtGraphicsConfigDataPtr
       
    58 getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject parentPeer);
       
    59 extern Boolean keyboardGrabbed;
       
    60 Boolean poppingDown = False;
       
    61 
       
    62 struct MPopupMenuPeerIDs mPopupMenuPeerIDs;
       
    63 
       
    64 static Widget activePopup;
       
    65 
       
    66 void removePopupMenus() {
       
    67     if (activePopup != NULL &&
       
    68         XtIsManaged(activePopup))
       
    69     {
       
    70             XtUnmanageChild(activePopup);
       
    71             activePopup = NULL;
       
    72     }
       
    73 }
       
    74 
       
    75 Boolean awtMenuIsActive() {
       
    76     return ((activePopup != NULL) || (awt_util_focusIsOnMenu(awt_display)));
       
    77 }
       
    78 
       
    79 struct ClientDataStruct {
       
    80     struct ComponentData *wdata;
       
    81     jobject mMenuItemPeerIDs;
       
    82 };
       
    83 
       
    84 /*
       
    85  * Class:     sun_awt_motif_MPopupMenuPeer
       
    86  * Method:    initIDs
       
    87  * Signature: ()V
       
    88  */
       
    89 
       
    90 /* This function gets called from the static initializer for
       
    91    MPopupMenuPeer.java to initialize the methodIDs for methods that may
       
    92    be accessed from C */
       
    93 
       
    94 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_initIDs
       
    95   (JNIEnv *env, jclass cls)
       
    96 {
       
    97     mPopupMenuPeerIDs.destroyNativeWidgetAfterGettingTreeLock =
       
    98         (*env)->GetMethodID(env, cls,
       
    99                             "destroyNativeWidgetAfterGettingTreeLock", "()V");
       
   100 }
       
   101 
       
   102 extern Boolean skipNextNotifyWhileGrabbed;
       
   103 
       
   104 static void
       
   105 Popup_popUpCB(Widget w, XtPointer client_data, XtPointer calldata)
       
   106 {
       
   107     skipNextNotifyWhileGrabbed = True;
       
   108 }
       
   109 /*
       
   110  * client_data is MPopupMenuPeer instance
       
   111  */
       
   112 static void
       
   113 Popup_popdownCB(Widget w, XtPointer client_data, XtPointer calldata)
       
   114 {
       
   115     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
       
   116     jobject target = NULL;
       
   117 
       
   118     /*
       
   119      * Fix for 4394847. Due to the race keyboard remains grabbed after menu
       
   120      * was disposed. Clear the grab status here instead of processOneEvent.
       
   121      */
       
   122     poppingDown = True;
       
   123     keyboardGrabbed = False;
       
   124     skipNextNotifyWhileGrabbed = True;
       
   125 
       
   126     XtRemoveCallback(w, XtNpopdownCallback,
       
   127                      Popup_popdownCB, (XtPointer) client_data);
       
   128 
       
   129     (*env)->CallVoidMethod(env, (jobject) client_data,
       
   130         mPopupMenuPeerIDs.destroyNativeWidgetAfterGettingTreeLock);
       
   131 
       
   132     if ((*env)->ExceptionOccurred(env)) {
       
   133         (*env)->ExceptionDescribe(env);
       
   134         (*env)->ExceptionClear(env);
       
   135     }
       
   136 }
       
   137 
       
   138 /*
       
   139  * Class:     sun_awt_motif_MPopupMenuPeer
       
   140  * Method:    createMenu
       
   141  * Signature: (Lsun/awt/motif/MComponentPeer;)V
       
   142  */
       
   143 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_createMenu
       
   144   (JNIEnv *env, jobject this, jobject parent)
       
   145 {
       
   146     struct ComponentData *wdata;
       
   147     struct MenuData *mdata;
       
   148     struct FontData *fdata;
       
   149     char *ctitle = NULL;
       
   150     int32_t argc;
       
   151 #define MAX_ARGC 10
       
   152     Arg args[MAX_ARGC];
       
   153     Pixel bg;
       
   154     Pixel fg;
       
   155     XmFontList fontlist = NULL;
       
   156     XmString mfstr = NULL;
       
   157     jobject font;
       
   158     jobject target;
       
   159     jobject targetFont;
       
   160     jobject label;
       
   161     jboolean IsMultiFont;
       
   162     jboolean tearOff;
       
   163     jobject globalRef = (*env)->NewGlobalRef(env, this);
       
   164     AwtGraphicsConfigDataPtr adata;
       
   165 
       
   166     JNU_SetLongFieldFromPtr(env, this,
       
   167                             mMenuItemPeerIDs.jniGlobalRef, globalRef);
       
   168 
       
   169 
       
   170     AWT_LOCK();
       
   171 
       
   172     if (JNU_IsNull(env, parent)) {
       
   173         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   174         AWT_UNLOCK();
       
   175         return;
       
   176     }
       
   177     target =
       
   178       (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target);
       
   179     wdata = (struct ComponentData *)
       
   180       JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData);
       
   181 
       
   182     if (wdata == NULL || JNU_IsNull(env, target)) {
       
   183         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   184         AWT_UNLOCK();
       
   185         return;
       
   186     }
       
   187     mdata = ZALLOC(MenuData);
       
   188     if (mdata == NULL) {
       
   189         JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
       
   190         AWT_UNLOCK();
       
   191         return;
       
   192     }
       
   193     JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata);
       
   194 
       
   195     adata = getGraphicsConfigFromComponentPeer(env, parent);
       
   196 
       
   197     /*
       
   198      * Why are these different?
       
   199      */
       
   200     font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode",
       
   201                                 "()Ljava/awt/Font;").l;
       
   202     targetFont =
       
   203       (*env)->GetObjectField(env, target, menuComponentIDs.font);
       
   204     if (!JNU_IsNull(env, targetFont) &&
       
   205         (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) {
       
   206         IsMultiFont = awtJNI_IsMultiFont(env, targetFont);
       
   207     } else {
       
   208         IsMultiFont = awtJNI_IsMultiFont(env, font);
       
   209     }
       
   210 
       
   211     label = (*env)->GetObjectField(env, target, menuItemIDs.label);
       
   212     if (JNU_IsNull(env, label)) {
       
   213         mfstr = XmStringCreateLocalized("");
       
   214         ctitle = "";
       
   215     } else {
       
   216         if (IsMultiFont) {
       
   217             mfstr = awtJNI_MakeMultiFontString(env, label, font);
       
   218         } else {
       
   219             ctitle = (char *) JNU_GetStringPlatformChars(env, label, NULL);
       
   220         }
       
   221     }
       
   222 
       
   223     XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL);
       
   224     XtVaGetValues(wdata->widget, XmNforeground, &fg, NULL);
       
   225 
       
   226     argc = 0;
       
   227     XtSetArg(args[argc], XmNbackground, bg);
       
   228     argc++;
       
   229     XtSetArg(args[argc], XmNforeground, fg);
       
   230     argc++;
       
   231     tearOff = (*env)->GetBooleanField(env, target, menuIDs.tearOff);
       
   232     if (tearOff) {
       
   233         XtSetArg(args[argc], XmNtearOffModel, XmTEAR_OFF_ENABLED);
       
   234         argc++;
       
   235     }
       
   236     if (!JNU_IsNull(env, targetFont)
       
   237         && (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) {
       
   238         if (IsMultiFont) {
       
   239             fontlist = awtJNI_GetFontList(env, targetFont);
       
   240         } else {
       
   241             fontlist = XmFontListCreate(fdata->xfont, "labelFont");
       
   242         }
       
   243 
       
   244         XtSetArg(args[argc], XmNfontList, fontlist);
       
   245         argc++;
       
   246     } else {
       
   247         if (IsMultiFont) {
       
   248             fontlist = awtJNI_GetFontList(env, font);
       
   249             XtSetArg(args[argc], XmNfontList, fontlist);
       
   250             argc++;
       
   251         }
       
   252     }
       
   253 
       
   254     XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual);
       
   255     argc++;
       
   256     XtSetArg (args[argc], XmNscreen,
       
   257               ScreenOfDisplay(awt_display,
       
   258                               adata->awt_visInfo.screen));
       
   259     argc++;
       
   260 
       
   261     if (IsMultiFont) {
       
   262         DASSERT(!(argc > MAX_ARGC));
       
   263         mdata->itemData.comp.widget = XmCreatePopupMenu(wdata->widget,
       
   264                                                         "",
       
   265                                                         args,
       
   266                                                         argc);
       
   267     } else {
       
   268         DASSERT(!(argc > MAX_ARGC));
       
   269         mdata->itemData.comp.widget = XmCreatePopupMenu(wdata->widget,
       
   270                                                         ctitle,
       
   271                                                         args,
       
   272                                                         argc);
       
   273     }
       
   274     awt_addMenuWidget(mdata->itemData.comp.widget);
       
   275 
       
   276     /*
       
   277      * Fix for bug 4180147 -
       
   278      * screen can be frozen when interacting with MB3 using AWT on Motif
       
   279      */
       
   280     XtUngrabButton(wdata->widget, AnyButton, AnyModifier);
       
   281     XtUngrabPointer(wdata->widget, CurrentTime);
       
   282 
       
   283     /* fix for bug #4169155: Popup menus get a leading separator on Motif
       
   284        system.
       
   285        Additional check that title string is not empty*/
       
   286     if (!JNU_IsNull(env, label) &&
       
   287         (*env)->GetStringUTFLength( env, label) != (jsize)0 ) {
       
   288         if (IsMultiFont) {
       
   289             XtVaCreateManagedWidget("",
       
   290                                     xmLabelWidgetClass,
       
   291                                     mdata->itemData.comp.widget,
       
   292                                     XmNfontList, fontlist,
       
   293                                     XmNlabelString, mfstr,
       
   294                                     XmNbackground, bg,
       
   295                                     XmNforeground, fg,
       
   296                                     XmNhighlightColor, fg,
       
   297                                     NULL);
       
   298             XmStringFree(mfstr);
       
   299         } else {
       
   300             XmString xmstr = XmStringCreateLocalized(ctitle);
       
   301 
       
   302             XtVaCreateManagedWidget(ctitle,
       
   303                                     xmLabelWidgetClass,
       
   304                                     mdata->itemData.comp.widget,
       
   305                                     XmNlabelString, xmstr,
       
   306                                     XmNbackground, bg,
       
   307                                     XmNforeground, fg,
       
   308                                     XmNhighlightColor, fg,
       
   309                                     NULL);
       
   310             XmStringFree(xmstr);
       
   311             JNU_ReleaseStringPlatformChars(env, label, (const char *) ctitle);
       
   312         }
       
   313         /* Create separator */
       
   314         XtVaCreateManagedWidget("",
       
   315                                 xmSeparatorWidgetClass,
       
   316                                 mdata->itemData.comp.widget,
       
   317                                 XmNbackground, bg,
       
   318                                 XmNforeground, fg,
       
   319                                 NULL);
       
   320     }
       
   321     if (tearOff) {
       
   322         Widget tearOffWidget = XmGetTearOffControl(mdata->itemData.comp.widget);
       
   323 
       
   324         XtVaSetValues(tearOffWidget,
       
   325                       XmNbackground, bg,
       
   326                       XmNforeground, fg,
       
   327                       XmNhighlightColor, fg,
       
   328                       NULL);
       
   329     }
       
   330     mdata->comp.widget = mdata->itemData.comp.widget;
       
   331 
       
   332     if (!JNU_IsNull(env, targetFont)) {
       
   333         XmFontListFree(fontlist);
       
   334     }
       
   335     XtSetSensitive(mdata->comp.widget,
       
   336       ((*env)->GetBooleanField(env, target, menuItemIDs.enabled) ?
       
   337        True : False));
       
   338 
       
   339     AWT_UNLOCK();
       
   340 }
       
   341 
       
   342 /*
       
   343  * Class:     sun_awt_motif_MPopupMenuPeer
       
   344  * Method:    pShow
       
   345  * Signature: (Ljava/awt/Event;IILsun/awt/motif/MComponentPeer;)V
       
   346  */
       
   347 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_pShow
       
   348   (JNIEnv *env, jobject this, jobject event, jint x, jint y, jobject origin)
       
   349 {
       
   350     struct MenuData *mdata;
       
   351     struct ComponentData *wdata;
       
   352     XButtonEvent *bevent;
       
   353     XButtonEvent *newEvent = NULL;
       
   354     void *data;
       
   355 
       
   356     AWT_LOCK();
       
   357 
       
   358     mdata = (struct MenuData *)
       
   359       JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData);
       
   360     if (mdata == NULL || JNU_IsNull(env, event)) {
       
   361         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   362         AWT_UNLOCK();
       
   363         return;
       
   364     }
       
   365 
       
   366     wdata = (struct ComponentData *)
       
   367         JNU_GetLongFieldAsPtr(env, origin, mComponentPeerIDs.pData);
       
   368 
       
   369     if ( wdata == NULL || wdata->widget == NULL ) { /* 425598 */
       
   370         JNU_ThrowNullPointerException(env, "NullPointerException"); /* 425598 */
       
   371         AWT_UNLOCK(); /* 425598 */
       
   372         return; /* 425598 */
       
   373     } /* 425598 */
       
   374 
       
   375     if (!XtIsRealized(wdata->widget)) {
       
   376         JNU_ThrowInternalError(env, "widget not visible on screen");
       
   377         AWT_UNLOCK();
       
   378         return;
       
   379     }
       
   380 
       
   381     /*
       
   382      * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time.
       
   383      * If another popup is currently visible hide it.
       
   384      */
       
   385     if (activePopup != NULL &&
       
   386         activePopup != mdata->comp.widget &&
       
   387         XtIsObject(activePopup) &&
       
   388         XtIsManaged(activePopup)) {
       
   389             removePopupMenus();
       
   390     }
       
   391 
       
   392     /* If the raw x event is not available, then we must use an unfortunate
       
   393      * round-trip call to XTranslateCoordiates to get the root coordinates.
       
   394      */
       
   395     data = JNU_GetLongFieldAsPtr(env, event, eventIDs.data);
       
   396     if (data == NULL || ((XEvent *) data)->type != ButtonPress) {
       
   397         int32_t rx, ry;
       
   398         Window root, win;
       
   399 
       
   400         root = RootWindowOfScreen(XtScreen(wdata->widget));
       
   401         XTranslateCoordinates(awt_display,
       
   402                               XtWindow(wdata->widget),
       
   403                               root,
       
   404                               (int32_t) x, (int32_t) y,
       
   405                               &rx, &ry,
       
   406                               &win);
       
   407         /*
       
   408                 printf("translated coords %d,%d to root %d,%d\n", x, y, rx, ry);
       
   409         */
       
   410 
       
   411         newEvent = (XButtonEvent *) malloc(sizeof(XButtonEvent));
       
   412         newEvent->type = ButtonPress;
       
   413         newEvent->display = awt_display;
       
   414         newEvent->window = XtWindow(wdata->widget);
       
   415         newEvent->time = awt_util_getCurrentServerTime();
       
   416         newEvent->x = (int32_t) x;
       
   417         newEvent->y = (int32_t) y;
       
   418         newEvent->x_root = rx;
       
   419         newEvent->y_root = ry;
       
   420         bevent = newEvent;
       
   421 
       
   422     } else {
       
   423         bevent = (XButtonEvent *) data;
       
   424     }
       
   425 
       
   426     XtAddCallback(XtParent(mdata->comp.widget), XtNpopdownCallback,
       
   427                   Popup_popdownCB,
       
   428                   (XtPointer)
       
   429                   JNU_GetLongFieldAsPtr(env, this,
       
   430                                         mMenuItemPeerIDs.jniGlobalRef));
       
   431 
       
   432     XtAddCallback(XtParent(mdata->comp.widget), XtNpopupCallback,
       
   433                   Popup_popUpCB,
       
   434                   (XtPointer)
       
   435                   JNU_GetLongFieldAsPtr(env, this,
       
   436                                         mMenuItemPeerIDs.jniGlobalRef));
       
   437 
       
   438 
       
   439     XmMenuPosition(mdata->comp.widget, bevent);
       
   440     XtManageChild(mdata->comp.widget);
       
   441 
       
   442     /*
       
   443      * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time.
       
   444      * Store the pointer to the currently showing popup.
       
   445      */
       
   446     activePopup = mdata->comp.widget;
       
   447 
       
   448     if (newEvent) {
       
   449         free((void *) newEvent);
       
   450     }
       
   451     AWT_UNLOCK();
       
   452 }
       
   453 
       
   454 /*
       
   455  * Class:     sun_awt_motif_MPopupMenuPeer
       
   456  * Method:    pDispose
       
   457  * Signature: ()V
       
   458  */
       
   459 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_pDispose
       
   460   (JNIEnv *env, jobject this)
       
   461 {
       
   462     struct MenuData *mdata;
       
   463 
       
   464     AWT_LOCK();
       
   465 
       
   466     mdata = (struct MenuData *)
       
   467       JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData);
       
   468 
       
   469     if (mdata == NULL) {
       
   470         AWT_UNLOCK();
       
   471         return;
       
   472     }
       
   473     /*
       
   474      * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time.
       
   475      * Clear the pointer to the currently showing popup.
       
   476      */
       
   477     if (activePopup == mdata->comp.widget) {
       
   478         activePopup = NULL;
       
   479     }
       
   480     awt_delMenuWidget(mdata->itemData.comp.widget);
       
   481     XtUnmanageChild(mdata->comp.widget);
       
   482     awt_util_consumeAllXEvents(mdata->comp.widget);
       
   483     XtDestroyWidget(mdata->comp.widget);
       
   484     free((void *) mdata);
       
   485     (*env)->SetLongField(env, this, mMenuItemPeerIDs.pData, (jlong)0);
       
   486 
       
   487     awtJNI_DeleteGlobalMenuRef(env, this);
       
   488 
       
   489     poppingDown = False;
       
   490     AWT_UNLOCK();
       
   491 }