1/* 2 3Copyright (c) 1993, Oracle and/or its affiliates. 4 5Permission is hereby granted, free of charge, to any person obtaining a 6copy of this software and associated documentation files (the "Software"), 7to deal in the Software without restriction, including without limitation 8the rights to use, copy, modify, merge, publish, distribute, sublicense, 9and/or sell copies of the Software, and to permit persons to whom the 10Software is furnished to do so, subject to the following conditions: 11 12The above copyright notice and this permission notice (including the next 13paragraph) shall be included in all copies or substantial portions of the 14Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22DEALINGS IN THE SOFTWARE. 23 24*/ 25/******************************************************** 26 27Copyright 1988 by Hewlett-Packard Company 28Copyright 1987, 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts 29 30Permission to use, copy, modify, and distribute this software 31and its documentation for any purpose and without fee is hereby 32granted, provided that the above copyright notice appear in all 33copies and that both that copyright notice and this permission 34notice appear in supporting documentation, and that the names of 35Hewlett-Packard or Digital not be used in advertising or 36publicity pertaining to distribution of the software without specific, 37written prior permission. 38 39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 43WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 45SOFTWARE. 46 47********************************************************/ 48 49/* 50 51Copyright 1987, 1988, 1994, 1998 The Open Group 52 53Permission to use, copy, modify, distribute, and sell this software and its 54documentation for any purpose is hereby granted without fee, provided that 55the above copyright notice appear in all copies and that both that 56copyright notice and this permission notice appear in supporting 57documentation. 58 59The above copyright notice and this permission notice shall be included in 60all copies or substantial portions of the Software. 61 62THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 63IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 64FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 65OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 66AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 67CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 68 69Except as contained in this notice, the name of The Open Group shall not be 70used in advertising or otherwise to promote the sale, use or other dealings 71in this Software without prior written authorization from The Open Group. 72 73*/ 74 75#ifdef HAVE_CONFIG_H 76#include <config.h> 77#endif 78#include "IntrinsicI.h" 79 80#include "PassivGraI.h" 81#include "EventI.h" 82 83#define _GetWindowedAncestor(w) (XtIsWidget(w) ? w : _XtWindowedAncestor(w)) 84 85/* InActiveSubtree cache of the current focus source and its ancestors */ 86static Widget *pathTrace = NULL; 87static int pathTraceDepth = 0; 88static int pathTraceMax = 0; 89 90/* FindKeyDestination cache of focus destination and ancestors up to source */ 91static Widget *pseudoTrace = NULL; 92static int pseudoTraceDepth = 0; 93static int pseudoTraceMax = 0; 94 95void 96_XtClearAncestorCache(Widget widget) 97{ 98 /* the caller must lock the process lock */ 99 if (pathTraceDepth && pathTrace[0] == widget) 100 pathTraceDepth = 0; 101} 102 103static XtServerGrabPtr 104CheckServerGrabs(XEvent *event, Widget *trace, Cardinal traceDepth) 105{ 106 Cardinal i; 107 108 for (i = traceDepth; i > 0; i--) { 109 XtServerGrabPtr grab; 110 111 if ((grab = _XtCheckServerGrabsOnWidget(event, trace[i - 1], KEYBOARD))) 112 return (grab); 113 } 114 return (XtServerGrabPtr) 0; 115} 116 117static Boolean 118IsParent(Widget a, Widget b) 119{ 120 for (b = XtParent(b); b; b = XtParent(b)) { 121 if (b == a) 122 return TRUE; 123 if (XtIsShell(b)) 124 return FALSE; 125 } 126 return FALSE; 127} 128 129#define RelRtn(lca, type) {*relTypeRtn = type; return lca;} 130 131static Widget 132CommonAncestor(register Widget a, register Widget b, XtGeneology *relTypeRtn) 133{ 134 if (a == b) { 135 RelRtn(a, XtMySelf) 136 } 137 else if (IsParent(a, b)) { 138 RelRtn(a, XtMyAncestor) 139 } 140 else if (IsParent(b, a)) { 141 RelRtn(b, XtMyDescendant) 142 } 143 else 144 for (b = XtParent(b); b && !XtIsShell(b); b = XtParent(b)) 145 if (IsParent(b, a)) { 146 RelRtn(b, XtMyCousin) 147 } 148 RelRtn(NULL, XtUnrelated) 149} 150 151#undef RelRtn 152 153static Widget 154_FindFocusWidget(Widget widget, 155 Widget *trace, 156 int traceDepth, 157 Boolean activeCheck, 158 Boolean *isTarget) 159{ 160 int src; 161 Widget dst; 162 XtPerWidgetInput pwi = NULL; 163 164 /* For each ancestor, starting at the top, see if it's forwarded */ 165 166 /* first check the trace list till done or we go to branch */ 167 for (src = traceDepth - 1, dst = widget; src > 0;) { 168 if ((pwi = _XtGetPerWidgetInput(trace[src], FALSE))) { 169 if (pwi->focusKid) { 170 dst = pwi->focusKid; 171 for (src--; src > 0 && trace[src] != dst; src--) { 172 } 173 } 174 else 175 dst = trace[--src]; 176 } 177 else 178 dst = trace[--src]; 179 } 180 181 if (isTarget) { 182 if (pwi && pwi->focusKid == widget) 183 *isTarget = TRUE; 184 else 185 *isTarget = FALSE; 186 } 187 188 if (!activeCheck) 189 while (XtIsWidget(dst) 190 && (pwi = _XtGetPerWidgetInput(dst, FALSE)) 191 && pwi->focusKid) 192 dst = pwi->focusKid; 193 194 return dst; 195} 196 197static Widget 198FindFocusWidget(Widget widget, XtPerDisplayInput pdi) 199{ 200 if (pdi->focusWidget) 201 return pdi->focusWidget; 202 else 203 return _FindFocusWidget(widget, pdi->trace, pdi->traceDepth, FALSE, 204 NULL); 205} 206 207Widget 208XtGetKeyboardFocusWidget(Widget widget) 209{ 210 XtPerDisplayInput pdi; 211 Widget retval; 212 213 WIDGET_TO_APPCON(widget); 214 215 LOCK_APP(app); 216 pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 217 retval = FindFocusWidget(widget, pdi); 218 UNLOCK_APP(app); 219 return retval; 220} 221 222static Boolean 223IsOutside(XKeyEvent *e, Widget w) 224{ 225 Position left, right, top, bottom; 226 227 /* 228 * if the pointer is outside the shell or inside 229 * the window try to see if it would receive the 230 * focus 231 */ 232 XtTranslateCoords(w, 0, 0, &left, &top); 233 /* We need to take borders into consideration */ 234 left = (Position) (left - w->core.border_width); 235 top = (Position) (top - w->core.border_width); 236 right = (Position) (left + w->core.width + w->core.border_width); 237 bottom = (Position) (top + w->core.height + w->core.border_width); 238 239 if ((e->x_root < left) || (e->y_root < top) || 240 (e->x_root > right) || (e->y_root > bottom)) 241 return TRUE; 242 else 243 return FALSE; 244} 245 246static Widget 247FindKeyDestination(Widget widget, 248 XKeyEvent *event, 249 XtServerGrabPtr prevGrab, 250 XtServerGrabType prevGrabType, 251 XtServerGrabPtr devGrab, 252 XtServerGrabType devGrabType, 253 XtPerDisplayInput pdi) 254{ 255 256 Widget dspWidget; 257 Widget focusWidget; 258 259 LOCK_PROCESS; 260 dspWidget = 261 focusWidget = 262 pdi->focusWidget = _GetWindowedAncestor(FindFocusWidget(widget, pdi)); 263 264 /* 265 * If a grab is active from a previous activation then dispatch 266 * based on owner_events ala protocol but with focus being 267 * determined by XtSetKeyboardFocus. 268 */ 269 if (IsAnyGrab(prevGrabType)) { 270 if (prevGrab->ownerEvents) 271 dspWidget = focusWidget; 272 else 273 dspWidget = prevGrab->widget; 274 } 275 else { 276 /* 277 * If the focus widget is the event widget or a descendant 278 * then we can avoid the rest of this. Else ugh... 279 */ 280 if (focusWidget != widget) { 281 XtGeneology ewRelFw; /* relationship of event widget to 282 focusWidget */ 283 Widget lca; 284 285 lca = CommonAncestor(widget, focusWidget, &ewRelFw); 286 287 /* 288 * if the event widget is an ancestor of focus due to the pointer 289 * and/or the grab being in an ancestor and it's a passive grab 290 * send to grab widget. 291 * we are also dispatching to widget if ownerEvents and the event 292 * is outside the client 293 */ 294 if ((ewRelFw == XtMyAncestor) && 295 (devGrabType == XtPassiveServerGrab)) { 296 if (IsOutside(event, widget) || event->type == KeyPress) 297 dspWidget = devGrab->widget; 298 } 299 else { 300 /* 301 * if the grab widget is not an ancestor of the focus 302 * release the grab in order to avoid locking. There 303 * is a possible case in that ownerEvents true will fall 304 * through and if synch is set and the event widget 305 * could turn it off we'll lock. check for it ? why not 306 */ 307 if ((ewRelFw != XtMyAncestor) 308 && (devGrabType == XtPassiveServerGrab) 309 && (!IsAnyGrab(prevGrabType)) 310 ) { 311 XtUngrabKeyboard(devGrab->widget, event->time); 312 } 313 /* 314 * if there isn't a grab with then check 315 * for a logical grab that would have been activated 316 * if the server was using Xt focus instead of server 317 * focus 318 */ 319 if ((event->type != KeyPress) || (event->keycode == 0) /* Xlib XIM composed input */ 320 ) 321 dspWidget = focusWidget; 322 else { 323 XtServerGrabPtr grab; 324 325 if (!pseudoTraceDepth || 326 !(focusWidget == pseudoTrace[0]) || 327 !(lca == pseudoTrace[pseudoTraceDepth])) { 328 /* 329 * fill ancestor list from lca 330 * (non-inclusive)to focusWidget by 331 * passing in lca as breakWidget 332 */ 333 _XtFillAncestorList(&pseudoTrace, 334 &pseudoTraceMax, 335 &pseudoTraceDepth, 336 focusWidget, lca); 337 /* ignore lca */ 338 pseudoTraceDepth--; 339 } 340 if ((grab = CheckServerGrabs((XEvent *) event, 341 pseudoTrace, 342 (Cardinal) pseudoTraceDepth))) 343 { 344 XtDevice device = &pdi->keyboard; 345 346 device->grabType = XtPseudoPassiveServerGrab; 347 pdi->activatingKey = (KeyCode) event->keycode; 348 device->grab = *grab; 349 dspWidget = grab->widget; 350 } 351 } 352 } 353 } 354 } 355 UNLOCK_PROCESS; 356 return dspWidget; 357} 358 359Widget 360_XtProcessKeyboardEvent(XKeyEvent *event, Widget widget, XtPerDisplayInput pdi) 361{ 362 XtDevice device = &pdi->keyboard; 363 XtServerGrabPtr devGrab = &device->grab; 364 XtServerGrabRec prevGrabRec; 365 XtServerGrabType prevGrabType = device->grabType; 366 Widget dspWidget = NULL; 367 Boolean deactivateGrab = FALSE; 368 369 prevGrabRec = *devGrab; 370 371 switch (event->type) { 372 case KeyPress: 373 { 374 XtServerGrabPtr newGrab; 375 376 if (event->keycode != 0 && /* Xlib XIM composed input */ 377 !IsServerGrab(device->grabType) && 378 (newGrab = CheckServerGrabs((XEvent *) event, 379 pdi->trace, 380 (Cardinal) pdi->traceDepth))) { 381 /* 382 * honor pseudo-grab from prior event by X 383 * unlocking keyboard. Not Xt Unlock ! 384 */ 385 if (IsPseudoGrab(prevGrabType)) 386 XUngrabKeyboard(XtDisplay(newGrab->widget), event->time); 387 else { 388 /* Activate the grab */ 389 device->grab = *newGrab; 390 pdi->activatingKey = (KeyCode) event->keycode; 391 device->grabType = XtPassiveServerGrab; 392 } 393 } 394 } 395 break; 396 397 case KeyRelease: 398 { 399 if (IsEitherPassiveGrab(device->grabType) && 400 (event->keycode == pdi->activatingKey)) 401 deactivateGrab = TRUE; 402 } 403 break; 404 } 405 dspWidget = FindKeyDestination(widget, event, 406 &prevGrabRec, prevGrabType, 407 devGrab, device->grabType, pdi); 408 if (deactivateGrab) { 409 /* Deactivate the grab */ 410 device->grabType = XtNoServerGrab; 411 pdi->activatingKey = 0; 412 } 413 return dspWidget; 414} 415 416static Widget 417GetShell(Widget widget) 418{ 419 Widget shell; 420 421 for (shell = widget; shell && !XtIsShell(shell); shell = XtParent(shell)) { 422 } 423 return shell; 424} 425 426/* 427 * Check that widget really has Xt focus due to it having received an 428 * event 429 */ 430typedef enum { NotActive = 0, IsActive, IsTarget } ActiveType; 431 432static ActiveType 433InActiveSubtree(Widget widget) 434{ 435 Boolean isTarget; 436 ActiveType retval; 437 438 LOCK_PROCESS; 439 if (!pathTraceDepth || widget != pathTrace[0]) { 440 _XtFillAncestorList(&pathTrace, 441 &pathTraceMax, &pathTraceDepth, widget, NULL); 442 } 443 if (widget == _FindFocusWidget(widget, 444 pathTrace, pathTraceDepth, TRUE, &isTarget)) 445 retval = (isTarget ? IsTarget : IsActive); 446 else 447 retval = NotActive; 448 UNLOCK_PROCESS; 449 return retval; 450} 451 452void 453_XtHandleFocus(Widget widget, 454 XtPointer client_data, /* child who wants focus */ 455 XEvent *event, 456 Boolean *cont _X_UNUSED) 457{ 458 XtPerDisplayInput pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 459 XtPerWidgetInput pwi = (XtPerWidgetInput) client_data; 460 XtGeneology oldFocalPoint = pwi->focalPoint; 461 XtGeneology newFocalPoint = pwi->focalPoint; 462 463 switch (event->type) { 464 465 case KeyPress: 466 case KeyRelease: 467 /* 468 * We're getting the keyevents used to guarantee propagating 469 * child interest ala ForwardEvent in R3 470 */ 471 return; 472 473 case EnterNotify: 474 case LeaveNotify: 475 476 /* 477 * If operating in a focus driven model, then enter and 478 * leave events do not affect the keyboard focus. 479 */ 480 if ((event->xcrossing.detail != NotifyInferior) 481 && (event->xcrossing.focus)) { 482 switch (oldFocalPoint) { 483 case XtMyAncestor: 484 if (event->type == LeaveNotify) 485 newFocalPoint = XtUnrelated; 486 break; 487 case XtUnrelated: 488 if (event->type == EnterNotify) 489 newFocalPoint = XtMyAncestor; 490 break; 491 case XtMySelf: 492 break; 493 case XtMyDescendant: 494 break; 495 496 } 497 } 498 break; 499 case FocusIn: 500 switch (event->xfocus.detail) { 501 case NotifyNonlinear: 502 case NotifyAncestor: 503 case NotifyInferior: 504 newFocalPoint = XtMySelf; 505 break; 506 case NotifyNonlinearVirtual: 507 case NotifyVirtual: 508 newFocalPoint = XtMyDescendant; 509 break; 510 case NotifyPointer: 511 newFocalPoint = XtMyAncestor; 512 break; 513 } 514 break; 515 case FocusOut: 516 switch (event->xfocus.detail) { 517 case NotifyPointer: 518 case NotifyNonlinear: 519 case NotifyAncestor: 520 case NotifyNonlinearVirtual: 521 case NotifyVirtual: 522 newFocalPoint = XtUnrelated; 523 break; 524 case NotifyInferior: 525 return; 526 } 527 break; 528 } 529 530 if (newFocalPoint != oldFocalPoint) { 531 Boolean add; 532 Widget descendant = pwi->focusKid; 533 534 pwi->focalPoint = newFocalPoint; 535 536 if ((oldFocalPoint == XtUnrelated) && 537 InActiveSubtree(widget) != NotActive) { 538 pdi->focusWidget = NULL; /* invalidate the cache */ 539 pwi->haveFocus = TRUE; 540 add = TRUE; 541 } 542 else if (newFocalPoint == XtUnrelated) { 543 pdi->focusWidget = NULL; /* invalidate the cache */ 544 pwi->haveFocus = FALSE; 545 add = FALSE; 546 } 547 else 548 return; 549 550 if (descendant) { 551 if (add) { 552 _XtSendFocusEvent(descendant, FocusIn); 553 } 554 else { 555 _XtSendFocusEvent(descendant, FocusOut); 556 } 557 } 558 } 559} 560 561static void 562AddFocusHandler(Widget widget, 563 Widget descendant, 564 XtPerWidgetInput pwi, 565 XtPerWidgetInput psi, 566 XtPerDisplayInput pdi, 567 EventMask oldEventMask) 568{ 569 EventMask eventMask, targetEventMask; 570 Widget target; 571 572 /* 573 * widget must now select for key events if the descendant is 574 * interested in them. 575 * 576 * shell borders are not occluded by the child, they're occluded 577 * by reparenting window managers. !!! 578 */ 579 target = descendant ? _GetWindowedAncestor(descendant) : NULL; 580 targetEventMask = XtBuildEventMask(target); 581 eventMask = targetEventMask & (KeyPressMask | KeyReleaseMask); 582 eventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask; 583 584 if (oldEventMask) { 585 oldEventMask &= KeyPressMask | KeyReleaseMask; 586 oldEventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask; 587 588 if (oldEventMask != eventMask) 589 XtRemoveEventHandler(widget, (oldEventMask & ~eventMask), 590 False, _XtHandleFocus, (XtPointer) pwi); 591 } 592 593 if (oldEventMask != eventMask) 594 XtAddEventHandler(widget, eventMask, False, 595 _XtHandleFocus, (XtPointer) pwi); 596 597 /* What follows is too much grief to go through if the 598 * target doesn't actually care about focus change events, 599 * so just invalidate the focus cache & refill it when 600 * the next input event actually arrives. 601 */ 602 603 if (!(targetEventMask & FocusChangeMask)) { 604 pdi->focusWidget = NULL; 605 return; 606 } 607 608 if (XtIsRealized(widget) && !pwi->haveFocus) { 609 if (psi->haveFocus) { 610 Window root, child; 611 int root_x, root_y, win_x, win_y; 612 int left, right, top, bottom; 613 unsigned int modMask; 614 ActiveType act; 615 616 /* 617 * If the shell has the focus but the source widget 618 * doesn't, it may only be because the source widget 619 * wasn't previously tracking focus or crossing events. 620 * If the target wants focus events, we have to 621 * now determine whether the source has the focus. 622 */ 623 624 if ((act = InActiveSubtree(widget)) == IsTarget) 625 pwi->haveFocus = TRUE; 626 else if (act == IsActive) { 627 /* 628 * An ancestor contains the focus, so if source 629 * contains the pointer, then source has the focus. 630 */ 631 632 if (XQueryPointer(XtDisplay(widget), XtWindow(widget), 633 &root, &child, 634 &root_x, &root_y, &win_x, &win_y, &modMask)) { 635 /* We need to take borders into consideration */ 636 left = top = -((int) widget->core.border_width); 637 right = 638 (int) (widget->core.width + 639 (widget->core.border_width << 1)); 640 bottom = 641 (int) (widget->core.height + 642 (widget->core.border_width << 1)); 643 644 if (win_x >= left && win_x < right && 645 win_y >= top && win_y < bottom) 646 pwi->haveFocus = TRUE; 647 } 648 } 649 } 650 } 651 if (pwi->haveFocus) { 652 pdi->focusWidget = NULL; /* invalidate the cache */ 653 _XtSendFocusEvent(target, FocusIn); 654 } 655} 656 657static void 658QueryEventMask(Widget widget, /* child who gets focus */ 659 XtPointer client_data, /* ancestor giving it */ 660 XEvent *event _X_UNUSED, 661 Boolean *cont _X_UNUSED) 662{ 663 /* widget was once the target of an XtSetKeyboardFocus but 664 * was unrealized at the time. Make sure ancestor still wants 665 * focus set here then install the handler now that we know the 666 * complete event mask. 667 */ 668 Widget ancestor = (Widget) client_data; 669 XtPerWidgetInput pwi = _XtGetPerWidgetInput(ancestor, FALSE); 670 671 if (pwi) { 672 Widget target = pwi->queryEventDescendant; 673 674 /* use of 'target' is non-standard hackery; 675 allows focus to non-widget */ 676 if (pwi->focusKid == target) { 677 AddFocusHandler(ancestor, target, pwi, 678 _XtGetPerWidgetInput(GetShell(ancestor), TRUE), 679 _XtGetPerDisplayInput(XtDisplay(ancestor)), 680 (EventMask) 0); 681 } 682 XtRemoveEventHandler(widget, XtAllEvents, True, 683 QueryEventMask, client_data); 684 pwi->map_handler_added = FALSE; 685 } 686} 687 688static void 689FocusDestroyCallback(Widget widget _X_UNUSED, 690 XtPointer closure, /* Widget */ 691 XtPointer call_data _X_UNUSED) 692{ 693 XtSetKeyboardFocus((Widget) closure, NULL); 694} 695 696void 697XtSetKeyboardFocus(Widget widget, Widget descendant) 698{ 699 XtPerDisplayInput pdi; 700 XtPerWidgetInput pwi; 701 Widget oldDesc, oldTarget, target, hookobj; 702 703 WIDGET_TO_APPCON(widget); 704 705 LOCK_APP(app); 706 LOCK_PROCESS; 707 pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 708 pwi = _XtGetPerWidgetInput(widget, TRUE); 709 oldDesc = pwi->focusKid; 710 711 if (descendant == widget) 712 descendant = (Widget) None; 713 714 target = descendant ? _GetWindowedAncestor(descendant) : NULL; 715 oldTarget = oldDesc ? _GetWindowedAncestor(oldDesc) : NULL; 716 717 if (descendant != oldDesc) { 718 719 /* update the forward path */ 720 pwi->focusKid = descendant; 721 722 /* all the rest handles focus ins and focus outs and misc gunk */ 723 724 if (oldDesc) { 725 /* invalidate FindKeyDestination's ancestor list */ 726 if (pseudoTraceDepth && oldTarget == pseudoTrace[0]) 727 pseudoTraceDepth = 0; 728 729 XtRemoveCallback(oldDesc, XtNdestroyCallback, 730 FocusDestroyCallback, (XtPointer) widget); 731 732 if (!oldTarget->core.being_destroyed) { 733 if (pwi->map_handler_added) { 734 XtRemoveEventHandler(oldTarget, XtAllEvents, True, 735 QueryEventMask, (XtPointer) widget); 736 pwi->map_handler_added = FALSE; 737 } 738 if (pwi->haveFocus) { 739 _XtSendFocusEvent(oldTarget, FocusOut); 740 } 741 } 742 else if (pwi->map_handler_added) { 743 pwi->map_handler_added = FALSE; 744 } 745 746 if (pwi->haveFocus) 747 pdi->focusWidget = NULL; /* invalidate cache */ 748 749 /* 750 * If there was a forward path then remove the handler if 751 * the path is being set to null and it isn't a shell. 752 * shells always have a handler for tracking focus for the 753 * hierarchy. 754 * 755 * Keep the pwi record on the assumption that the client 756 * will continue to dynamically assign focus for this widget. 757 */ 758 if (!XtIsShell(widget) && !descendant) { 759 XtRemoveEventHandler(widget, XtAllEvents, True, 760 _XtHandleFocus, (XtPointer) pwi); 761 pwi->haveFocus = FALSE; 762 } 763 } 764 765 if (descendant) { 766 Widget shell = GetShell(widget); 767 XtPerWidgetInput psi = _XtGetPerWidgetInput(shell, TRUE); 768 769 XtAddCallback(descendant, XtNdestroyCallback, 770 FocusDestroyCallback, (XtPointer) widget); 771 772 AddFocusHandler(widget, descendant, pwi, psi, pdi, 773 oldTarget ? XtBuildEventMask(oldTarget) : 0); 774 775 if (widget != shell) 776 XtAddEventHandler(shell, 777 FocusChangeMask | EnterWindowMask | 778 LeaveWindowMask, False, _XtHandleFocus, 779 (XtPointer) psi); 780 781 if (!XtIsRealized(target)) { 782 XtAddEventHandler(target, (EventMask) StructureNotifyMask, 783 False, QueryEventMask, (XtPointer) widget); 784 pwi->map_handler_added = TRUE; 785 pwi->queryEventDescendant = descendant; 786 } 787 } 788 } 789 hookobj = XtHooksOfDisplay(XtDisplay(widget)); 790 if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { 791 XtChangeHookDataRec call_data; 792 793 call_data.type = XtHsetKeyboardFocus; 794 call_data.widget = widget; 795 call_data.event_data = (XtPointer) descendant; 796 XtCallCallbackList(hookobj, 797 ((HookObject) hookobj)->hooks.changehook_callbacks, 798 (XtPointer) &call_data); 799 } 800 UNLOCK_PROCESS; 801 UNLOCK_APP(app); 802} 803