/* * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ #ifdef HEADLESS #error This file should not be included in headless library #endif #include "awt_p.h" #include "color.h" #include "java_awt_Menu.h" #include "sun_awt_motif_MMenuPeer.h" #include "java_awt_MenuBar.h" #include "sun_awt_motif_MMenuBarPeer.h" #include "awt_MenuBar.h" #include "awt_MenuComponent.h" #include "awt_MenuItem.h" #include "awt_Menu.h" #include "multi_font.h" #include #include #include extern struct MenuComponentIDs menuComponentIDs; extern struct MenuItemIDs menuItemIDs; extern struct MMenuItemPeerIDs mMenuItemPeerIDs; extern struct MMenuBarPeerIDs mMenuBarPeerIDs; struct MenuIDs menuIDs; /* * Class: java_awt_Menu * Method: initIDs * Signature: ()V */ /* This function gets called from the static initializer for Menu.java to initialize the fieldIDs for fields that may be accessed from C */ JNIEXPORT void JNICALL Java_java_awt_Menu_initIDs (JNIEnv *env, jclass cls) { menuIDs.tearOff = (*env)->GetFieldID(env, cls, "tearOff", "Z"); menuIDs.isHelpMenu = (*env)->GetFieldID(env, cls, "isHelpMenu", "Z"); } /* * Fix for Bug Traq 4251941 - segfault after double tear-off and close * Removes the lost callback from menu item on tear-off control re-creation. * Only for internal use, to be used from awtTearOffActivatedCallback */ static void awtTearOffShellDestroy(Widget widget, XtPointer closure, XtPointer data) { if (widget != NULL ) { XtSetKeyboardFocus(widget, NULL); } } /* * Fix for Bug Traq 4251941 - segfault after double tear-off and close * This callback is added to menu after the creation. * It adds the destroy callback awtTearOffShellDestroy to remove the lost focus callback on destroy */ static void awtTearOffActivatedCallback(Widget widget, XtPointer closure, XtPointer data) { Widget shell; shell = XtParent(widget); if (shell != NULL && XtClass(shell) == transientShellWidgetClass) { XtAddCallback(shell, XtNdestroyCallback, awtTearOffShellDestroy, widget); } } extern Boolean skipNextNotifyWhileGrabbed; static void Menu_popDownCB(Widget w, XtPointer client_data, XtPointer calldata) { skipNextNotifyWhileGrabbed = True; } /* * this is a MMenuPeer instance */ static void awtJNI_CreateMenu(JNIEnv * env, jobject this, Widget menuParent) { int32_t argc; #define MAX_ARGC 10 Arg args[MAX_ARGC]; char *ctitle = NULL; struct MenuData *mdata; struct FontData *fdata; Pixel bg; Pixel fg; XmFontList fontlist = NULL; Widget tearOff; XmString mfstr = NULL; XmString str = NULL; jobject target; jobject targetFont; jobject label; jobject font; jboolean IsMultiFont; jboolean isTearOff; /* perhaps this is unncessary, if awtJNI_CreateMenu is only called * from a native method. */ if ((*env)->PushLocalFrame(env, (jint)16) < (jint)0) { return; } fdata = NULL; target = (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); if (JNU_IsNull(env, target)) { JNU_ThrowNullPointerException(env, "NullPointerException"); (*env)->PopLocalFrame(env, NULL); return; } font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", "()Ljava/awt/Font;").l; mdata = ZALLOC(MenuData); JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata); if (mdata == NULL) { JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); (*env)->PopLocalFrame(env, NULL); return; } targetFont = (*env)->GetObjectField(env, target, menuComponentIDs.font); if (!JNU_IsNull(env, targetFont) && (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { IsMultiFont = awtJNI_IsMultiFont(env, targetFont); } else { IsMultiFont = awtJNI_IsMultiFont(env, font); } label = (*env)->GetObjectField(env, target, menuItemIDs.label); if (JNU_IsNull(env, label)) { mfstr = XmStringCreateLocalized(""); ctitle = ""; } else { if (IsMultiFont) { mfstr = awtJNI_MakeMultiFontString(env, label, font); } else { ctitle = (char *) JNU_GetStringPlatformChars(env, label, NULL); } } XtVaGetValues(menuParent, XmNbackground, &bg, NULL); XtVaGetValues(menuParent, XmNforeground, &fg, NULL); argc = 0; XtSetArg(args[argc], XmNbackground, bg); argc++; XtSetArg(args[argc], XmNforeground, fg); argc++; XtSetArg(args[argc], XmNlabelFontList, getMotifFontList()); argc++; XtSetArg(args[argc], XmNbuttonFontList, getMotifFontList()); argc++; isTearOff = (*env)->GetBooleanField(env, target, menuIDs.tearOff); if (isTearOff) { XtSetArg(args[argc], XmNtearOffModel, XmTEAR_OFF_ENABLED); argc++; } if (IsMultiFont) { DASSERT(!(argc > MAX_ARGC)); mdata->itemData.comp.widget = XmCreatePulldownMenu(menuParent, "", args, argc); } else { DASSERT(!(argc > MAX_ARGC)); mdata->itemData.comp.widget = XmCreatePulldownMenu(menuParent, ctitle, args, argc); } awt_addMenuWidget(mdata->itemData.comp.widget); if (isTearOff) { tearOff = XmGetTearOffControl(mdata->itemData.comp.widget); XtVaSetValues(tearOff, XmNbackground, bg, XmNforeground, fg, XmNhighlightColor, fg, NULL); XtAddCallback(mdata->itemData.comp.widget, XmNtearOffMenuActivateCallback, awtTearOffActivatedCallback, NULL); } argc = 0; XtSetArg(args[argc], XmNsubMenuId, mdata->itemData.comp.widget); argc++; if (IsMultiFont) { XtSetArg(args[argc], XmNlabelString, mfstr); } else { str = XmStringCreate(ctitle, XmSTRING_DEFAULT_CHARSET); XtSetArg(args[argc], XmNlabelString, str); } argc++; XtSetArg(args[argc], XmNbackground, bg); argc++; XtSetArg(args[argc], XmNforeground, fg); argc++; if (!JNU_IsNull(env, targetFont) && (fdata != NULL)) { if (IsMultiFont) { fontlist = awtJNI_GetFontList(env, targetFont); } else { fontlist = XmFontListCreate(fdata->xfont, "labelFont"); } XtSetArg(args[argc], XmNfontList, fontlist); argc++; } else { if (IsMultiFont) { fontlist = awtJNI_GetFontList(env, font); XtSetArg(args[argc], XmNfontList, fontlist); argc++; } } if (IsMultiFont) { DASSERT(!(argc > MAX_ARGC)); mdata->comp.widget = XmCreateCascadeButton(menuParent, "", args, argc); } else { DASSERT(!(argc > MAX_ARGC)); mdata->comp.widget = XmCreateCascadeButton(menuParent, ctitle, args, argc); } if ((*env)->GetBooleanField(env, target, menuIDs.isHelpMenu)) { XtVaSetValues(menuParent, XmNmenuHelpWidget, mdata->comp.widget, NULL); } /** * Add callback to MenuShell of the menu so we know when * menu pops down. mdata->itemData.comp.widget is RowColumn, * its parent - MenuShell. */ XtAddCallback(XtParent(mdata->itemData.comp.widget), XtNpopdownCallback, Menu_popDownCB, (XtPointer) JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.jniGlobalRef)); /* * Free resources */ if (!JNU_IsNull(env, targetFont)) { XmFontListFree(fontlist); } if (mfstr != NULL) { XmStringFree(mfstr); mfstr = NULL; } if (str) { XmStringFree(str); str = NULL; } XtManageChild(mdata->comp.widget); XtSetSensitive(mdata->comp.widget, (*env)->GetBooleanField(env, target, menuItemIDs.enabled) ? True : False); if (ctitle != NULL && ctitle != "") { JNU_ReleaseStringPlatformChars(env, label, (const char *) ctitle); } (*env)->PopLocalFrame(env, NULL); } /* * Class: sun_awt_motif_MMenuPeer * Method: createMenu * Signature: (Lsun/awt/motif/MMenuBarPeer;)V */ JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_createMenu (JNIEnv *env, jobject this, jobject parent) { struct ComponentData *mbdata; AwtGraphicsConfigDataPtr adata; AWT_LOCK(); if (JNU_IsNull(env, parent)) { JNU_ThrowNullPointerException(env, "NullPointerException"); AWT_UNLOCK(); return; } mbdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env, parent, mMenuBarPeerIDs.pData); if (mbdata == NULL) { JNU_ThrowNullPointerException(env, "NullPointerException"); AWT_UNLOCK(); return; } awtJNI_CreateMenu(env, this, mbdata->widget); AWT_UNLOCK(); } /* * Class: sun_awt_motif_MMenuPeer * Method: createSubMenu * Signature: (Lsun/awt/motif/MMenuPeer;)V */ JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_createSubMenu (JNIEnv *env, jobject this, jobject parent) { struct MenuData *mpdata; AwtGraphicsConfigDataPtr adata; AWT_LOCK(); if (JNU_IsNull(env, parent)) { JNU_ThrowNullPointerException(env, "NullPointerException"); AWT_UNLOCK(); return; } mpdata = (struct MenuData *) JNU_GetLongFieldAsPtr(env, parent, mMenuItemPeerIDs.pData); if (mpdata == NULL) { JNU_ThrowNullPointerException(env, "NullPointerException"); AWT_UNLOCK(); return; } awtJNI_CreateMenu(env, this, mpdata->itemData.comp.widget); AWT_UNLOCK(); } /* * Class: sun_awt_motif_MMenuPeer * Method: pDispose * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_pDispose (JNIEnv *env, jobject this) { struct MenuData *mdata; Widget parent; Boolean isParentManaged = False; AWT_LOCK(); mdata = (struct MenuData *) JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); if (mdata == NULL) { AWT_UNLOCK(); return; } awt_delMenuWidget(mdata->itemData.comp.widget); XtUnmanageChild(mdata->comp.widget); awt_util_consumeAllXEvents(mdata->itemData.comp.widget); awt_util_consumeAllXEvents(mdata->comp.widget); parent = XtParent(mdata->itemData.comp.widget); if (parent != NULL && XtIsManaged(parent)) { isParentManaged = True; XtUnmanageChild(parent); } XtDestroyWidget(mdata->itemData.comp.widget); if (isParentManaged) { XtManageChild(parent); } XtDestroyWidget(mdata->comp.widget); free((void *) mdata); AWT_UNLOCK(); }