1 /* 2 * Copyright (c) 1995, 2003, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 "awt_TopLevel.h" 33 #include <X11/IntrinsicP.h> 34 #include <X11/Xatom.h> 35 #include <X11/Xmd.h> 36 #include <X11/Xutil.h> 37 #include <X11/Xproto.h> 38 #ifndef XAWT 39 #include <Xm/MenuShell.h> 40 #include <Xm/List.h> 41 #include <Xm/Form.h> 42 #include <Xm/RowColumn.h> 43 #include <Xm/MwmUtil.h> 44 #endif /* XAWT */ 45 #include <jni.h> 46 #include <jni_util.h> 47 #include <sys/time.h> 48 49 #include "awt_xembed.h" 50 51 52 #ifndef XAWT 53 #if MOTIF_VERSION!=1 54 #include <Xm/GrabShell.h> 55 #endif 56 #endif 57 58 #include "java_awt_event_MouseWheelEvent.h" 59 60 /* 61 * Since X reports protocol errors asynchronously, we often need to 62 * install an error handler that acts like a callback. While that 63 * specialized handler is installed we save original handler here. 64 */ 65 XErrorHandler xerror_saved_handler; 66 67 /* 68 * A place for error handler to report the error code. 69 */ 70 unsigned char xerror_code; 71 72 extern jint getModifiers(uint32_t state, jint button, jint keyCode); 73 extern jint getButton(uint32_t button); 74 75 static int32_t winmgr_running = 0; 76 static Atom OLDecorDelAtom = 0; 77 static Atom MWMHints = 0; 78 static Atom DTWMHints = 0; 79 static Atom decor_list[9]; 80 81 #ifndef MAX 82 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 83 #endif 84 85 #ifndef MIN 86 #define MIN(a,b) ((a) < (b) ? (a) : (b)) 87 #endif 88 89 #ifndef XAWT 90 /* 91 * The following three funtions are to work around menu problems 92 */ 93 94 /* 95 * test if there is a menu that has the current focus 96 * called from awt_Dialog.c and awt_Component.c 97 */ 98 Boolean 99 awt_util_focusIsOnMenu(Display *display) 100 { 101 Window window; 102 Widget widget; 103 int32_t rtr; 104 105 XGetInputFocus(display, &window, &rtr); 106 if (window == None) { 107 return False; 108 } 109 110 widget = XtWindowToWidget(display, window); 111 if (widget == NULL) { 112 return False; 113 } 114 115 if (XtIsSubclass(widget, xmMenuShellWidgetClass)) { 116 return True; 117 } 118 119 #if MOTIF_VERSION!=1 120 /* Motif 2.1 uses XmGrabShell on XmComboBox instead 121 of XmMenuShell 122 */ 123 if (XtIsSubclass(widget, xmGrabShellWidgetClass)) { 124 return True; 125 } 126 /* Fix 4800638 check the ancestor of focus widget is 127 GrabSell 128 */ 129 if (XtIsSubclass(widget, xmListWidgetClass)) 130 { 131 Widget shell = getShellWidget(widget); 132 if (shell && XtIsSubclass(shell, 133 xmGrabShellWidgetClass)) 134 { 135 return True; 136 } 137 } 138 #endif 139 140 if (XtIsSubclass(widget, xmRowColumnWidgetClass)) { 141 unsigned char type; 142 XtVaGetValues(widget, XmNrowColumnType, &type, NULL); 143 if (type == XmMENU_BAR) { 144 return True; 145 } 146 } 147 return False; 148 } 149 150 static 151 void fillButtonEvent(XButtonEvent *ev, int32_t type, Display *display, Window window) { 152 ev->type = type; 153 ev->display = display; 154 ev->window = window; 155 ev->send_event = True; 156 157 /* REMIND: multi-screen */ 158 ev->root = RootWindow(display, DefaultScreen(display)); 159 ev->subwindow = (Window)None; 160 ev->time = CurrentTime; 161 ev->x = 0; 162 ev->y = 0; 163 ev->x_root = 0; 164 ev->y_root = 0; 165 ev->same_screen = True; 166 ev->button = Button1; 167 ev->state = Button1Mask; 168 } 169 170 /* 171 * generates a mouse press event and a release event 172 * called from awt_Dialog.c 173 */ 174 int32_t 175 awt_util_sendButtonClick(Display *display, Window window) 176 { 177 XButtonEvent ev; 178 int32_t status; 179 180 fillButtonEvent(&ev, ButtonPress, display, window); 181 status = XSendEvent(display, window, True, ButtonPressMask, (XEvent *)&ev); 182 183 if (status != 0) { 184 fillButtonEvent(&ev, ButtonRelease, display, window); 185 status = XSendEvent(display, window, False, ButtonReleaseMask, 186 (XEvent *)&ev); 187 } 188 return status; 189 } 190 191 Widget 192 awt_util_createWarningWindow(Widget parent, char *warning) 193 { 194 Widget warningWindow; 195 #ifdef NETSCAPE 196 extern Widget FE_MakeAppletSecurityChrome(Widget parent, char* message); 197 warningWindow = FE_MakeAppletSecurityChrome(parent, warning); 198 #else 199 Widget label; 200 int32_t argc; 201 #define MAX_ARGC 10 202 Arg args[MAX_ARGC]; 203 int32_t screen = 0; 204 int32_t i; 205 AwtGraphicsConfigDataPtr adata; 206 extern int32_t awt_numScreens; 207 208 Pixel gray; 209 Pixel black; 210 211 for (i = 0; i < awt_numScreens; i++) { 212 if (ScreenOfDisplay(awt_display, i) == XtScreen(parent)) { 213 screen = i; 214 break; 215 } 216 } 217 adata = getDefaultConfig(screen); 218 219 gray = adata->AwtColorMatch(192, 192, 192, adata); 220 black = adata->AwtColorMatch(0, 0, 0, adata); 221 222 argc = 0; 223 XtSetArg(args[argc], XmNbackground, gray); argc++; 224 XtSetArg(args[argc], XmNmarginHeight, 0); argc++; 225 XtSetArg(args[argc], XmNmarginWidth, 0); argc++; 226 XtSetArg (args[argc], XmNscreen, XtScreen(parent)); argc++; 227 228 DASSERT(!(argc > MAX_ARGC)); 229 warningWindow = XmCreateForm(parent, "main", args, argc); 230 231 XtManageChild(warningWindow); 232 label = XtVaCreateManagedWidget(warning, 233 xmLabelWidgetClass, warningWindow, 234 XmNhighlightThickness, 0, 235 XmNbackground, gray, 236 XmNforeground, black, 237 XmNalignment, XmALIGNMENT_CENTER, 238 XmNrecomputeSize, False, 239 NULL); 240 XtVaSetValues(label, 241 XmNbottomAttachment, XmATTACH_FORM, 242 XmNtopAttachment, XmATTACH_FORM, 243 XmNleftAttachment, XmATTACH_FORM, 244 XmNrightAttachment, XmATTACH_FORM, 245 NULL); 246 #endif 247 return warningWindow; 248 } 249 250 void 251 awt_setWidgetGravity(Widget w, int32_t gravity) 252 { 253 XSetWindowAttributes xattr; 254 Window win = XtWindow(w); 255 256 if (win != None) { 257 xattr.bit_gravity = StaticGravity; 258 xattr.win_gravity = StaticGravity; 259 XChangeWindowAttributes(XtDisplay(w), win, 260 CWBitGravity|CWWinGravity, 261 &xattr); 262 } 263 } 264 265 Widget get_shell_focused_widget(Widget w) { 266 while (w != NULL && !XtIsShell(w)) { 267 w = XtParent(w); 268 } 269 if (w != NULL) { 270 return XmGetFocusWidget(w); 271 } else { 272 return NULL; 273 } 274 } 275 276 void 277 awt_util_reshape(Widget w, jint x, jint y, jint wd, jint ht) 278 { 279 Widget parent; 280 Dimension ww, wh; 281 Position wx, wy; 282 Boolean move = False; 283 Boolean resize = False; 284 Boolean mapped_when_managed = False; 285 Boolean need_to_unmanage = True; 286 Widget saved_focus_widget = NULL; 287 288 if (w == NULL) { 289 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 290 JNU_ThrowNullPointerException(env,"NullPointerException"); 291 return; 292 } 293 parent = XtParent(w); 294 295 /* Aim: hack to prevent direct children of scrollpane from 296 * being unmanaged during a reshape operation (which results 297 * in too many expose events). 298 */ 299 if (parent != NULL && XtParent(parent) != NULL && 300 XtIsSubclass(XtParent(parent), xmScrolledWindowWidgetClass)) { 301 need_to_unmanage = False; 302 } 303 304 XtVaGetValues(w, 305 XmNwidth, &ww, 306 XmNheight, &wh, 307 XmNx, &wx, 308 XmNy, &wy, 309 NULL); 310 311 if (x != wx || y != wy) { 312 move = True; 313 } 314 if (wd != ww || ht != wh) { 315 resize = True; 316 } 317 if (!move && !resize) { 318 return; 319 } 320 321 if (need_to_unmanage) { 322 if (!resize) { 323 mapped_when_managed = w->core.mapped_when_managed; 324 w->core.mapped_when_managed = False; 325 } 326 saved_focus_widget = get_shell_focused_widget(w); 327 XtUnmanageChild(w); 328 } 329 330 /* GES: AVH's hack: 331 * Motif ignores attempts to move a toplevel window to 0,0. 332 * Instead we set the position to 1,1. The expected value is 333 * returned by Frame.getBounds() since it uses the internally 334 * held rectangle rather than querying the peer. 335 * N.B. [pauly, 9/97] This is only required for wm shells 336 * under the Motif Window Manager (MWM), not for any others. 337 * Note. Utilizes C short-circuiting if w is not a wm shell. 338 */ 339 if ((x == 0) && (y == 0) && 340 (XtIsSubclass(w, wmShellWidgetClass)) && 341 (XmIsMotifWMRunning(w))) { 342 XtVaSetValues(w, XmNx, 1, XmNy, 1, NULL); 343 } 344 345 if (move && !resize) { 346 XtVaSetValues(w, XmNx, x, XmNy, y, NULL); 347 348 } else if (resize && !move) { 349 XtVaSetValues(w, 350 XmNwidth, (wd > 0) ? wd : 1, 351 XmNheight, (ht > 0) ? ht : 1, 352 NULL); 353 354 } else { 355 XtVaSetValues(w, 356 XmNx, x, 357 XmNy, y, 358 XmNwidth, (wd > 0) ? wd : 1, 359 XmNheight, (ht > 0) ? ht : 1, 360 NULL); 361 } 362 363 if (need_to_unmanage) { 364 XtManageChild(w); 365 if (!resize) { 366 w->core.mapped_when_managed = mapped_when_managed; 367 } 368 if (saved_focus_widget != NULL) { 369 Boolean result = XmProcessTraversal(saved_focus_widget, XmTRAVERSE_CURRENT); 370 if (!result) 371 { 372 Widget shell = saved_focus_widget; 373 while(shell != NULL && !XtIsShell(shell)) { 374 shell = XtParent(shell); 375 } 376 XtSetKeyboardFocus(shell, saved_focus_widget); 377 } 378 } 379 } 380 } 381 382 void 383 awt_util_hide(Widget w) 384 { 385 if (w == NULL) { 386 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 387 JNU_ThrowNullPointerException(env,"NullPointerException"); 388 return; 389 } 390 XtSetMappedWhenManaged(w, False); 391 } 392 393 void 394 awt_util_show(Widget w) 395 { 396 /* 397 extern Boolean scrollBugWorkAround; 398 */ 399 if (w == NULL) { 400 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 401 JNU_ThrowNullPointerException(env,"NullPointerException"); 402 return; 403 } 404 XtSetMappedWhenManaged(w, True); 405 /* 406 XXX: causes problems on 2.5 407 if (!scrollBugWorkAround) { 408 awt_setWidgetGravity(w, StaticGravity); 409 } 410 */ 411 } 412 413 void 414 awt_util_enable(Widget w) 415 { 416 XtSetSensitive(w, True); 417 } 418 419 void 420 awt_util_disable(Widget w) 421 { 422 XtSetSensitive(w, False); 423 } 424 425 void 426 awt_util_mapChildren(Widget w, void (*func)(Widget,void *), 427 int32_t applyToCurrent, void *data) { 428 WidgetList wlist; 429 Cardinal wlen = 0; 430 Cardinal i; 431 432 /* The widget may have been destroyed by another thread. */ 433 if ((w == NULL) || (!XtIsObject(w)) || (w->core.being_destroyed)) 434 return; 435 436 if (applyToCurrent != 0) { 437 (*func)(w, data); 438 } 439 if (!XtIsComposite(w)) { 440 return; 441 } 442 443 XtVaGetValues(w, 444 XmNchildren, &wlist, 445 XmNnumChildren, &wlen, 446 NULL); 447 if (wlen > 0) { 448 for (i=0; i < wlen; i++) { 449 awt_util_mapChildren(wlist[i], func, 1, data); 450 } 451 } 452 } 453 454 void 455 awt_changeAttributes(Display *dpy, Widget w, unsigned long mask, 456 XSetWindowAttributes *xattr) 457 { 458 WidgetList wlist; 459 Cardinal wlen = 0; 460 Cardinal i; 461 462 if (XtWindow(w) && XtIsRealized(w)) { 463 XChangeWindowAttributes(dpy, 464 XtWindow(w), 465 mask, 466 xattr); 467 } else { 468 return; 469 } 470 XtVaGetValues(w, 471 XmNchildren, &wlist, 472 XmNnumChildren, &wlen, 473 NULL); 474 for (i = 0; i < wlen; i++) { 475 if (XtWindow(wlist[i]) && XtIsRealized(wlist[i])) { 476 XChangeWindowAttributes(dpy, 477 XtWindow(wlist[i]), 478 mask, 479 xattr); 480 } 481 } 482 } 483 484 static Widget prevWgt = NULL; 485 486 static void 487 DestroyCB(Widget w, XtPointer client_data, XtPointer call_data) { 488 if (prevWgt == w) { 489 prevWgt = NULL; 490 } 491 } 492 493 int32_t 494 awt_util_setCursor(Widget w, Cursor c) { 495 static Cursor prevCur = None; 496 497 if (XtIsRealized(w)) { 498 unsigned long valuemask = 0; 499 XSetWindowAttributes attributes; 500 501 valuemask = CWCursor; 502 if (prevWgt != NULL) { 503 attributes.cursor = None; 504 XChangeWindowAttributes(awt_display, 505 XtWindow(prevWgt), 506 valuemask, 507 &attributes); 508 } 509 510 if (c == None) { 511 c = prevCur; 512 if (w != NULL) { 513 XtAddCallback(w, XmNdestroyCallback, DestroyCB, NULL); 514 } 515 prevWgt = w; 516 } else { 517 prevCur = c; 518 prevWgt = NULL; 519 } 520 attributes.cursor = c; 521 XChangeWindowAttributes(awt_display, 522 XtWindow(w), 523 valuemask, 524 &attributes); 525 XFlush(awt_display); 526 return 1; 527 } else 528 return 0; 529 } 530 531 void 532 awt_util_convertEventTimeAndModifiers(XEvent *event, 533 ConvertEventTimeAndModifiers *output) { 534 switch (event->type) { 535 case KeyPress: 536 case KeyRelease: 537 output->when = awt_util_nowMillisUTC_offset(event->xkey.time); 538 output->modifiers = getModifiers(event->xkey.state, 0, 0); 539 break; 540 case ButtonPress: 541 case ButtonRelease: 542 output->when = awt_util_nowMillisUTC_offset(event->xbutton.time); 543 output->modifiers = getModifiers(event->xbutton.state, 544 getButton(event->xbutton.button), 0); 545 break; 546 default: 547 output->when = awt_util_nowMillisUTC(); 548 output->modifiers =0; 549 break; 550 } 551 } 552 553 554 /* 555 Part fix for bug id 4017222. Return the widget at the given screen coords 556 by searching the widget tree beginning at root. This function will return 557 null if the pointer is not over the root widget or child of the root widget. 558 559 Additionally, this function will only return a Widget with non-nil XmNuserData. 560 In 1.2.1, when the mouse was dragged over a Choice component, this function 561 returned the GadgetButton associated with the Choice. This GadgetButton had 562 nil as its XmNuserData. This lead to a crash when the nil XmNuserData was 563 extracted and used as a reference to a peer. Ooops. 564 Now the GadgetButton is not returned and the function goes on to find a widget 565 which contains the correct peer reference in XmNuserData. 566 */ 567 Widget 568 awt_WidgetAtXY(Widget root, Position pointerx, Position pointery) { 569 Widget answer = NULL; 570 571 if(!root) return NULL; 572 573 if(XtIsComposite(root)) { 574 int32_t i=0; 575 WidgetList wl=NULL; 576 Cardinal wlen=0; 577 578 XtVaGetValues(root, XmNchildren, &wl, XmNnumChildren, &wlen, NULL); 579 580 if(wlen>0) { 581 for(i=0; i<wlen && !answer; i++) { 582 answer = awt_WidgetAtXY(wl[i], pointerx, pointery); 583 } 584 } 585 } 586 587 if(!answer) { 588 Position wx=0, wy=0; 589 Dimension width=0, height=0; 590 int32_t lastx=0, lasty=0; 591 XtPointer widgetUserData=NULL; 592 593 XtVaGetValues(root, XmNwidth, &width, XmNheight, &height, 594 XmNuserData, &widgetUserData, 595 NULL); 596 597 XtTranslateCoords(root, 0, 0, &wx, &wy); 598 lastx = wx + width; 599 lasty = wy + height; 600 601 if(pointerx>=wx && pointerx<=lastx && pointery>=wy && pointery<=lasty && 602 widgetUserData) 603 answer = root; 604 } 605 606 return answer; 607 } 608 #ifdef __linux__ 609 610 611 #define MAXARGS 10 612 static Arg xic_vlist[MAXARGS]; 613 static Arg status_vlist[MAXARGS]; 614 static Arg preedit_vlist[MAXARGS]; 615 616 #define NO_ARG_VAL -1 617 #define SEPARATOR_HEIGHT 2 618 619 static XFontSet extract_fontset(XmFontList); 620 621 /* get_im_height: returns height of the input method status area in pixels. 622 * 623 * This function assumes that if any XIM related information cannot be 624 * queried then the app must not have an input method status area in the 625 * current locale and returns zero as the status area height 626 */ 627 628 static XtPointer* 629 get_im_info_ptr(Widget w, 630 Boolean create) 631 { 632 Widget p; 633 XmVendorShellExtObject ve; 634 XmWidgetExtData extData; 635 XmImShellInfo im_info; 636 XmImDisplayInfo xim_info; 637 638 if (w == NULL) 639 return NULL; 640 641 p = w; 642 while (!XtIsShell(p)) 643 p = XtParent(p); 644 645 /* Check extension data since app could be attempting to create 646 * a text widget as child of menu shell. This is illegal, and will 647 * be detected later, but check here so we don't core dump. 648 */ 649 if ((extData = _XmGetWidgetExtData((Widget)p, XmSHELL_EXTENSION)) == NULL) 650 return NULL; 651 652 ve = (XmVendorShellExtObject) extData->widget; 653 654 return &ve->vendor.im_info; 655 } 656 657 static XmImShellInfo 658 get_im_info(Widget w, 659 Boolean create) 660 { 661 XmImShellInfo* ptr = (XmImShellInfo *) get_im_info_ptr(w, create); 662 if (ptr != NULL) 663 return *ptr; 664 else 665 return NULL; 666 } 667 668 #endif /* !linux */ 669 670 Widget 671 awt_util_getXICStatusAreaWindow(Widget w) 672 { 673 while (!XtIsShell(w)){ 674 w = XtParent(w); 675 } 676 return w; 677 } 678 679 #ifdef __linux__ 680 static XRectangle geometryRect; 681 XVaNestedList awt_util_getXICStatusAreaList(Widget w) 682 { 683 XIC xic; 684 XmImXICInfo icp; 685 XmVendorShellExtObject ve; 686 XmWidgetExtData extData; 687 XmImShellInfo im_info; 688 XmFontList fl=NULL; 689 690 XRectangle *ssgeometry = &geometryRect; 691 XRectangle geomRect ; 692 XRectangle *im_rect; 693 XFontSet *im_font; 694 695 Pixel bg ; 696 Pixel fg ; 697 Dimension height, width ; 698 Position x,y ; 699 Pixmap bpm, *bpmout ; 700 701 XVaNestedList list = NULL; 702 703 char *ret; 704 Widget p=w; 705 706 while (!XtIsShell(p)) { 707 p = XtParent(p); 708 } 709 710 XtVaGetValues(p, 711 XmNx, &x, 712 XmNy, &y, 713 XmNwidth, &width, 714 XmNheight, &height, 715 XmNbackgroundPixmap, &bpm, 716 NULL); 717 718 extData = _XmGetWidgetExtData((Widget) p, XmSHELL_EXTENSION); 719 if (extData == NULL) { 720 return NULL; 721 } 722 ve = (XmVendorShellExtObject) extData->widget; 723 im_info = get_im_info(w, False); 724 725 if (im_info == NULL) { 726 return NULL; 727 } else { 728 icp = im_info->iclist; 729 } 730 731 if (icp) { 732 /* 733 * We have at least a textfield/textarea in the frame, use the 734 * first one. 735 */ 736 ssgeometry->x = 0; 737 ssgeometry->y = height - icp->sp_height; 738 ssgeometry->width = icp->status_width; 739 ssgeometry->height = icp->sp_height; 740 XtVaGetValues(w, XmNbackground, &bg, NULL); 741 XtVaGetValues(w, XmNforeground, &fg, NULL); 742 XtVaGetValues(w, XmNfontList, &fl, NULL); 743 /* 744 * use motif TextComponent's resource 745 */ 746 747 list = XVaCreateNestedList(0, 748 XNFontSet, extract_fontset(fl), 749 XNArea, ssgeometry, 750 XNBackground, bg, 751 XNForeground, fg, 752 NULL); 753 } 754 return list ; 755 } 756 757 static XFontSet 758 extract_fontset(XmFontList fl) 759 { 760 XmFontContext context; 761 XmFontListEntry next_entry; 762 XmFontType type_return; 763 XtPointer tmp_font; 764 XFontSet first_fs = NULL; 765 char *font_tag; 766 767 if (!XmFontListInitFontContext(&context, fl)) 768 return NULL; 769 770 do { 771 next_entry = XmFontListNextEntry(context); 772 if (next_entry) { 773 tmp_font = XmFontListEntryGetFont(next_entry, &type_return); 774 if (type_return == XmFONT_IS_FONTSET) { 775 font_tag = XmFontListEntryGetTag(next_entry); 776 if (!strcmp(font_tag, XmFONTLIST_DEFAULT_TAG)) { 777 XmFontListFreeFontContext(context); 778 XtFree(font_tag); 779 return (XFontSet) tmp_font; 780 } 781 XtFree(font_tag); 782 if (first_fs == NULL) 783 first_fs = (XFontSet) tmp_font; 784 } 785 } 786 } while (next_entry); 787 788 XmFontListFreeFontContext(context); 789 return first_fs; 790 } 791 #endif 792 793 /*the caller does have the responsibility to free the memory return 794 from this function...*/ 795 char* awt_util_makeWMMenuItem(char *target, Atom protocol){ 796 char *buf = NULL; 797 int32_t buflen = 0; 798 799 /*a label in a menuitem is not supposed to be a FullOfSpaceString... */ 800 buflen = strlen(target) * 3; 801 buf = (char*)malloc(buflen + 20); 802 if (buf == NULL){ 803 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL); 804 } 805 else{ 806 int32_t off = 0; 807 char *ptr = target; 808 while ((off < (buflen - 20)) && (*ptr != '\0')){ 809 if (*ptr == ' '){ 810 *(buf + off++) = 0x5c; 811 } 812 *(buf + off++) = *ptr++; 813 } 814 sprintf(buf + off, " f.send_msg %ld", protocol); 815 } 816 return buf; 817 } 818 819 /* 820 * This callback proc is installed via setting the XmNinsertPosition 821 * resource on a widget. It ensures that components added 822 * to a widget are inserted in the correct z-order position 823 * to match up with their peer/target ordering in Container.java 824 */ 825 Cardinal 826 awt_util_insertCallback(Widget w) 827 { 828 jobject peer; 829 WidgetList children; 830 Cardinal num_children; 831 Widget parent; 832 XtPointer userdata; 833 Cardinal index; 834 int32_t pos; 835 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 836 837 parent = XtParent(w); 838 XtVaGetValues(parent, 839 XmNnumChildren, &num_children, 840 XmNchildren, &children, 841 NULL); 842 XtVaGetValues(w, XmNuserData, &userdata, NULL); 843 844 index = num_children; /* default is to add to end */ 845 846 if (userdata != NULL) { 847 peer = (jobject) userdata; 848 849 // SECURITY: We are running on the privileged toolkit thread. 850 // The peer must *NOT* call into user code 851 pos = (int32_t) JNU_CallMethodByName(env 852 ,NULL 853 ,(jobject) peer 854 ,"getZOrderPosition_NoClientCode" 855 ,"()I").i; 856 if ((*env)->ExceptionOccurred(env)) { 857 (*env)->ExceptionDescribe(env); 858 (*env)->ExceptionClear(env); 859 } 860 index = (Cardinal) (pos != -1 ? pos : num_children); 861 } 862 return index; 863 } 864 865 void 866 awt_util_consumeAllXEvents(Widget widget) 867 { 868 /* Remove all queued X Events for the window of the widget. */ 869 870 #define ALL_EVENTS_MASK 0xFFFF 871 872 XEvent xev; 873 874 XFlush(awt_display); 875 while (XCheckWindowEvent(awt_display, XtWindow(widget), 876 ALL_EVENTS_MASK, &xev)) ; 877 } 878 879 #endif /* XAWT */ 880 /** 881 * Gets the thread we are currently executing on 882 */ 883 jobject 884 awtJNI_GetCurrentThread(JNIEnv *env) { 885 static jclass threadClass = NULL; 886 static jmethodID currentThreadMethodID = NULL; 887 888 jobject currentThread = NULL; 889 890 /* Initialize our java identifiers once. Checking before locking 891 * is a huge performance win. 892 */ 893 if (threadClass == NULL) { 894 // should enter a monitor here... 895 Boolean err = FALSE; 896 if (threadClass == NULL) { 897 jclass tc = (*env)->FindClass(env, "java/lang/Thread"); 898 threadClass = (*env)->NewGlobalRef(env, tc); 899 if (threadClass != NULL) { 900 currentThreadMethodID = (*env)->GetStaticMethodID(env, 901 threadClass, 902 "currentThread", 903 "()Ljava/lang/Thread;" 904 ); 905 } 906 } 907 if (currentThreadMethodID == NULL) { 908 threadClass = NULL; 909 err = TRUE; 910 } 911 if (err) { 912 return NULL; 913 } 914 } /* threadClass == NULL*/ 915 916 currentThread = (*env)->CallStaticObjectMethod( 917 env, threadClass, currentThreadMethodID); 918 DASSERT(!((*env)->ExceptionOccurred(env))); 919 /*JNU_PrintString(env, "getCurrentThread() -> ", JNU_ToString(env,currentThread));*/ 920 return currentThread; 921 } /* awtJNI_GetCurrentThread() */ 922 923 void 924 awtJNI_ThreadYield(JNIEnv *env) { 925 926 static jclass threadClass = NULL; 927 static jmethodID yieldMethodID = NULL; 928 929 /* Initialize our java identifiers once. Checking before locking 930 * is a huge performance win. 931 */ 932 if (threadClass == NULL) { 933 // should enter a monitor here... 934 Boolean err = FALSE; 935 if (threadClass == NULL) { 936 jclass tc = (*env)->FindClass(env, "java/lang/Thread"); 937 threadClass = (*env)->NewGlobalRef(env, tc); 938 (*env)->DeleteLocalRef(env, tc); 939 if (threadClass != NULL) { 940 yieldMethodID = (*env)->GetStaticMethodID(env, 941 threadClass, 942 "yield", 943 "()V" 944 ); 945 } 946 } 947 if (yieldMethodID == NULL) { 948 threadClass = NULL; 949 err = TRUE; 950 } 951 if (err) { 952 return; 953 } 954 } /* threadClass == NULL*/ 955 956 (*env)->CallStaticVoidMethod(env, threadClass, yieldMethodID); 957 DASSERT(!((*env)->ExceptionOccurred(env))); 958 } /* awtJNI_ThreadYield() */ 959 960 #ifndef XAWT 961 962 void 963 awt_util_cleanupBeforeDestroyWidget(Widget widget) 964 { 965 /* Bug 4017222: Drag processing uses global prevWidget. */ 966 if (widget == prevWidget) { 967 prevWidget = NULL; 968 } 969 } 970 971 static Boolean timeStampUpdated = False; 972 973 static int32_t 974 isTimeStampUpdated(void* p) { 975 return timeStampUpdated; 976 } 977 978 static void 979 propertyChangeEventHandler(Widget w, XtPointer client_data, 980 XEvent* event, Boolean* continue_to_dispatch) { 981 timeStampUpdated = True; 982 } 983 984 /* 985 * If the application doesn't receive events with timestamp for a long time 986 * XtLastTimestampProcessed() will return out-of-date value. This may cause 987 * selection handling routines to fail (see BugTraq ID 4085183). 988 * This routine is to resolve this problem. It queries the current X server 989 * time by appending a zero-length data to a property as prescribed by 990 * X11 Reference Manual. 991 * Note that this is a round-trip request, so it can be slow. If you know 992 * that the Xt timestamp is up-to-date use XtLastTimestampProcessed(). 993 */ 994 Time 995 awt_util_getCurrentServerTime() { 996 997 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 998 static Atom _XA_JAVA_TIME_PROPERTY_ATOM = 0; 999 Time server_time = 0; 1000 1001 AWT_LOCK(); 1002 1003 if (_XA_JAVA_TIME_PROPERTY_ATOM == 0) { 1004 XtAddEventHandler(awt_root_shell, PropertyChangeMask, False, 1005 propertyChangeEventHandler, NULL); 1006 _XA_JAVA_TIME_PROPERTY_ATOM = XInternAtom(awt_display, "_SUNW_JAVA_AWT_TIME", False); 1007 } 1008 1009 timeStampUpdated = False; 1010 XChangeProperty(awt_display, XtWindow(awt_root_shell), 1011 _XA_JAVA_TIME_PROPERTY_ATOM, XA_ATOM, 32, PropModeAppend, 1012 (unsigned char *)"", 0); 1013 XFlush(awt_display); 1014 1015 if (awt_currentThreadIsPrivileged(env)) { 1016 XEvent event; 1017 XMaskEvent(awt_display, PropertyChangeMask, &event); 1018 XtDispatchEvent(&event); 1019 } else { 1020 awt_MToolkit_modalWait(isTimeStampUpdated, NULL); 1021 } 1022 server_time = XtLastTimestampProcessed(awt_display); 1023 1024 AWT_UNLOCK(); 1025 1026 return server_time; 1027 } 1028 1029 /* 1030 * This function is stolen from /src/solaris/hpi/src/system_md.c 1031 * It is used in setting the time in Java-level InputEvents 1032 */ 1033 jlong 1034 awt_util_nowMillisUTC() 1035 { 1036 struct timeval t; 1037 gettimeofday(&t, NULL); 1038 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000); 1039 } 1040 1041 /* 1042 * This function converts between the X server time (number of milliseconds 1043 * since the last server reset) and the UTC time for the 'when' field of an 1044 * InputEvent (or another event type with a timestamp). 1045 */ 1046 jlong 1047 awt_util_nowMillisUTC_offset(Time server_offset) 1048 { 1049 /* 1050 * Because Time is of type 'unsigned long', it is possible that Time will 1051 * never wrap when using 64-bit Xlib. However, if a 64-bit client 1052 * connects to a 32-bit server, I suspect the values will still wrap. So 1053 * we should not attempt to remove the wrap checking even if _LP64 is 1054 * true. 1055 */ 1056 static const jlong WRAP_TIME_MILLIS = (jlong)((uint32_t)-1); 1057 static jlong reset_time_utc; 1058 1059 jlong current_time_utc = awt_util_nowMillisUTC(); 1060 1061 if ((current_time_utc - reset_time_utc) > WRAP_TIME_MILLIS) { 1062 reset_time_utc = awt_util_nowMillisUTC() - 1063 awt_util_getCurrentServerTime(); 1064 } 1065 1066 return reset_time_utc + server_offset; 1067 } 1068 1069 void awt_util_do_wheel_scroll(Widget scrolled_window, jint scrollType, 1070 jint scrollAmt, jint wheelAmt) { 1071 Widget scrollbar = NULL; 1072 int value; 1073 int slider_size; 1074 int min; 1075 int max; 1076 int increment; 1077 int page_increment; 1078 int scrollAdjustment; 1079 int newValue; 1080 1081 /* TODO: 1082 * If a TextArea's scrollbar policy is set to never, it should still 1083 * wheel scroll, but right now it doesn't. 1084 */ 1085 1086 scrollbar = awt_util_get_scrollbar_to_scroll(scrolled_window); 1087 if (scrollbar == NULL) { /* no suitable scrollbar for scrolling */ 1088 return; 1089 } 1090 1091 XtVaGetValues(scrollbar, XmNvalue, &value, 1092 XmNsliderSize, &slider_size, 1093 XmNminimum, &min, 1094 XmNmaximum, &max, 1095 XmNincrement, &increment, 1096 XmNpageIncrement, &page_increment, NULL); 1097 1098 if (scrollType == java_awt_event_MouseWheelEvent_WHEEL_BLOCK_SCROLL) { 1099 scrollAdjustment = page_increment; 1100 } 1101 else { // WHEEL_UNIT_SCROLL 1102 scrollAdjustment = increment * scrollAmt; 1103 } 1104 1105 if (wheelAmt < 0) { 1106 // Don't need to check that newValue < max - slider_size because 1107 // newValue < current value. If scrollAmt is ever user-configurable, 1108 // we'll have to check this. 1109 newValue = MAX(min, value+ (scrollAdjustment * wheelAmt)); 1110 } 1111 else { 1112 newValue = MIN(max - slider_size, 1113 value + (scrollAdjustment * wheelAmt)); 1114 } 1115 1116 XtVaSetValues(scrollbar, XmNvalue, newValue, NULL); 1117 XtCallCallbacks(scrollbar, XmNvalueChangedCallback, NULL); 1118 } 1119 1120 1121 /* Given a ScrollWindow widget, return the Scrollbar that the wheel should 1122 * scroll. A null return value means that the ScrollWindow has a scrollbar 1123 * display policy of none, or that neither scrollbar can be scrolled. 1124 */ 1125 Widget awt_util_get_scrollbar_to_scroll(Widget scrolled_window) { 1126 Widget scrollbar = NULL; 1127 int value; 1128 int slider_size; 1129 int min; 1130 int max; 1131 1132 /* first, try the vertical scrollbar */ 1133 XtVaGetValues(scrolled_window, XmNverticalScrollBar, &scrollbar, NULL); 1134 if (scrollbar != NULL) { 1135 XtVaGetValues(scrollbar, XmNvalue, &value, 1136 XmNsliderSize, &slider_size, 1137 XmNminimum, &min, 1138 XmNmaximum, &max, NULL); 1139 if (slider_size < max - min) { 1140 return scrollbar; 1141 } 1142 } 1143 1144 /* then, try the horiz */ 1145 XtVaGetValues(scrolled_window, XmNhorizontalScrollBar, &scrollbar, NULL); 1146 if (scrollbar != NULL) { 1147 XtVaGetValues(scrollbar, XmNvalue, &value, 1148 XmNsliderSize, &slider_size, 1149 XmNminimum, &min, 1150 XmNmaximum, &max, NULL); 1151 if (slider_size < max - min) { 1152 return scrollbar; 1153 } 1154 } 1155 /* neither is suitable for scrolling */ 1156 return NULL; 1157 } 1158 1159 EmbeddedFrame *theEmbeddedFrameList = NULL; 1160 1161 static void awt_util_updateXtCoordinatesForEmbeddedFrame(Widget ef) 1162 { 1163 Window ef_window; 1164 Window win; 1165 int32_t x, y; 1166 ef_window = XtWindow(ef); 1167 if (ef_window != None) { 1168 if (XTranslateCoordinates(awt_display, ef_window, 1169 RootWindowOfScreen(XtScreen(ef)), 1170 0, 0, &x, &y, &win)) { 1171 DTRACE_PRINTLN("correcting coordinates"); 1172 ef->core.x = x; 1173 ef->core.y = y; 1174 } 1175 } 1176 } 1177 1178 Boolean awt_util_processEventForEmbeddedFrame(XEvent *ev) 1179 { 1180 EmbeddedFrame *ef; 1181 Boolean dummy; 1182 Boolean eventProcessed = False; 1183 switch (ev->type) { 1184 case FocusIn: 1185 case FocusOut: 1186 ef = theEmbeddedFrameList; 1187 while (ef != NULL) { 1188 if (ef->frameContainer == ev->xfocus.window) { 1189 eventProcessed = True; 1190 if (isXEmbedActiveByWindow(XtWindow(ef->embeddedFrame))) { 1191 return True; 1192 } 1193 // pretend that the embedded frame gets a focus event 1194 // the event's window field is not the same as 1195 // the embeddedFrame's widget, but luckily the shellEH 1196 // doesnt seem to care about this. 1197 shellEH(ef->embeddedFrame, ef->javaRef, ev, &dummy); 1198 } 1199 ef = ef->next; 1200 } 1201 return eventProcessed; 1202 case ConfigureNotify: 1203 for (ef = theEmbeddedFrameList; ef != NULL; ef = ef->next) { 1204 awt_util_updateXtCoordinatesForEmbeddedFrame(ef->embeddedFrame); 1205 } 1206 return True; 1207 } 1208 return False; 1209 } 1210 1211 void awt_util_addEmbeddedFrame(Widget embeddedFrame, jobject javaRef) 1212 { 1213 EmbeddedFrame *ef, *eflist; 1214 Atom WM_STATE; 1215 Window win; 1216 Window parent, root; 1217 Window *children; 1218 uint32_t nchildren; 1219 Atom type = None; 1220 int32_t format; 1221 unsigned long nitems, after; 1222 unsigned char * data; 1223 XWindowAttributes win_attributes; 1224 1225 WM_STATE = XInternAtom(awt_display, "WM_STATE", True); 1226 if (WM_STATE == None) { 1227 return; 1228 } 1229 win = XtWindow(embeddedFrame); 1230 if (win == None) 1231 return; 1232 /* 1233 * according to XICCM, we search our toplevel window 1234 * by looking for WM_STATE property 1235 */ 1236 while (True) { 1237 if (!XQueryTree(awt_display, win, &root, &parent, 1238 &children, &nchildren)) { 1239 return; 1240 } 1241 if (children) { 1242 XFree(children); 1243 } 1244 if (parent == NULL || parent == root) { 1245 return; 1246 } 1247 win = parent; 1248 /* 1249 * Add StructureNotifyMask through hierarchy upto toplevel 1250 */ 1251 XGetWindowAttributes(awt_display, win, &win_attributes); 1252 XSelectInput(awt_display, win, win_attributes.your_event_mask | 1253 StructureNotifyMask); 1254 1255 if (XGetWindowProperty(awt_display, win, WM_STATE, 1256 0, 0, False, AnyPropertyType, 1257 &type, &format, &nitems, &after, &data) == Success) { 1258 XFree(data); 1259 if (type) { 1260 break; 1261 } 1262 } 1263 } 1264 ef = (EmbeddedFrame *) malloc(sizeof(EmbeddedFrame)); 1265 if (ef == NULL) { 1266 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), 1267 "OutOfMemory in awt_util_addEmbeddedFrame"); 1268 return; 1269 } 1270 ef->embeddedFrame = embeddedFrame; 1271 ef->frameContainer = win; 1272 ef->javaRef = javaRef; 1273 ef->eventSelectedPreviously = False; 1274 /* initialize the xt coordinates */ 1275 awt_util_updateXtCoordinatesForEmbeddedFrame(embeddedFrame); 1276 1277 /* 1278 * go through the exisiting embedded frames see if we have 1279 * already selected the event on the same frameContainer 1280 */ 1281 eflist = theEmbeddedFrameList; 1282 while (eflist != NULL) { 1283 if (eflist->frameContainer == win) { 1284 break; 1285 } 1286 eflist = eflist->next; 1287 } 1288 if (eflist != NULL) { 1289 /* 1290 * we already have a embedded frame selecting this container's 1291 * event, we remember its eventSelectedPreviously value 1292 * so that we know whether to deselect later when we are removed 1293 */ 1294 ef->eventSelectedPreviously = eflist->eventSelectedPreviously; 1295 } else { 1296 XGetWindowAttributes(awt_display, ef->frameContainer, 1297 &win_attributes); 1298 XSelectInput(awt_display, ef->frameContainer, 1299 win_attributes.your_event_mask | FocusChangeMask); 1300 } 1301 1302 /* ef will become the head of the embedded frame list */ 1303 ef->next = theEmbeddedFrameList; 1304 if (theEmbeddedFrameList != NULL) { 1305 theEmbeddedFrameList->prev = ef; 1306 } 1307 ef->prev = NULL; 1308 theEmbeddedFrameList = ef; 1309 } 1310 1311 void awt_util_delEmbeddedFrame(Widget embeddedFrame) 1312 { 1313 EmbeddedFrame *ef = theEmbeddedFrameList; 1314 Window frameContainer; 1315 XWindowAttributes win_attributes; 1316 Boolean needToDeselect; 1317 1318 while (ef != NULL) { 1319 if (ef->embeddedFrame == embeddedFrame) { 1320 break; 1321 } 1322 ef = ef->next; 1323 } 1324 if (ef == NULL) { /* cannot find specified embedded frame */ 1325 return; 1326 } 1327 /* remove ef from link list EmbeddedFrameList */ 1328 if (ef->prev) { 1329 ef->prev->next = ef->next; 1330 } 1331 if (ef->next) { 1332 ef->next->prev = ef->prev; 1333 } 1334 if (theEmbeddedFrameList == ef) { 1335 theEmbeddedFrameList = ef->next; 1336 } 1337 1338 frameContainer = ef->frameContainer; 1339 needToDeselect = ef->eventSelectedPreviously ? False : True; 1340 free(ef); 1341 if (!needToDeselect) { 1342 return; 1343 } 1344 /* 1345 * now decide whether we need to stop listenning event for 1346 * frameContainer 1347 */ 1348 ef = theEmbeddedFrameList; 1349 while (ef != NULL) { 1350 if (ef->frameContainer == frameContainer) { 1351 break; 1352 } 1353 ef = ef->next; 1354 } 1355 if (ef == NULL) { 1356 /* 1357 * if we get here, no one is interested in this frame 1358 * and StructureNotify was not selected by anyone else 1359 * so we deselect it 1360 */ 1361 DTRACE_PRINTLN("remove event from frame"); 1362 XGetWindowAttributes(awt_display, frameContainer, &win_attributes); 1363 XSelectInput(awt_display, frameContainer, 1364 win_attributes.your_event_mask & 1365 (~FocusChangeMask)); 1366 } 1367 } 1368 1369 #endif /* XAWT */ 1370 1371 void awt_util_debug_init() { 1372 #if defined(DEBUG) 1373 DTrace_Initialize(); 1374 #endif 1375 } 1376 1377 static void awt_util_debug_fini() { 1378 #if defined(DEBUG) 1379 DTrace_Shutdown(); 1380 #endif 1381 }