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