blob: 3b2b3918dec6a4095c254eb0b44d12cf1f3ccd6c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
47extern struct MenuComponentIDs menuComponentIDs;
48extern struct MenuItemIDs menuItemIDs;
49extern struct MMenuItemPeerIDs mMenuItemPeerIDs;
50extern struct MMenuBarPeerIDs mMenuBarPeerIDs;
51
52struct 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
64JNIEXPORT 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 */
76static 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 */
87static 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
95extern Boolean skipNextNotifyWhileGrabbed;
96
97static void
98Menu_popDownCB(Widget w, XtPointer client_data, XtPointer calldata)
99{
100 skipNextNotifyWhileGrabbed = True;
101}
102
103
104
105/*
106 * this is a MMenuPeer instance
107 */
108static void
109awtJNI_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 */
312JNIEXPORT 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 */
342JNIEXPORT 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 */
372JNIEXPORT 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}