blob: 3b2b3918dec6a4095c254eb0b44d12cf1f3ccd6c [file] [log] [blame]
/*
* 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 <jni.h>
#include <jni_util.h>
#include <Xm/CascadeBP.h>
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();
}