J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2000-2001 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 | #if MOTIF_VERSION!=1 |
| 27 | #error This file should only be compiled with motif 1.2 |
| 28 | #endif |
| 29 | |
| 30 | #include "awt_motif.h" |
| 31 | #include <Xm/VendorSEP.h> |
| 32 | #include <Xm/DragCP.h> |
| 33 | #include "debug_util.h" |
| 34 | #include "awt.h" |
| 35 | |
| 36 | /* |
| 37 | * awt_motif_getIMStatusHeight is a cut and paste of the ImGetGeo() function |
| 38 | * found in CDE Motif's Xm/XmIm.c. It returns the height of the Input Method |
| 39 | * Status region attached to the given VendorShell. This is needed in order |
| 40 | * to calculate geometry for Frames and Dialogs that contain TextField or |
| 41 | * TextArea widgets. |
| 42 | * |
| 43 | * BCB: Copying this function out of the Motif source is a horrible |
| 44 | * hack. Unfortunately, Motif tries to hide the existence of the IM Status |
| 45 | * region from us so it does not provide any public way to get this info. |
| 46 | * Clearly a better long term solution needs to be found. |
| 47 | */ |
| 48 | |
| 49 | typedef struct _XmICStruct { |
| 50 | struct _XmICStruct *next; |
| 51 | Widget icw; |
| 52 | Window focus_window; |
| 53 | XtArgVal foreground; |
| 54 | XtArgVal background; |
| 55 | XtArgVal background_pixmap; |
| 56 | XtArgVal font_list; |
| 57 | XtArgVal line_space; |
| 58 | int32_t status_width; |
| 59 | int32_t status_height; |
| 60 | int32_t preedit_width; |
| 61 | int32_t preedit_height; |
| 62 | Boolean has_focus; |
| 63 | Boolean need_reset; |
| 64 | } XmICStruct; |
| 65 | |
| 66 | typedef struct { |
| 67 | Widget im_widget; |
| 68 | XIMStyle input_style; |
| 69 | XIC xic; |
| 70 | int32_t status_width; |
| 71 | int32_t status_height; |
| 72 | int32_t preedit_width; |
| 73 | int32_t preedit_height; |
| 74 | XmICStruct *iclist; |
| 75 | XmICStruct *current; |
| 76 | } XmImInfo; |
| 77 | |
| 78 | static XFontSet extract_fontset(XmFontList); |
| 79 | static XmICStruct *get_iclist(Widget); |
| 80 | |
| 81 | #define MAXARGS 10 |
| 82 | static Arg xic_vlist[MAXARGS]; |
| 83 | static Arg status_vlist[MAXARGS]; |
| 84 | static Arg preedit_vlist[MAXARGS]; |
| 85 | |
| 86 | #define NO_ARG_VAL -1 |
| 87 | #define SEPARATOR_HEIGHT 2 |
| 88 | |
| 89 | |
| 90 | #ifdef MOTIF_2_1_HACK |
| 91 | /* To shut up warning messages from "cc -v" |
| 92 | * Copied from Solaris 2.6 /usr/dt/include/Xm/BaseClassP.h and not |
| 93 | * there in Solaris 7. |
| 94 | */ |
| 95 | #if defined(__SunOS_5_7) || defined(__SunOS_5_8) |
| 96 | extern XmWidgetExtData _XmGetWidgetExtData(Widget, unsigned char); |
| 97 | #endif |
| 98 | |
| 99 | #else |
| 100 | |
| 101 | /* |
| 102 | The following defines are to make the XmImGetXIC to compile on systems |
| 103 | lower than SunOS 5.7, so therefore the following is a copy of the |
| 104 | defines on SunOS 5.7/Motif2.1 header files. |
| 105 | */ |
| 106 | /*#if defined (__SunOS_5_5_1) || defined (__SunOS_5_6)*/ |
| 107 | #define XmPER_SHELL 0 |
| 108 | |
| 109 | extern XIC XmImGetXIC( |
| 110 | Widget w, |
| 111 | unsigned int input_policy, |
| 112 | ArgList args, |
| 113 | Cardinal num_args) ; |
| 114 | #endif |
| 115 | |
| 116 | static XmICStruct * |
| 117 | get_iclist(Widget w) |
| 118 | { |
| 119 | Widget p; |
| 120 | XmVendorShellExtObject ve; |
| 121 | XmWidgetExtData extData; |
| 122 | XmImInfo *im_info; |
| 123 | |
| 124 | p = w; |
| 125 | while (!XtIsShell(p)) |
| 126 | p = XtParent(p); |
| 127 | |
| 128 | extData = (XmWidgetExtData)_XmGetWidgetExtData((Widget) p, XmSHELL_EXTENSION); |
| 129 | if (extData == NULL) |
| 130 | return NULL; |
| 131 | |
| 132 | ve = (XmVendorShellExtObject) extData->widget; |
| 133 | if ((im_info = (XmImInfo *) ve->vendor.im_info) == NULL) |
| 134 | return NULL; |
| 135 | else |
| 136 | return im_info->iclist; |
| 137 | } |
| 138 | |
| 139 | int32_t |
| 140 | awt_motif_getIMStatusHeight(Widget vw, jobject tc) |
| 141 | { |
| 142 | XmICStruct *icp; |
| 143 | XmVendorShellExtObject ve; |
| 144 | XmWidgetExtData extData; |
| 145 | XmImInfo *im_info; |
| 146 | int32_t width = 0; |
| 147 | int32_t height = 0; |
| 148 | XRectangle rect; |
| 149 | XRectangle *rp; |
| 150 | int32_t old_height; |
| 151 | Arg args[1]; |
| 152 | int32_t base_height; |
| 153 | XFontSet fs; |
| 154 | XFontSet fss = NULL; |
| 155 | XFontSet fsp = NULL; |
| 156 | |
| 157 | extData = (XmWidgetExtData)_XmGetWidgetExtData((Widget) vw, XmSHELL_EXTENSION); |
| 158 | ve = (XmVendorShellExtObject) extData->widget; |
| 159 | |
| 160 | if ((icp = get_iclist(vw)) == NULL) { |
| 161 | ve->vendor.im_height = 0; |
| 162 | return 0; |
| 163 | } |
| 164 | im_info = (XmImInfo *) ve->vendor.im_info; |
| 165 | if (im_info->xic == NULL) { |
| 166 | ve->vendor.im_height = 0; |
| 167 | return 0; |
| 168 | } |
| 169 | status_vlist[0].name = XNFontSet; |
| 170 | status_vlist[1].name = NULL; |
| 171 | preedit_vlist[0].name = XNFontSet; |
| 172 | preedit_vlist[1].name = NULL; |
| 173 | |
| 174 | xic_vlist[0].name = XNAreaNeeded; |
| 175 | xic_vlist[1].name = NULL; |
| 176 | |
| 177 | im_info->status_width = 0; |
| 178 | im_info->status_height = 0; |
| 179 | im_info->preedit_width = 0; |
| 180 | im_info->preedit_height = 0; |
| 181 | for (; icp != NULL; icp = icp->next) { |
| 182 | if (im_info->input_style & XIMStatusArea) { |
| 183 | if (icp->status_height == 0) { |
| 184 | char *ret; |
| 185 | |
| 186 | if (icp->font_list == NO_ARG_VAL || |
| 187 | (fss = extract_fontset((XmFontList) icp->font_list)) == NULL) |
| 188 | continue; |
| 189 | |
| 190 | status_vlist[0].value = (XtArgVal) fss; |
| 191 | XSetICValues(im_info->xic, |
| 192 | XNStatusAttributes, &status_vlist[0], |
| 193 | NULL); |
| 194 | |
| 195 | xic_vlist[0].value = (XtArgVal) & rp; |
| 196 | ret = XGetICValues(im_info->xic, |
| 197 | XNStatusAttributes, &xic_vlist[0], |
| 198 | NULL); |
| 199 | |
| 200 | if (ret) { |
| 201 | /* Cannot obtain XIC value. IM server may be gone. */ |
| 202 | ve->vendor.im_height = 0; |
| 203 | return 0; |
| 204 | } else { |
| 205 | icp->status_width = rp->width; |
| 206 | icp->status_height = rp->height; |
| 207 | XFree(rp); |
| 208 | } |
| 209 | } |
| 210 | if (icp->status_width > im_info->status_width) |
| 211 | im_info->status_width = icp->status_width; |
| 212 | if (icp->status_height > im_info->status_height) |
| 213 | im_info->status_height = icp->status_height; |
| 214 | } |
| 215 | if (im_info->input_style & XIMPreeditArea) { |
| 216 | if (icp->preedit_height == 0) { |
| 217 | if (icp->font_list == NO_ARG_VAL || |
| 218 | (fsp = extract_fontset((XmFontList) icp->font_list)) == NULL) |
| 219 | continue; |
| 220 | |
| 221 | preedit_vlist[0].value = (XtArgVal) fsp; |
| 222 | XSetICValues(im_info->xic, |
| 223 | XNPreeditAttributes, &preedit_vlist[0], |
| 224 | NULL); |
| 225 | |
| 226 | xic_vlist[0].value = (XtArgVal) & rp; |
| 227 | XGetICValues(im_info->xic, |
| 228 | XNPreeditAttributes, &xic_vlist[0], |
| 229 | NULL); |
| 230 | |
| 231 | icp->preedit_width = rp->width; |
| 232 | icp->preedit_height = rp->height; |
| 233 | XFree(rp); |
| 234 | } |
| 235 | if (icp->preedit_width > im_info->preedit_width) |
| 236 | im_info->preedit_width = icp->preedit_width; |
| 237 | if (icp->preedit_height > im_info->preedit_height) |
| 238 | im_info->preedit_height = icp->preedit_height; |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | if (im_info->current != NULL && (fss != NULL || fsp != NULL)) { |
| 243 | if (im_info->current->font_list != NO_ARG_VAL && |
| 244 | (fs = extract_fontset((XmFontList) im_info->current->font_list)) |
| 245 | != NULL) { |
| 246 | if (fss != NULL) |
| 247 | status_vlist[0].value = (XtArgVal) fs; |
| 248 | else |
| 249 | status_vlist[0].name = NULL; |
| 250 | if (fsp != NULL) |
| 251 | preedit_vlist[0].value = (XtArgVal) fs; |
| 252 | else |
| 253 | preedit_vlist[0].name = NULL; |
| 254 | XSetICValues(im_info->xic, |
| 255 | XNStatusAttributes, &status_vlist[0], |
| 256 | XNPreeditAttributes, &preedit_vlist[0], |
| 257 | NULL); |
| 258 | } |
| 259 | } |
| 260 | if (im_info->status_height > im_info->preedit_height) |
| 261 | height = im_info->status_height; |
| 262 | else |
| 263 | height = im_info->preedit_height; |
| 264 | old_height = ve->vendor.im_height; |
| 265 | if (height) |
| 266 | height += SEPARATOR_HEIGHT; |
| 267 | |
| 268 | ve->vendor.im_height = height; |
| 269 | |
| 270 | XtSetArg(args[0], XtNbaseHeight, &base_height); |
| 271 | XtGetValues(vw, args, 1); |
| 272 | if (base_height < 0) |
| 273 | base_height = 0; |
| 274 | XtSetArg(args[0], XtNbaseHeight, base_height); |
| 275 | XtSetValues(vw, args, 1); |
| 276 | return height; |
| 277 | } |
| 278 | static XRectangle geometryRect; |
| 279 | XVaNestedList awt_motif_getXICStatusAreaList(Widget w, jobject tc) |
| 280 | { |
| 281 | Widget p; |
| 282 | XmVendorShellExtObject ve; |
| 283 | XmWidgetExtData extData; |
| 284 | XmImInfo *im_info; |
| 285 | XmICStruct *icp; |
| 286 | |
| 287 | XVaNestedList list = NULL; |
| 288 | XRectangle *ssgeometry = &geometryRect; |
| 289 | Pixel bg; |
| 290 | Pixel fg; |
| 291 | Pixmap bpm; |
| 292 | Dimension height,width; |
| 293 | Position x,y; |
| 294 | |
| 295 | p = w; |
| 296 | while (!XtIsShell(p)){ |
| 297 | p = XtParent(p); |
| 298 | } |
| 299 | |
| 300 | XtVaGetValues(p, |
| 301 | XmNx, &x, |
| 302 | XmNy, &y, |
| 303 | XmNwidth, &width, |
| 304 | XmNheight, &height, |
| 305 | NULL); |
| 306 | |
| 307 | extData = (XmWidgetExtData)_XmGetWidgetExtData((Widget) p, XmSHELL_EXTENSION); |
| 308 | if (extData == NULL) { |
| 309 | return NULL; |
| 310 | } |
| 311 | |
| 312 | ve = (XmVendorShellExtObject) extData->widget; |
| 313 | if ((im_info = (XmImInfo *) ve->vendor.im_info) == NULL) { |
| 314 | return NULL; |
| 315 | } else |
| 316 | icp = im_info->iclist; |
| 317 | |
| 318 | |
| 319 | if (icp) { |
| 320 | /* |
| 321 | * We hava at least a textfield/textarea in the frame, use the |
| 322 | * first one. |
| 323 | */ |
| 324 | ssgeometry->x = 0; |
| 325 | ssgeometry->y = height - icp->status_height; |
| 326 | ssgeometry->width = icp->status_width; |
| 327 | ssgeometry->height = icp->status_height; |
| 328 | |
| 329 | /* |
| 330 | * use motif TextComponent's resource |
| 331 | */ |
| 332 | fg = icp->foreground; |
| 333 | bg = icp->background; |
| 334 | bpm = icp->background_pixmap; |
| 335 | |
| 336 | list = XVaCreateNestedList(0, |
| 337 | XNFontSet, extract_fontset((XmFontList)icp->font_list), |
| 338 | XNArea, ssgeometry, |
| 339 | XNBackground, bg, |
| 340 | XNForeground, fg, |
| 341 | XNBackgroundPixmap, bpm, |
| 342 | NULL); |
| 343 | } |
| 344 | return list ; |
| 345 | } |
| 346 | |
| 347 | static XFontSet |
| 348 | extract_fontset(XmFontList fl) |
| 349 | { |
| 350 | XmFontContext context; |
| 351 | XmFontListEntry next_entry; |
| 352 | XmFontType type_return; |
| 353 | XtPointer tmp_font; |
| 354 | XFontSet first_fs = NULL; |
| 355 | char *font_tag; |
| 356 | |
| 357 | if (!XmFontListInitFontContext(&context, fl)) |
| 358 | return NULL; |
| 359 | |
| 360 | do { |
| 361 | next_entry = XmFontListNextEntry(context); |
| 362 | if (next_entry) { |
| 363 | tmp_font = XmFontListEntryGetFont(next_entry, &type_return); |
| 364 | if (type_return == XmFONT_IS_FONTSET) { |
| 365 | font_tag = XmFontListEntryGetTag(next_entry); |
| 366 | if (!strcmp(font_tag, XmFONTLIST_DEFAULT_TAG)) { |
| 367 | XmFontListFreeFontContext(context); |
| 368 | XtFree(font_tag); |
| 369 | return (XFontSet) tmp_font; |
| 370 | } |
| 371 | XtFree(font_tag); |
| 372 | if (first_fs == NULL) |
| 373 | first_fs = (XFontSet) tmp_font; |
| 374 | } |
| 375 | } |
| 376 | } while (next_entry); |
| 377 | |
| 378 | XmFontListFreeFontContext(context); |
| 379 | return first_fs; |
| 380 | } |
| 381 | |
| 382 | /* |
| 383 | * Motif 1.2 requires that an X event passed to XmDragStart is of |
| 384 | * ButtonPress type. In Motif 2.1 the restriction is relaxed to allow |
| 385 | * ButtonPress, ButtonRelease, KeyRelease, KeyPress, MotionNotify events |
| 386 | * as drag initiators. Actually the code in Motif 1.2 works okay for these |
| 387 | * events as well, since it uses only the fields that have the same values |
| 388 | * in all five event types. To bypass the initial sanity check in |
| 389 | * XmDragStart we forcibly change event type to ButtonPress. |
| 390 | * |
| 391 | * This function causes an UnsatisfiedLinkError on Linux. |
| 392 | * Since Linux only links against Motif 2.1, we can safely remove |
| 393 | * this function altogether from the Linux build. |
| 394 | * bchristi 1/22/2001 |
| 395 | */ |
| 396 | |
| 397 | #ifdef __solaris__ |
| 398 | void |
| 399 | awt_motif_adjustDragTriggerEvent(XEvent* xevent) { |
| 400 | xevent->type = ButtonPress; |
| 401 | } |
| 402 | #endif /* __solaris__ */ |
| 403 | |
| 404 | static XmDragStartProc do_drag_start = NULL; |
| 405 | static Widget drag_initiator = NULL; |
| 406 | |
| 407 | static void |
| 408 | CheckedDragStart(XmDragContext dc, Widget src, XEvent *event) { |
| 409 | DASSERT(do_drag_start != NULL); |
| 410 | DASSERT(drag_initiator != NULL); |
| 411 | /* |
| 412 | * Fix for BugTraq ID 4407057. |
| 413 | * Enable the drag operation only if it is registered on the specific widget. |
| 414 | * We use this check to disable Motif default drag support. |
| 415 | */ |
| 416 | if (src == drag_initiator) { |
| 417 | do_drag_start(dc, src, event); |
| 418 | } else { |
| 419 | /* |
| 420 | * This is the last chance to destroy the XmDragContext widget. |
| 421 | * NOTE: We rely on the fact that Motif 1.2 never uses the pointer |
| 422 | * to XmDragContext object returned from XmDragStart. |
| 423 | */ |
| 424 | XtDestroyWidget(dc); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | void |
| 429 | awt_motif_enableSingleDragInitiator(Widget w) { |
| 430 | DASSERT(drag_initiator == NULL && do_drag_start == NULL && w != NULL); |
| 431 | drag_initiator = w; |
| 432 | do_drag_start = xmDragContextClassRec.drag_class.start; |
| 433 | DASSERT(do_drag_start != NULL); |
| 434 | xmDragContextClassRec.drag_class.start = (XmDragStartProc)CheckedDragStart; |
| 435 | } |