1 /* |
|
2 * Copyright 1996-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 <Xm/Separator.h> |
|
32 #include <Xm/MenuShell.h> |
|
33 #include <Xm/RowColumn.h> |
|
34 #include "color.h" |
|
35 #include "java_awt_PopupMenu.h" |
|
36 #include "java_awt_Component.h" |
|
37 #include "java_awt_Event.h" |
|
38 #include "sun_awt_motif_MPopupMenuPeer.h" |
|
39 #include "sun_awt_motif_MComponentPeer.h" |
|
40 |
|
41 #include "awt_PopupMenu.h" |
|
42 #include "awt_MenuItem.h" |
|
43 #include "awt_Component.h" |
|
44 #include "awt_MenuComponent.h" |
|
45 #include "awt_Menu.h" |
|
46 #include "awt_Event.h" |
|
47 |
|
48 #include "multi_font.h" |
|
49 #include <jni.h> |
|
50 #include <jni_util.h> |
|
51 |
|
52 extern struct MMenuItemPeerIDs mMenuItemPeerIDs; |
|
53 extern struct MComponentPeerIDs mComponentPeerIDs; |
|
54 extern struct MenuComponentIDs menuComponentIDs; |
|
55 extern struct MenuItemIDs menuItemIDs; |
|
56 extern struct MenuIDs menuIDs; |
|
57 extern AwtGraphicsConfigDataPtr |
|
58 getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject parentPeer); |
|
59 extern Boolean keyboardGrabbed; |
|
60 Boolean poppingDown = False; |
|
61 |
|
62 struct MPopupMenuPeerIDs mPopupMenuPeerIDs; |
|
63 |
|
64 static Widget activePopup; |
|
65 |
|
66 void removePopupMenus() { |
|
67 if (activePopup != NULL && |
|
68 XtIsManaged(activePopup)) |
|
69 { |
|
70 XtUnmanageChild(activePopup); |
|
71 activePopup = NULL; |
|
72 } |
|
73 } |
|
74 |
|
75 Boolean awtMenuIsActive() { |
|
76 return ((activePopup != NULL) || (awt_util_focusIsOnMenu(awt_display))); |
|
77 } |
|
78 |
|
79 struct ClientDataStruct { |
|
80 struct ComponentData *wdata; |
|
81 jobject mMenuItemPeerIDs; |
|
82 }; |
|
83 |
|
84 /* |
|
85 * Class: sun_awt_motif_MPopupMenuPeer |
|
86 * Method: initIDs |
|
87 * Signature: ()V |
|
88 */ |
|
89 |
|
90 /* This function gets called from the static initializer for |
|
91 MPopupMenuPeer.java to initialize the methodIDs for methods that may |
|
92 be accessed from C */ |
|
93 |
|
94 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_initIDs |
|
95 (JNIEnv *env, jclass cls) |
|
96 { |
|
97 mPopupMenuPeerIDs.destroyNativeWidgetAfterGettingTreeLock = |
|
98 (*env)->GetMethodID(env, cls, |
|
99 "destroyNativeWidgetAfterGettingTreeLock", "()V"); |
|
100 } |
|
101 |
|
102 extern Boolean skipNextNotifyWhileGrabbed; |
|
103 |
|
104 static void |
|
105 Popup_popUpCB(Widget w, XtPointer client_data, XtPointer calldata) |
|
106 { |
|
107 skipNextNotifyWhileGrabbed = True; |
|
108 } |
|
109 /* |
|
110 * client_data is MPopupMenuPeer instance |
|
111 */ |
|
112 static void |
|
113 Popup_popdownCB(Widget w, XtPointer client_data, XtPointer calldata) |
|
114 { |
|
115 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
|
116 jobject target = NULL; |
|
117 |
|
118 /* |
|
119 * Fix for 4394847. Due to the race keyboard remains grabbed after menu |
|
120 * was disposed. Clear the grab status here instead of processOneEvent. |
|
121 */ |
|
122 poppingDown = True; |
|
123 keyboardGrabbed = False; |
|
124 skipNextNotifyWhileGrabbed = True; |
|
125 |
|
126 XtRemoveCallback(w, XtNpopdownCallback, |
|
127 Popup_popdownCB, (XtPointer) client_data); |
|
128 |
|
129 (*env)->CallVoidMethod(env, (jobject) client_data, |
|
130 mPopupMenuPeerIDs.destroyNativeWidgetAfterGettingTreeLock); |
|
131 |
|
132 if ((*env)->ExceptionOccurred(env)) { |
|
133 (*env)->ExceptionDescribe(env); |
|
134 (*env)->ExceptionClear(env); |
|
135 } |
|
136 } |
|
137 |
|
138 /* |
|
139 * Class: sun_awt_motif_MPopupMenuPeer |
|
140 * Method: createMenu |
|
141 * Signature: (Lsun/awt/motif/MComponentPeer;)V |
|
142 */ |
|
143 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_createMenu |
|
144 (JNIEnv *env, jobject this, jobject parent) |
|
145 { |
|
146 struct ComponentData *wdata; |
|
147 struct MenuData *mdata; |
|
148 struct FontData *fdata; |
|
149 char *ctitle = NULL; |
|
150 int32_t argc; |
|
151 #define MAX_ARGC 10 |
|
152 Arg args[MAX_ARGC]; |
|
153 Pixel bg; |
|
154 Pixel fg; |
|
155 XmFontList fontlist = NULL; |
|
156 XmString mfstr = NULL; |
|
157 jobject font; |
|
158 jobject target; |
|
159 jobject targetFont; |
|
160 jobject label; |
|
161 jboolean IsMultiFont; |
|
162 jboolean tearOff; |
|
163 jobject globalRef = (*env)->NewGlobalRef(env, this); |
|
164 AwtGraphicsConfigDataPtr adata; |
|
165 |
|
166 JNU_SetLongFieldFromPtr(env, this, |
|
167 mMenuItemPeerIDs.jniGlobalRef, globalRef); |
|
168 |
|
169 |
|
170 AWT_LOCK(); |
|
171 |
|
172 if (JNU_IsNull(env, parent)) { |
|
173 JNU_ThrowNullPointerException(env, "NullPointerException"); |
|
174 AWT_UNLOCK(); |
|
175 return; |
|
176 } |
|
177 target = |
|
178 (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); |
|
179 wdata = (struct ComponentData *) |
|
180 JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); |
|
181 |
|
182 if (wdata == NULL || JNU_IsNull(env, target)) { |
|
183 JNU_ThrowNullPointerException(env, "NullPointerException"); |
|
184 AWT_UNLOCK(); |
|
185 return; |
|
186 } |
|
187 mdata = ZALLOC(MenuData); |
|
188 if (mdata == NULL) { |
|
189 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); |
|
190 AWT_UNLOCK(); |
|
191 return; |
|
192 } |
|
193 JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata); |
|
194 |
|
195 adata = getGraphicsConfigFromComponentPeer(env, parent); |
|
196 |
|
197 /* |
|
198 * Why are these different? |
|
199 */ |
|
200 font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", |
|
201 "()Ljava/awt/Font;").l; |
|
202 targetFont = |
|
203 (*env)->GetObjectField(env, target, menuComponentIDs.font); |
|
204 if (!JNU_IsNull(env, targetFont) && |
|
205 (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { |
|
206 IsMultiFont = awtJNI_IsMultiFont(env, targetFont); |
|
207 } else { |
|
208 IsMultiFont = awtJNI_IsMultiFont(env, font); |
|
209 } |
|
210 |
|
211 label = (*env)->GetObjectField(env, target, menuItemIDs.label); |
|
212 if (JNU_IsNull(env, label)) { |
|
213 mfstr = XmStringCreateLocalized(""); |
|
214 ctitle = ""; |
|
215 } else { |
|
216 if (IsMultiFont) { |
|
217 mfstr = awtJNI_MakeMultiFontString(env, label, font); |
|
218 } else { |
|
219 ctitle = (char *) JNU_GetStringPlatformChars(env, label, NULL); |
|
220 } |
|
221 } |
|
222 |
|
223 XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); |
|
224 XtVaGetValues(wdata->widget, XmNforeground, &fg, NULL); |
|
225 |
|
226 argc = 0; |
|
227 XtSetArg(args[argc], XmNbackground, bg); |
|
228 argc++; |
|
229 XtSetArg(args[argc], XmNforeground, fg); |
|
230 argc++; |
|
231 tearOff = (*env)->GetBooleanField(env, target, menuIDs.tearOff); |
|
232 if (tearOff) { |
|
233 XtSetArg(args[argc], XmNtearOffModel, XmTEAR_OFF_ENABLED); |
|
234 argc++; |
|
235 } |
|
236 if (!JNU_IsNull(env, targetFont) |
|
237 && (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { |
|
238 if (IsMultiFont) { |
|
239 fontlist = awtJNI_GetFontList(env, targetFont); |
|
240 } else { |
|
241 fontlist = XmFontListCreate(fdata->xfont, "labelFont"); |
|
242 } |
|
243 |
|
244 XtSetArg(args[argc], XmNfontList, fontlist); |
|
245 argc++; |
|
246 } else { |
|
247 if (IsMultiFont) { |
|
248 fontlist = awtJNI_GetFontList(env, font); |
|
249 XtSetArg(args[argc], XmNfontList, fontlist); |
|
250 argc++; |
|
251 } |
|
252 } |
|
253 |
|
254 XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual); |
|
255 argc++; |
|
256 XtSetArg (args[argc], XmNscreen, |
|
257 ScreenOfDisplay(awt_display, |
|
258 adata->awt_visInfo.screen)); |
|
259 argc++; |
|
260 |
|
261 if (IsMultiFont) { |
|
262 DASSERT(!(argc > MAX_ARGC)); |
|
263 mdata->itemData.comp.widget = XmCreatePopupMenu(wdata->widget, |
|
264 "", |
|
265 args, |
|
266 argc); |
|
267 } else { |
|
268 DASSERT(!(argc > MAX_ARGC)); |
|
269 mdata->itemData.comp.widget = XmCreatePopupMenu(wdata->widget, |
|
270 ctitle, |
|
271 args, |
|
272 argc); |
|
273 } |
|
274 awt_addMenuWidget(mdata->itemData.comp.widget); |
|
275 |
|
276 /* |
|
277 * Fix for bug 4180147 - |
|
278 * screen can be frozen when interacting with MB3 using AWT on Motif |
|
279 */ |
|
280 XtUngrabButton(wdata->widget, AnyButton, AnyModifier); |
|
281 XtUngrabPointer(wdata->widget, CurrentTime); |
|
282 |
|
283 /* fix for bug #4169155: Popup menus get a leading separator on Motif |
|
284 system. |
|
285 Additional check that title string is not empty*/ |
|
286 if (!JNU_IsNull(env, label) && |
|
287 (*env)->GetStringUTFLength( env, label) != (jsize)0 ) { |
|
288 if (IsMultiFont) { |
|
289 XtVaCreateManagedWidget("", |
|
290 xmLabelWidgetClass, |
|
291 mdata->itemData.comp.widget, |
|
292 XmNfontList, fontlist, |
|
293 XmNlabelString, mfstr, |
|
294 XmNbackground, bg, |
|
295 XmNforeground, fg, |
|
296 XmNhighlightColor, fg, |
|
297 NULL); |
|
298 XmStringFree(mfstr); |
|
299 } else { |
|
300 XmString xmstr = XmStringCreateLocalized(ctitle); |
|
301 |
|
302 XtVaCreateManagedWidget(ctitle, |
|
303 xmLabelWidgetClass, |
|
304 mdata->itemData.comp.widget, |
|
305 XmNlabelString, xmstr, |
|
306 XmNbackground, bg, |
|
307 XmNforeground, fg, |
|
308 XmNhighlightColor, fg, |
|
309 NULL); |
|
310 XmStringFree(xmstr); |
|
311 JNU_ReleaseStringPlatformChars(env, label, (const char *) ctitle); |
|
312 } |
|
313 /* Create separator */ |
|
314 XtVaCreateManagedWidget("", |
|
315 xmSeparatorWidgetClass, |
|
316 mdata->itemData.comp.widget, |
|
317 XmNbackground, bg, |
|
318 XmNforeground, fg, |
|
319 NULL); |
|
320 } |
|
321 if (tearOff) { |
|
322 Widget tearOffWidget = XmGetTearOffControl(mdata->itemData.comp.widget); |
|
323 |
|
324 XtVaSetValues(tearOffWidget, |
|
325 XmNbackground, bg, |
|
326 XmNforeground, fg, |
|
327 XmNhighlightColor, fg, |
|
328 NULL); |
|
329 } |
|
330 mdata->comp.widget = mdata->itemData.comp.widget; |
|
331 |
|
332 if (!JNU_IsNull(env, targetFont)) { |
|
333 XmFontListFree(fontlist); |
|
334 } |
|
335 XtSetSensitive(mdata->comp.widget, |
|
336 ((*env)->GetBooleanField(env, target, menuItemIDs.enabled) ? |
|
337 True : False)); |
|
338 |
|
339 AWT_UNLOCK(); |
|
340 } |
|
341 |
|
342 /* |
|
343 * Class: sun_awt_motif_MPopupMenuPeer |
|
344 * Method: pShow |
|
345 * Signature: (Ljava/awt/Event;IILsun/awt/motif/MComponentPeer;)V |
|
346 */ |
|
347 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_pShow |
|
348 (JNIEnv *env, jobject this, jobject event, jint x, jint y, jobject origin) |
|
349 { |
|
350 struct MenuData *mdata; |
|
351 struct ComponentData *wdata; |
|
352 XButtonEvent *bevent; |
|
353 XButtonEvent *newEvent = NULL; |
|
354 void *data; |
|
355 |
|
356 AWT_LOCK(); |
|
357 |
|
358 mdata = (struct MenuData *) |
|
359 JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); |
|
360 if (mdata == NULL || JNU_IsNull(env, event)) { |
|
361 JNU_ThrowNullPointerException(env, "NullPointerException"); |
|
362 AWT_UNLOCK(); |
|
363 return; |
|
364 } |
|
365 |
|
366 wdata = (struct ComponentData *) |
|
367 JNU_GetLongFieldAsPtr(env, origin, mComponentPeerIDs.pData); |
|
368 |
|
369 if ( wdata == NULL || wdata->widget == NULL ) { /* 425598 */ |
|
370 JNU_ThrowNullPointerException(env, "NullPointerException"); /* 425598 */ |
|
371 AWT_UNLOCK(); /* 425598 */ |
|
372 return; /* 425598 */ |
|
373 } /* 425598 */ |
|
374 |
|
375 if (!XtIsRealized(wdata->widget)) { |
|
376 JNU_ThrowInternalError(env, "widget not visible on screen"); |
|
377 AWT_UNLOCK(); |
|
378 return; |
|
379 } |
|
380 |
|
381 /* |
|
382 * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time. |
|
383 * If another popup is currently visible hide it. |
|
384 */ |
|
385 if (activePopup != NULL && |
|
386 activePopup != mdata->comp.widget && |
|
387 XtIsObject(activePopup) && |
|
388 XtIsManaged(activePopup)) { |
|
389 removePopupMenus(); |
|
390 } |
|
391 |
|
392 /* If the raw x event is not available, then we must use an unfortunate |
|
393 * round-trip call to XTranslateCoordiates to get the root coordinates. |
|
394 */ |
|
395 data = JNU_GetLongFieldAsPtr(env, event, eventIDs.data); |
|
396 if (data == NULL || ((XEvent *) data)->type != ButtonPress) { |
|
397 int32_t rx, ry; |
|
398 Window root, win; |
|
399 |
|
400 root = RootWindowOfScreen(XtScreen(wdata->widget)); |
|
401 XTranslateCoordinates(awt_display, |
|
402 XtWindow(wdata->widget), |
|
403 root, |
|
404 (int32_t) x, (int32_t) y, |
|
405 &rx, &ry, |
|
406 &win); |
|
407 /* |
|
408 printf("translated coords %d,%d to root %d,%d\n", x, y, rx, ry); |
|
409 */ |
|
410 |
|
411 newEvent = (XButtonEvent *) malloc(sizeof(XButtonEvent)); |
|
412 newEvent->type = ButtonPress; |
|
413 newEvent->display = awt_display; |
|
414 newEvent->window = XtWindow(wdata->widget); |
|
415 newEvent->time = awt_util_getCurrentServerTime(); |
|
416 newEvent->x = (int32_t) x; |
|
417 newEvent->y = (int32_t) y; |
|
418 newEvent->x_root = rx; |
|
419 newEvent->y_root = ry; |
|
420 bevent = newEvent; |
|
421 |
|
422 } else { |
|
423 bevent = (XButtonEvent *) data; |
|
424 } |
|
425 |
|
426 XtAddCallback(XtParent(mdata->comp.widget), XtNpopdownCallback, |
|
427 Popup_popdownCB, |
|
428 (XtPointer) |
|
429 JNU_GetLongFieldAsPtr(env, this, |
|
430 mMenuItemPeerIDs.jniGlobalRef)); |
|
431 |
|
432 XtAddCallback(XtParent(mdata->comp.widget), XtNpopupCallback, |
|
433 Popup_popUpCB, |
|
434 (XtPointer) |
|
435 JNU_GetLongFieldAsPtr(env, this, |
|
436 mMenuItemPeerIDs.jniGlobalRef)); |
|
437 |
|
438 |
|
439 XmMenuPosition(mdata->comp.widget, bevent); |
|
440 XtManageChild(mdata->comp.widget); |
|
441 |
|
442 /* |
|
443 * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time. |
|
444 * Store the pointer to the currently showing popup. |
|
445 */ |
|
446 activePopup = mdata->comp.widget; |
|
447 |
|
448 if (newEvent) { |
|
449 free((void *) newEvent); |
|
450 } |
|
451 AWT_UNLOCK(); |
|
452 } |
|
453 |
|
454 /* |
|
455 * Class: sun_awt_motif_MPopupMenuPeer |
|
456 * Method: pDispose |
|
457 * Signature: ()V |
|
458 */ |
|
459 JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_pDispose |
|
460 (JNIEnv *env, jobject this) |
|
461 { |
|
462 struct MenuData *mdata; |
|
463 |
|
464 AWT_LOCK(); |
|
465 |
|
466 mdata = (struct MenuData *) |
|
467 JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); |
|
468 |
|
469 if (mdata == NULL) { |
|
470 AWT_UNLOCK(); |
|
471 return; |
|
472 } |
|
473 /* |
|
474 * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time. |
|
475 * Clear the pointer to the currently showing popup. |
|
476 */ |
|
477 if (activePopup == mdata->comp.widget) { |
|
478 activePopup = NULL; |
|
479 } |
|
480 awt_delMenuWidget(mdata->itemData.comp.widget); |
|
481 XtUnmanageChild(mdata->comp.widget); |
|
482 awt_util_consumeAllXEvents(mdata->comp.widget); |
|
483 XtDestroyWidget(mdata->comp.widget); |
|
484 free((void *) mdata); |
|
485 (*env)->SetLongField(env, this, mMenuItemPeerIDs.pData, (jlong)0); |
|
486 |
|
487 awtJNI_DeleteGlobalMenuRef(env, this); |
|
488 |
|
489 poppingDown = False; |
|
490 AWT_UNLOCK(); |
|
491 } |
|