jdk/src/solaris/native/sun/awt/awt_Menu.c
changeset 1211 b659a7cee935
parent 1210 7798f9e88bf9
parent 1203 3e5496df0d2b
child 1212 d718a4419361
equal deleted inserted replaced
1210:7798f9e88bf9 1211:b659a7cee935
     1 /*
       
     2  * Copyright 1995-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 "color.h"
       
    32 #include "java_awt_Menu.h"
       
    33 #include "sun_awt_motif_MMenuPeer.h"
       
    34 #include "java_awt_MenuBar.h"
       
    35 #include "sun_awt_motif_MMenuBarPeer.h"
       
    36 
       
    37 #include "awt_MenuBar.h"
       
    38 #include "awt_MenuComponent.h"
       
    39 #include "awt_MenuItem.h"
       
    40 #include "awt_Menu.h"
       
    41 
       
    42 #include "multi_font.h"
       
    43 #include <jni.h>
       
    44 #include <jni_util.h>
       
    45 #include <Xm/CascadeBP.h>
       
    46 
       
    47 extern struct MenuComponentIDs menuComponentIDs;
       
    48 extern struct MenuItemIDs menuItemIDs;
       
    49 extern struct MMenuItemPeerIDs mMenuItemPeerIDs;
       
    50 extern struct MMenuBarPeerIDs mMenuBarPeerIDs;
       
    51 
       
    52 struct MenuIDs menuIDs;
       
    53 
       
    54 /*
       
    55  * Class:     java_awt_Menu
       
    56  * Method:    initIDs
       
    57  * Signature: ()V
       
    58  */
       
    59 
       
    60 /* This function gets called from the static initializer for
       
    61    Menu.java to initialize the fieldIDs for fields that may
       
    62    be accessed from C */
       
    63 
       
    64 JNIEXPORT void JNICALL Java_java_awt_Menu_initIDs
       
    65   (JNIEnv *env, jclass cls)
       
    66 {
       
    67     menuIDs.tearOff = (*env)->GetFieldID(env, cls, "tearOff", "Z");
       
    68     menuIDs.isHelpMenu = (*env)->GetFieldID(env, cls, "isHelpMenu", "Z");
       
    69 }
       
    70 
       
    71 /*
       
    72  * Fix for Bug Traq 4251941 - segfault after double tear-off and close
       
    73  * Removes the lost callback from menu item on tear-off control re-creation.
       
    74  * Only for internal use, to be used from awtTearOffActivatedCallback
       
    75  */
       
    76 static void awtTearOffShellDestroy(Widget widget, XtPointer closure, XtPointer data) {
       
    77     if (widget != NULL ) {
       
    78         XtSetKeyboardFocus(widget, NULL);
       
    79     }
       
    80 }
       
    81 
       
    82 /*
       
    83  * Fix for Bug Traq 4251941 - segfault after double tear-off and close
       
    84  * This callback is added to menu after the creation.
       
    85  * It adds the destroy callback awtTearOffShellDestroy to remove the lost focus callback on destroy
       
    86  */
       
    87 static void awtTearOffActivatedCallback(Widget widget, XtPointer closure, XtPointer data) {
       
    88     Widget shell;
       
    89     shell = XtParent(widget);
       
    90     if (shell != NULL && XtClass(shell) == transientShellWidgetClass) {
       
    91         XtAddCallback(shell, XtNdestroyCallback, awtTearOffShellDestroy, widget);
       
    92     }
       
    93 }
       
    94 
       
    95 extern Boolean skipNextNotifyWhileGrabbed;
       
    96 
       
    97 static void
       
    98 Menu_popDownCB(Widget w, XtPointer client_data, XtPointer calldata)
       
    99 {
       
   100     skipNextNotifyWhileGrabbed = True;
       
   101 }
       
   102 
       
   103 
       
   104 
       
   105 /*
       
   106  * this is a MMenuPeer instance
       
   107  */
       
   108 static void
       
   109 awtJNI_CreateMenu(JNIEnv * env, jobject this, Widget menuParent)
       
   110 {
       
   111     int32_t argc;
       
   112 #define MAX_ARGC 10
       
   113     Arg args[MAX_ARGC];
       
   114     char *ctitle = NULL;
       
   115     struct MenuData *mdata;
       
   116     struct FontData *fdata;
       
   117     Pixel bg;
       
   118     Pixel fg;
       
   119     XmFontList fontlist = NULL;
       
   120     Widget tearOff;
       
   121     XmString mfstr = NULL;
       
   122     XmString str = NULL;
       
   123     jobject target;
       
   124     jobject targetFont;
       
   125     jobject label;
       
   126     jobject font;
       
   127     jboolean IsMultiFont;
       
   128     jboolean isTearOff;
       
   129 
       
   130     /* perhaps this is unncessary, if awtJNI_CreateMenu is only called
       
   131      * from a native method.
       
   132      */
       
   133     if ((*env)->PushLocalFrame(env, (jint)16) < (jint)0) {
       
   134         return;
       
   135     }
       
   136 
       
   137     fdata = NULL;
       
   138 
       
   139     target = (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target);
       
   140     if (JNU_IsNull(env, target)) {
       
   141         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   142         (*env)->PopLocalFrame(env, NULL);
       
   143         return;
       
   144     }
       
   145     font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode",
       
   146                                 "()Ljava/awt/Font;").l;
       
   147 
       
   148     mdata = ZALLOC(MenuData);
       
   149     JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata);
       
   150     if (mdata == NULL) {
       
   151         JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
       
   152         (*env)->PopLocalFrame(env, NULL);
       
   153         return;
       
   154     }
       
   155     targetFont = (*env)->GetObjectField(env, target, menuComponentIDs.font);
       
   156     if (!JNU_IsNull(env, targetFont) &&
       
   157         (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) {
       
   158         IsMultiFont = awtJNI_IsMultiFont(env, targetFont);
       
   159     } else {
       
   160         IsMultiFont = awtJNI_IsMultiFont(env, font);
       
   161     }
       
   162 
       
   163     label = (*env)->GetObjectField(env, target, menuItemIDs.label);
       
   164     if (JNU_IsNull(env, label)) {
       
   165         mfstr = XmStringCreateLocalized("");
       
   166         ctitle = "";
       
   167     } else {
       
   168         if (IsMultiFont) {
       
   169             mfstr = awtJNI_MakeMultiFontString(env, label, font);
       
   170         } else {
       
   171             ctitle = (char *) JNU_GetStringPlatformChars(env, label, NULL);
       
   172         }
       
   173     }
       
   174 
       
   175     XtVaGetValues(menuParent, XmNbackground, &bg, NULL);
       
   176     XtVaGetValues(menuParent, XmNforeground, &fg, NULL);
       
   177 
       
   178     argc = 0;
       
   179     XtSetArg(args[argc], XmNbackground, bg);
       
   180     argc++;
       
   181     XtSetArg(args[argc], XmNforeground, fg);
       
   182     argc++;
       
   183 
       
   184     XtSetArg(args[argc], XmNlabelFontList,   getMotifFontList());
       
   185     argc++;
       
   186     XtSetArg(args[argc], XmNbuttonFontList,  getMotifFontList());
       
   187     argc++;
       
   188 
       
   189     isTearOff = (*env)->GetBooleanField(env, target, menuIDs.tearOff);
       
   190 
       
   191     if (isTearOff) {
       
   192         XtSetArg(args[argc], XmNtearOffModel, XmTEAR_OFF_ENABLED);
       
   193         argc++;
       
   194     }
       
   195 
       
   196     if (IsMultiFont) {
       
   197         DASSERT(!(argc > MAX_ARGC));
       
   198         mdata->itemData.comp.widget = XmCreatePulldownMenu(menuParent,
       
   199                                                            "",
       
   200                                                            args,
       
   201                                                            argc);
       
   202     } else {
       
   203         DASSERT(!(argc > MAX_ARGC));
       
   204         mdata->itemData.comp.widget = XmCreatePulldownMenu(menuParent,
       
   205                                                            ctitle,
       
   206                                                            args,
       
   207                                                            argc);
       
   208     }
       
   209     awt_addMenuWidget(mdata->itemData.comp.widget);
       
   210 
       
   211     if (isTearOff) {
       
   212         tearOff = XmGetTearOffControl(mdata->itemData.comp.widget);
       
   213         XtVaSetValues(tearOff,
       
   214                       XmNbackground, bg,
       
   215                       XmNforeground, fg,
       
   216                       XmNhighlightColor, fg,
       
   217                       NULL);
       
   218         XtAddCallback(mdata->itemData.comp.widget, XmNtearOffMenuActivateCallback,
       
   219                       awtTearOffActivatedCallback, NULL);
       
   220     }
       
   221     argc = 0;
       
   222     XtSetArg(args[argc], XmNsubMenuId, mdata->itemData.comp.widget);
       
   223     argc++;
       
   224 
       
   225     if (IsMultiFont) {
       
   226         XtSetArg(args[argc], XmNlabelString, mfstr);
       
   227     } else {
       
   228         str = XmStringCreate(ctitle, XmSTRING_DEFAULT_CHARSET);
       
   229         XtSetArg(args[argc], XmNlabelString, str);
       
   230     }
       
   231     argc++;
       
   232     XtSetArg(args[argc], XmNbackground, bg);
       
   233     argc++;
       
   234     XtSetArg(args[argc], XmNforeground, fg);
       
   235     argc++;
       
   236 
       
   237     if (!JNU_IsNull(env, targetFont) && (fdata != NULL)) {
       
   238         if (IsMultiFont) {
       
   239             fontlist = awtJNI_GetFontList(env, targetFont);
       
   240         } else {
       
   241             fontlist = XmFontListCreate(fdata->xfont, "labelFont");
       
   242         }
       
   243         XtSetArg(args[argc], XmNfontList, fontlist);
       
   244         argc++;
       
   245     } else {
       
   246         if (IsMultiFont) {
       
   247             fontlist = awtJNI_GetFontList(env, font);
       
   248             XtSetArg(args[argc], XmNfontList, fontlist);
       
   249             argc++;
       
   250         }
       
   251     }
       
   252 
       
   253     if (IsMultiFont) {
       
   254         DASSERT(!(argc > MAX_ARGC));
       
   255         mdata->comp.widget = XmCreateCascadeButton(menuParent, "", args, argc);
       
   256     } else {
       
   257         DASSERT(!(argc > MAX_ARGC));
       
   258         mdata->comp.widget = XmCreateCascadeButton(menuParent, ctitle, args, argc);
       
   259     }
       
   260 
       
   261     if ((*env)->GetBooleanField(env, target, menuIDs.isHelpMenu)) {
       
   262         XtVaSetValues(menuParent,
       
   263                       XmNmenuHelpWidget, mdata->comp.widget,
       
   264                       NULL);
       
   265     }
       
   266 
       
   267     /**
       
   268      * Add callback to MenuShell of the menu so we know when
       
   269      * menu pops down. mdata->itemData.comp.widget is RowColumn,
       
   270      * its parent - MenuShell.
       
   271      */
       
   272     XtAddCallback(XtParent(mdata->itemData.comp.widget), XtNpopdownCallback,
       
   273                   Menu_popDownCB,
       
   274                   (XtPointer)
       
   275                   JNU_GetLongFieldAsPtr(env, this,
       
   276                                         mMenuItemPeerIDs.jniGlobalRef));
       
   277 
       
   278     /*
       
   279      * Free resources
       
   280      */
       
   281     if (!JNU_IsNull(env, targetFont)) {
       
   282         XmFontListFree(fontlist);
       
   283     }
       
   284 
       
   285     if (mfstr != NULL) {
       
   286       XmStringFree(mfstr);
       
   287       mfstr = NULL;
       
   288     }
       
   289 
       
   290     if (str) {
       
   291       XmStringFree(str);
       
   292       str = NULL;
       
   293     }
       
   294 
       
   295     XtManageChild(mdata->comp.widget);
       
   296     XtSetSensitive(mdata->comp.widget,
       
   297                    (*env)->GetBooleanField(env, target, menuItemIDs.enabled) ?
       
   298                    True : False);
       
   299 
       
   300     if (ctitle != NULL && ctitle != "") {
       
   301         JNU_ReleaseStringPlatformChars(env, label, (const char *) ctitle);
       
   302     }
       
   303     (*env)->PopLocalFrame(env, NULL);
       
   304 }
       
   305 
       
   306 
       
   307 /*
       
   308  * Class:     sun_awt_motif_MMenuPeer
       
   309  * Method:    createMenu
       
   310  * Signature: (Lsun/awt/motif/MMenuBarPeer;)V
       
   311  */
       
   312 JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_createMenu
       
   313   (JNIEnv *env, jobject this, jobject parent)
       
   314 {
       
   315     struct ComponentData *mbdata;
       
   316     AwtGraphicsConfigDataPtr adata;
       
   317 
       
   318     AWT_LOCK();
       
   319     if (JNU_IsNull(env, parent)) {
       
   320         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   321         AWT_UNLOCK();
       
   322         return;
       
   323     }
       
   324     mbdata = (struct ComponentData *)
       
   325         JNU_GetLongFieldAsPtr(env, parent, mMenuBarPeerIDs.pData);
       
   326     if (mbdata == NULL) {
       
   327         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   328         AWT_UNLOCK();
       
   329         return;
       
   330     }
       
   331 
       
   332     awtJNI_CreateMenu(env, this, mbdata->widget);
       
   333 
       
   334     AWT_UNLOCK();
       
   335 }
       
   336 
       
   337 /*
       
   338  * Class:     sun_awt_motif_MMenuPeer
       
   339  * Method:    createSubMenu
       
   340  * Signature: (Lsun/awt/motif/MMenuPeer;)V
       
   341  */
       
   342 JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_createSubMenu
       
   343 (JNIEnv *env, jobject this, jobject parent)
       
   344 {
       
   345     struct MenuData *mpdata;
       
   346     AwtGraphicsConfigDataPtr adata;
       
   347 
       
   348     AWT_LOCK();
       
   349     if (JNU_IsNull(env, parent)) {
       
   350         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   351         AWT_UNLOCK();
       
   352         return;
       
   353     }
       
   354     mpdata = (struct MenuData *)
       
   355         JNU_GetLongFieldAsPtr(env, parent, mMenuItemPeerIDs.pData);
       
   356     if (mpdata == NULL) {
       
   357         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   358         AWT_UNLOCK();
       
   359         return;
       
   360     }
       
   361 
       
   362     awtJNI_CreateMenu(env, this, mpdata->itemData.comp.widget);
       
   363 
       
   364     AWT_UNLOCK();
       
   365 }
       
   366 
       
   367 /*
       
   368  * Class:     sun_awt_motif_MMenuPeer
       
   369  * Method:    pDispose
       
   370  * Signature: ()V
       
   371  */
       
   372 JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_pDispose
       
   373   (JNIEnv *env, jobject this)
       
   374 {
       
   375     struct MenuData *mdata;
       
   376     Widget parent;
       
   377     Boolean isParentManaged = False;
       
   378 
       
   379     AWT_LOCK();
       
   380 
       
   381     mdata = (struct MenuData *)
       
   382         JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData);
       
   383     if (mdata == NULL) {
       
   384         AWT_UNLOCK();
       
   385         return;
       
   386     }
       
   387     awt_delMenuWidget(mdata->itemData.comp.widget);
       
   388     XtUnmanageChild(mdata->comp.widget);
       
   389     awt_util_consumeAllXEvents(mdata->itemData.comp.widget);
       
   390     awt_util_consumeAllXEvents(mdata->comp.widget);
       
   391 
       
   392     parent = XtParent(mdata->itemData.comp.widget);
       
   393     if (parent != NULL && XtIsManaged(parent)) {
       
   394         isParentManaged = True;
       
   395         XtUnmanageChild(parent);
       
   396     }
       
   397 
       
   398     XtDestroyWidget(mdata->itemData.comp.widget);
       
   399 
       
   400     if (isParentManaged) {
       
   401         XtManageChild(parent);
       
   402     }
       
   403 
       
   404     XtDestroyWidget(mdata->comp.widget);
       
   405     free((void *) mdata);
       
   406     AWT_UNLOCK();
       
   407 }