blob: 15797146fe63cee6279e047a28fb0ad0e3fe64b4 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1995-2003 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 "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 */
65XErrorHandler xerror_saved_handler;
66
67/*
68 * A place for error handler to report the error code.
69 */
70unsigned char xerror_code;
71
72extern jint getModifiers(uint32_t state, jint button, jint keyCode);
73extern jint getButton(uint32_t button);
74
75static int32_t winmgr_running = 0;
76static Atom OLDecorDelAtom = 0;
77static Atom MWMHints = 0;
78static Atom DTWMHints = 0;
79static 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 */
98Boolean
99awt_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
150static
151void 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 */
174int32_t
175awt_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
191Widget
192awt_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
250void
251awt_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
265Widget 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
276void
277awt_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
382void
383awt_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
393void
394awt_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
413void
414awt_util_enable(Widget w)
415{
416 XtSetSensitive(w, True);
417}
418
419void
420awt_util_disable(Widget w)
421{
422 XtSetSensitive(w, False);
423}
424
425void
426awt_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
454void
455awt_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
484static Widget prevWgt = NULL;
485
486static void
487DestroyCB(Widget w, XtPointer client_data, XtPointer call_data) {
488 if (prevWgt == w) {
489 prevWgt = NULL;
490 }
491}
492
493int32_t
494awt_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
531void
532awt_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*/
567Widget
568awt_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
612static Arg xic_vlist[MAXARGS];
613static Arg status_vlist[MAXARGS];
614static Arg preedit_vlist[MAXARGS];
615
616#define NO_ARG_VAL -1
617#define SEPARATOR_HEIGHT 2
618
619static 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
628static XtPointer*
629get_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
657static XmImShellInfo
658get_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
670Widget
671awt_util_getXICStatusAreaWindow(Widget w)
672{
673 while (!XtIsShell(w)){
674 w = XtParent(w);
675 }
676 return w;
677}
678
679#ifdef __linux__
680static XRectangle geometryRect;
681XVaNestedList 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
757static XFontSet
758extract_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...*/
795char* 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 */
825Cardinal
826awt_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
865void
866awt_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 */
883jobject
884awtJNI_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
923void
924awtJNI_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
962void
963awt_util_cleanupBeforeDestroyWidget(Widget widget)
964{
965 /* Bug 4017222: Drag processing uses global prevWidget. */
966 if (widget == prevWidget) {
967 prevWidget = NULL;
968 }
969}
970
971static Boolean timeStampUpdated = False;
972
973static int32_t
974isTimeStampUpdated(void* p) {
975 return timeStampUpdated;
976}
977
978static void
979propertyChangeEventHandler(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 */
994Time
995awt_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 */
1033jlong
1034awt_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 */
1046jlong
1047awt_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
1069void 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 */
1125Widget 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
1159EmbeddedFrame *theEmbeddedFrameList = NULL;
1160
1161static 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
1178Boolean 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
1211void 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
1311void 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
1371void awt_util_debug_init() {
1372#if defined(DEBUG)
1373 DTrace_Initialize();
1374#endif
1375}
1376
1377static void awt_util_debug_fini() {
1378#if defined(DEBUG)
1379 DTrace_Shutdown();
1380#endif
1381}