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 } |
|