1/*****************************************************************************/ 2/* 3 4Copyright 1989, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 26*/ 27/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ 28/** Salt Lake City, Utah **/ 29/** Cambridge, Massachusetts **/ 30/** **/ 31/** All Rights Reserved **/ 32/** **/ 33/** Permission to use, copy, modify, and distribute this software and **/ 34/** its documentation for any purpose and without fee is hereby **/ 35/** granted, provided that the above copyright notice appear in all **/ 36/** copies and that both that copyright notice and this permis- **/ 37/** sion notice appear in supporting documentation, and that the **/ 38/** name of Evans & Sutherland not be used in advertising **/ 39/** in publicity pertaining to distribution of the software without **/ 40/** specific, written prior permission. **/ 41/** **/ 42/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/ 43/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ 44/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/ 45/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ 46/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ 47/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ 48/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ 49/** OR PERFORMANCE OF THIS SOFTWARE. **/ 50/*****************************************************************************/ 51 52/*********************************************************************** 53 * 54 * twm event handling 55 * 56 * 17-Nov-87 Thomas E. LaStrange File created 57 * 58 ***********************************************************************/ 59 60#include <stdio.h> 61#include "twm.h" 62#include <X11/Xatom.h> 63#include "iconmgr.h" 64#include "add_window.h" 65#include "menus.h" 66#include "events.h" 67#include "resize.h" 68#include "parse.h" 69#include "util.h" 70#include "screen.h" 71#include "icons.h" 72 73#ifdef HAVE_XRANDR 74#include <X11/extensions/Xrandr.h> 75#endif 76 77#define MAX_X_EVENT 256 78event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */ 79static const char *Action; 80int Context = C_NO_CONTEXT; /* current button press context */ 81static TwmWindow *ButtonWindow; /* button press window structure */ 82static XEvent ButtonEvent; /* button press event */ 83XEvent Event; /* the current event */ 84static TwmWindow *Tmp_win; /* the current twm window */ 85 86/** Used in HandleEnterNotify to remove border highlight from a window 87 * that has not received a LeaveNotify event because of a pointer grab 88 */ 89static TwmWindow *UnHighLight_win = NULL; 90 91Window DragWindow; /* variables used in moving windows */ 92int origDragX; 93int origDragY; 94int DragX; 95int DragY; 96int DragWidth; 97int DragHeight; 98int CurrentDragX; 99int CurrentDragY; 100 101static int enter_flag; 102static int ColortableThrashing; 103static TwmWindow *enter_win, *raise_win; 104 105static void free_window_names(TwmWindow *tmp, Bool nukefull, Bool nukename, 106 Bool nukeicon); 107static void remove_window_from_ring(TwmWindow *tmp); 108static void do_menu(MenuRoot *menu, Window w); 109static Bool HENQueueScanner(Display *dpy, XEvent *ev, char *args); 110static Bool HLNQueueScanner(Display *dpy, XEvent *ev, char *args); 111static void flush_expose(Window w); 112static Bool UninstallRootColormapQScanner(Display *dpy, XEvent *ev, char *args); 113static void RedoIconName(void); 114 115int ButtonPressed = -1; 116int Cancel = FALSE; 117 118void 119AutoRaiseWindow(TwmWindow *tmp) 120{ 121 XRaiseWindow(dpy, tmp->frame); 122 XSync(dpy, 0); 123 enter_win = NULL; 124 enter_flag = TRUE; 125 raise_win = tmp; 126} 127 128void 129SetRaiseWindow(TwmWindow *tmp) 130{ 131 enter_flag = TRUE; 132 enter_win = NULL; 133 raise_win = tmp; 134 XSync(dpy, 0); 135} 136 137/** 138 * initialize the event jump table. 139 */ 140void 141InitEvents(void) 142{ 143 int i; 144 145 ResizeWindow = (Window) 0; 146 DragWindow = (Window) 0; 147 enter_flag = FALSE; 148 enter_win = raise_win = NULL; 149 150 for (i = 0; i < MAX_X_EVENT; i++) 151 EventHandler[i] = HandleUnknown; 152 153 EventHandler[Expose] = HandleExpose; 154 EventHandler[CreateNotify] = HandleCreateNotify; 155 EventHandler[DestroyNotify] = HandleDestroyNotify; 156 EventHandler[MapRequest] = HandleMapRequest; 157 EventHandler[MapNotify] = HandleMapNotify; 158 EventHandler[UnmapNotify] = HandleUnmapNotify; 159 EventHandler[MotionNotify] = HandleMotionNotify; 160 EventHandler[ButtonRelease] = HandleButtonRelease; 161 EventHandler[ButtonPress] = HandleButtonPress; 162 EventHandler[EnterNotify] = HandleEnterNotify; 163 EventHandler[LeaveNotify] = HandleLeaveNotify; 164 EventHandler[ConfigureRequest] = HandleConfigureRequest; 165 EventHandler[ClientMessage] = HandleClientMessage; 166 EventHandler[PropertyNotify] = HandlePropertyNotify; 167 EventHandler[KeyPress] = HandleKeyPress; 168 EventHandler[ColormapNotify] = HandleColormapNotify; 169 EventHandler[VisibilityNotify] = HandleVisibilityNotify; 170 if (HasShape) 171 EventHandler[ShapeEventBase + ShapeNotify] = HandleShapeNotify; 172#ifdef HAVE_XRANDR 173 if (HasXrandr) { 174 int scrnum; 175 176 EventHandler[XrandrEventBase + RRScreenChangeNotify] = 177 HandleScreenChangeNotify; 178 for (scrnum = 0; scrnum < NumScreens; scrnum++) { 179 XRRSelectInput(dpy, ScreenList[scrnum]->Root, 180 RRScreenChangeNotifyMask); 181 } 182 } 183#endif 184} 185 186Time lastTimestamp = CurrentTime; /* until Xlib does this for us */ 187 188Bool 189StashEventTime(XEvent *ev) 190{ 191 switch (ev->type) { 192 case KeyPress: 193 case KeyRelease: 194 lastTimestamp = ev->xkey.time; 195 return True; 196 case ButtonPress: 197 case ButtonRelease: 198 lastTimestamp = ev->xbutton.time; 199 return True; 200 case MotionNotify: 201 lastTimestamp = ev->xmotion.time; 202 return True; 203 case EnterNotify: 204 case LeaveNotify: 205 lastTimestamp = ev->xcrossing.time; 206 return True; 207 case PropertyNotify: 208 lastTimestamp = ev->xproperty.time; 209 return True; 210 case SelectionClear: 211 lastTimestamp = ev->xselectionclear.time; 212 return True; 213 case SelectionRequest: 214 lastTimestamp = ev->xselectionrequest.time; 215 return True; 216 case SelectionNotify: 217 lastTimestamp = ev->xselection.time; 218 return True; 219 } 220 return False; 221} 222 223/** 224 * return the window about which this event is concerned; this 225 * window may not be the same as XEvent.xany.window (the first window listed 226 * in the structure). 227 */ 228Window 229WindowOfEvent(XEvent *e) 230{ 231 /* 232 * Each window subfield is marked with whether or not it is the same as 233 * XEvent.xany.window or is different (which is the case for some of the 234 * notify events). 235 */ 236 /* *INDENT-OFF* */ 237 switch (e->type) { 238 case KeyPress: 239 case KeyRelease: return e->xkey.window; /* same */ 240 case ButtonPress: 241 case ButtonRelease: return e->xbutton.window; /* same */ 242 case MotionNotify: return e->xmotion.window; /* same */ 243 case EnterNotify: 244 case LeaveNotify: return e->xcrossing.window; /* same */ 245 case FocusIn: 246 case FocusOut: return e->xfocus.window; /* same */ 247 case KeymapNotify: return e->xkeymap.window; /* same */ 248 case Expose: return e->xexpose.window; /* same */ 249 case GraphicsExpose: return e->xgraphicsexpose.drawable; /* same */ 250 case NoExpose: return e->xnoexpose.drawable; /* same */ 251 case VisibilityNotify: return e->xvisibility.window; /* same */ 252 case CreateNotify: return e->xcreatewindow.window; /* DIFF */ 253 case DestroyNotify: return e->xdestroywindow.window; /* DIFF */ 254 case UnmapNotify: return e->xunmap.window; /* DIFF */ 255 case MapNotify: return e->xmap.window; /* DIFF */ 256 case MapRequest: return e->xmaprequest.window; /* DIFF */ 257 case ReparentNotify: return e->xreparent.window; /* DIFF */ 258 case ConfigureNotify: return e->xconfigure.window; /* DIFF */ 259 case ConfigureRequest: return e->xconfigurerequest.window; /* DIFF */ 260 case GravityNotify: return e->xgravity.window; /* DIFF */ 261 case ResizeRequest: return e->xresizerequest.window; /* same */ 262 case CirculateNotify: return e->xcirculate.window; /* DIFF */ 263 case CirculateRequest: return e->xcirculaterequest.window; /* DIFF */ 264 case PropertyNotify: return e->xproperty.window; /* same */ 265 case SelectionClear: return e->xselectionclear.window; /* same */ 266 case SelectionRequest: return e->xselectionrequest.requestor; /* DIFF */ 267 case SelectionNotify: return e->xselection.requestor; /* same */ 268 case ColormapNotify: return e->xcolormap.window; /* same */ 269 case ClientMessage: return e->xclient.window; /* same */ 270 case MappingNotify: return None; 271 } 272 /* *INDENT-ON* */ 273 return None; 274} 275 276/** 277 * handle a single X event stored in global var Event 278 * this routine for is for a call during an f.move 279 */ 280Bool 281DispatchEvent2(void) 282{ 283 Window w = Event.xany.window; 284 XPointer context_data; 285 StashEventTime(&Event); 286 287 if (XFindContext(dpy, w, TwmContext, &context_data) == 0) 288 Tmp_win = (TwmWindow *) context_data; 289 else 290 Tmp_win = NULL; 291 292 if (XFindContext(dpy, w, ScreenContext, &context_data) == 0) 293 Scr = (struct ScreenInfo *) context_data; 294 else 295 Scr = FindScreenInfo(WindowOfEvent(&Event)); 296 297 if (!Scr) 298 return False; 299 300 if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose) 301 HandleExpose(); 302 303 if (!menuFromFrameOrWindowOrTitlebar && Event.type >= 0 && 304 Event.type < MAX_X_EVENT) { 305 (*EventHandler[Event.type]) (); 306 } 307 308 return True; 309} 310 311/** 312 * handle a single X event stored in global var Event 313 */ 314Bool 315DispatchEvent(void) 316{ 317 Window w = Event.xany.window; 318 XPointer context_data; 319 StashEventTime(&Event); 320 321 if (XFindContext(dpy, w, TwmContext, &context_data) == 0) 322 Tmp_win = (TwmWindow *) context_data; 323 else 324 Tmp_win = NULL; 325 326 if (XFindContext(dpy, w, ScreenContext, &context_data) == 0) 327 Scr = (struct ScreenInfo *) context_data; 328 else 329 Scr = FindScreenInfo(WindowOfEvent(&Event)); 330 331 if (!Scr) 332 return False; 333 334 if (Event.type >= 0 && Event.type < MAX_X_EVENT) { 335 (*EventHandler[Event.type]) (); 336 } 337 338 return True; 339} 340 341/** 342 * handle X events 343 */ 344void 345HandleEvents(XtAppContext appContext) 346{ 347 while (TRUE) { 348 if (enter_flag && !QLength(dpy)) { 349 if (enter_win && enter_win != raise_win) { 350 AutoRaiseWindow(enter_win); /* sets enter_flag T */ 351 } 352 else { 353 enter_flag = FALSE; 354 } 355 } 356 if (ColortableThrashing && !QLength(dpy) && Scr) { 357 InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); 358 } 359 WindowMoved = FALSE; 360 XtAppNextEvent(appContext, &Event); 361 362 if (Event.type >= 0 && Event.type < MAX_X_EVENT) 363 (void) DispatchEvent(); 364 else 365 XtDispatchEvent(&Event); 366 } 367} 368 369/** 370 * colormap notify event handler. 371 * 372 * This procedure handles both a client changing its own colormap, and 373 * a client explicitly installing its colormap itself (only the window 374 * manager should do that, so we must set it correctly). 375 * 376 */ 377void 378HandleColormapNotify(void) 379{ 380 XColormapEvent *cevent = (XColormapEvent *) &Event; 381 ColormapWindow *cwin; 382 TwmColormap *cmap; 383 XPointer context_data; 384 385 if (XFindContext(dpy, cevent->window, ColormapContext, &context_data) == 0) 386 cwin = (ColormapWindow *) context_data; 387 else 388 return; 389 390 cmap = cwin->colormap; 391 392#if defined(__cplusplus) || defined(c_plusplus) 393 if (cevent->c_new) { 394#else 395 if (cevent->new) { 396#endif 397 if (XFindContext(dpy, cevent->colormap, ColormapContext, 398 &context_data) == XCNOENT) 399 cwin->colormap = CreateTwmColormap(cevent->colormap); 400 else { 401 cwin->colormap = (TwmColormap *) context_data; 402 cwin->colormap->refcnt++; 403 } 404 405 cmap->refcnt--; 406 407 if (cevent->state == ColormapUninstalled) 408 cmap->state &= ~CM_INSTALLED; 409 else 410 cmap->state |= CM_INSTALLED; 411 412 if (cmap->state & CM_INSTALLABLE) 413 InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); 414 415 if (cmap->refcnt == 0) { 416 XDeleteContext(dpy, cmap->c, ColormapContext); 417 free(cmap); 418 } 419 420 return; 421 } 422 423 if (cevent->state == ColormapUninstalled && (cmap->state & CM_INSTALLABLE)) { 424 if (!(cmap->state & CM_INSTALLED)) 425 return; 426 cmap->state &= ~CM_INSTALLED; 427 428 if (!ColortableThrashing) { 429 ColortableThrashing = TRUE; 430 XSync(dpy, 0); 431 } 432 433 if (cevent->serial >= Scr->cmapInfo.first_req) { 434 ColormapWindow **cwins; 435 int lost, won, n, number_cwins; 436 437 number_cwins = Scr->cmapInfo.cmaps->number_cwins; 438 439 /* 440 * Find out which colortables collided. 441 */ 442 443 cwins = Scr->cmapInfo.cmaps->cwins; 444 for (lost = won = -1, n = 0; 445 (lost == -1 || won == -1) && n < number_cwins; n++) { 446 if (lost == -1 && cwins[n] == cwin) { 447 lost = n; /* This is the window which lost its colormap */ 448 continue; 449 } 450 451 if (won == -1 && 452 cwins[n]->colormap->install_req == cevent->serial) { 453 won = n; /* This is the window whose colormap caused */ 454 continue; /* the de-install of the previous colormap */ 455 } 456 } 457 458 /* 459 ** Cases are: 460 ** Both the request and the window were found: 461 ** One of the installs made honoring the WM_COLORMAP 462 ** property caused another of the colormaps to be 463 ** de-installed, just mark the scoreboard. 464 ** 465 ** Only the request was found: 466 ** One of the installs made honoring the WM_COLORMAP 467 ** property caused a window not in the WM_COLORMAP 468 ** list to lose its map. This happens when the map 469 ** it is losing is one which is trying to be installed, 470 ** but is getting getting de-installed by another map 471 ** in this case, we'll get a scoreable event later, 472 ** this one is meaningless. 473 ** 474 ** Neither the request nor the window was found: 475 ** Somebody called installcolormap, but it doesn't 476 ** affect the WM_COLORMAP windows. This case will 477 ** probably never occur. 478 ** 479 ** Only the window was found: 480 ** One of the WM_COLORMAP windows lost its colormap 481 ** but it wasn't one of the requests known. This is 482 ** probably because someone did an "InstallColormap". 483 ** The colormap policy is "enforced" by re-installing 484 ** the colormaps which are believed to be correct. 485 */ 486 487 if (won != -1) { 488 if (lost != -1) { 489 /* lower diagonal index calculation */ 490 if (lost > won) 491 n = lost * (lost - 1) / 2 + won; 492 else 493 n = won * (won - 1) / 2 + lost; 494 Scr->cmapInfo.cmaps->scoreboard[n] = 1; 495 } 496 else { 497 /* 498 ** One of the cwin installs caused one of the cwin 499 ** colormaps to be de-installed, so I'm sure to get an 500 ** UninstallNotify for the cwin I know about later. 501 ** I haven't got it yet, or the test of CM_INSTALLED 502 ** above would have failed. Turning the CM_INSTALLED 503 ** bit back on makes sure we get back here to score 504 ** the collision. 505 */ 506 cmap->state |= CM_INSTALLED; 507 } 508 } 509 else if (lost != -1) { 510 InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); 511 } 512 } 513 } 514 515 else if (cevent->state == ColormapUninstalled) 516 cmap->state &= ~CM_INSTALLED; 517 518 else if (cevent->state == ColormapInstalled) 519 cmap->state |= CM_INSTALLED; 520} 521 522/** 523 * visibility notify event handler. 524 * 525 * This routine keeps track of visibility events so that colormap 526 * installation can keep the maximum number of useful colormaps 527 * installed at one time. 528 * 529 */ 530void 531HandleVisibilityNotify(void) 532{ 533 XVisibilityEvent *vevent = (XVisibilityEvent *) &Event; 534 ColormapWindow *cwin; 535 TwmColormap *cmap; 536 XPointer context_data; 537 538 if (XFindContext(dpy, vevent->window, ColormapContext, &context_data) == 0) 539 cwin = (ColormapWindow *) context_data; 540 else 541 return; 542 543 /* 544 * when Saber complains about retrieving an <int> from an <unsigned int> 545 * just type "touch vevent->state" and "cont" 546 */ 547 cmap = cwin->colormap; 548 if ((cmap->state & CM_INSTALLABLE) && 549 vevent->state != cwin->visibility && 550 (vevent->state == VisibilityFullyObscured || 551 cwin->visibility == VisibilityFullyObscured) && cmap->w == cwin->w) { 552 cwin->visibility = vevent->state; 553 InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL); 554 } 555 else 556 cwin->visibility = vevent->state; 557} 558 559int MovedFromKeyPress = False; 560 561/** 562 * key press event handler 563 */ 564void 565HandleKeyPress(void) 566{ 567 KeySym ks; 568 FuncKey *key; 569 int len; 570 unsigned int modifier; 571 572 if (InfoLines) 573 XUnmapWindow(dpy, Scr->InfoWindow); 574 Context = C_NO_CONTEXT; 575 576 if (Event.xany.window == Scr->Root) 577 Context = C_ROOT; 578 if (Tmp_win) { 579 if (Event.xany.window == Tmp_win->title_w) 580 Context = C_TITLE; 581 if (Event.xany.window == Tmp_win->w) 582 Context = C_WINDOW; 583 if (Event.xany.window == Tmp_win->icon_w) 584 Context = C_ICON; 585 if (Event.xany.window == Tmp_win->frame) 586 Context = C_FRAME; 587 if (Tmp_win->list && Event.xany.window == Tmp_win->list->w) 588 Context = C_ICONMGR; 589 if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon) 590 Context = C_ICONMGR; 591 } 592 593 modifier = (Event.xkey.state & mods_used); 594 ks = XLookupKeysym((XKeyEvent *) &Event, /* KeySyms index */ 0); 595 596 for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next) { 597 if (key->keysym == ks && 598 (unsigned) key->mods == modifier && 599 (key->cont == Context || key->cont == C_NAME)) { 600 /* weed out the functions that don't make sense to execute 601 * from a key press 602 */ 603 if (key->func == F_RESIZE) 604 return; 605 /* special case for F_MOVE/F_FORCEMOVE activated from a keypress */ 606 if (key->func == F_MOVE || key->func == F_FORCEMOVE) 607 MovedFromKeyPress = True; 608 609 if (key->cont != C_NAME) { 610 ExecuteFunction(key->func, key->action, Event.xany.window, 611 Tmp_win, &Event, Context, FALSE); 612 XUngrabPointer(dpy, CurrentTime); 613 return; 614 } 615 else { 616 int matched = FALSE; 617 618 len = (int) strlen(key->win_name); 619 620 /* try and match the name first */ 621 for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL; 622 Tmp_win = Tmp_win->next) { 623 if (!strncmp(key->win_name, Tmp_win->name, (size_t) len)) { 624 matched = TRUE; 625 ExecuteFunction(key->func, key->action, Tmp_win->frame, 626 Tmp_win, &Event, C_FRAME, FALSE); 627 XUngrabPointer(dpy, CurrentTime); 628 } 629 } 630 631 /* now try the res_name */ 632 if (!matched) 633 for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL; 634 Tmp_win = Tmp_win->next) { 635 if (!strncmp 636 (key->win_name, Tmp_win->xclass.res_name, 637 (size_t) len)) { 638 matched = TRUE; 639 ExecuteFunction(key->func, key->action, 640 Tmp_win->frame, Tmp_win, &Event, 641 C_FRAME, FALSE); 642 XUngrabPointer(dpy, CurrentTime); 643 } 644 } 645 646 /* now try the res_class */ 647 if (!matched) 648 for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL; 649 Tmp_win = Tmp_win->next) { 650 if (!strncmp 651 (key->win_name, Tmp_win->xclass.res_class, 652 (size_t) len)) { 653 matched = TRUE; 654 ExecuteFunction(key->func, key->action, 655 Tmp_win->frame, Tmp_win, &Event, 656 C_FRAME, FALSE); 657 XUngrabPointer(dpy, CurrentTime); 658 } 659 } 660 if (matched) 661 return; 662 } 663 } 664 } 665 666 /* if we get here, no function key was bound to the key. Send it 667 * to the client if it was in a window we know about. 668 */ 669 if (Tmp_win) { 670 if (Event.xany.window == Tmp_win->icon_w || 671 Event.xany.window == Tmp_win->frame || 672 Event.xany.window == Tmp_win->title_w || 673 (Tmp_win->list && (Event.xany.window == Tmp_win->list->w))) { 674 Event.xkey.window = Tmp_win->w; 675 XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event); 676 } 677 } 678 679} 680 681static void 682free_window_names(TwmWindow *tmp, Bool nukefull, Bool nukename, Bool nukeicon) 683{ 684/* 685 * XXX - are we sure that nobody ever sets these to another constant (check 686 * twm windows)? 687 */ 688 if (tmp->name == tmp->full_name) 689 nukefull = False; 690 if (tmp->icon_name == tmp->name) 691 nukename = False; 692 693 if (nukefull && tmp->full_name) 694 free(tmp->full_name); 695 if (nukename && tmp->name) 696 free(tmp->name); 697 if (nukeicon && tmp->icon_name) 698 free(tmp->icon_name); 699 return; 700} 701 702void 703free_cwins(TwmWindow *tmp) 704{ 705 if (tmp->cmaps.number_cwins) { 706 int i; 707 708 for (i = 0; i < tmp->cmaps.number_cwins; i++) { 709 710 if (--tmp->cmaps.cwins[i]->refcnt == 0) { 711 TwmColormap *cmap = tmp->cmaps.cwins[i]->colormap; 712 713 if (--cmap->refcnt == 0) { 714 XDeleteContext(dpy, cmap->c, ColormapContext); 715 free(cmap); 716 } 717 XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext); 718 free(tmp->cmaps.cwins[i]); 719 } 720 } 721 free(tmp->cmaps.cwins); 722 723 if (tmp->cmaps.number_cwins > 1) { 724 free(tmp->cmaps.scoreboard); 725 tmp->cmaps.scoreboard = NULL; 726 } 727 tmp->cmaps.number_cwins = 0; 728 } 729} 730 731/** 732 * property notify event handler 733 */ 734void 735HandlePropertyNotify(void) 736{ 737 char *name = NULL; 738 XSetWindowAttributes attributes; /* attributes for create windows */ 739 Pixmap pm; 740 int dummy = 0; 741 unsigned udummy = 0; 742 Window wdummy = None; 743 744 /* watch for standard colormap changes */ 745 if (Event.xproperty.window == Scr->Root) { 746 XStandardColormap *maps = NULL; 747 int nmaps; 748 749 switch (Event.xproperty.state) { 750 case PropertyNewValue: 751 if (XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps, 752 Event.xproperty.atom)) { 753 /* if got one, then replace any existing entry */ 754 InsertRGBColormap(Event.xproperty.atom, maps, nmaps, True); 755 } 756 return; 757 758 case PropertyDelete: 759 RemoveRGBColormap(Event.xproperty.atom); 760 761 return; 762 } 763 } 764 765 if (!Tmp_win) 766 return; /* unknown window */ 767 768#define MAX_NAME_LEN 200L /* truncate to this many */ 769#define MAX_ICON_NAME_LEN 200L /* ditto */ 770 771 switch (Event.xproperty.atom) { 772 case XA_WM_NAME: 773 if (!I18N_FetchName(dpy, Tmp_win->w, &name)) 774 return; 775 free_window_names(Tmp_win, True, True, False); 776 777 Tmp_win->full_name = strdup(name ? name : NoName); 778 Tmp_win->name = strdup(name ? name : NoName); 779 if (name) 780 free(name); 781 782 Tmp_win->nameChanged = 1; 783 784 Tmp_win->name_width = MyFont_TextWidth(&Scr->TitleBarFont, 785 Tmp_win->name, 786 (int) strlen(Tmp_win->name)); 787 788 SetupWindow(Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y, 789 Tmp_win->frame_width, Tmp_win->frame_height, -1); 790 791 if (Tmp_win->title_w) 792 XClearArea(dpy, Tmp_win->title_w, 0, 0, 0, 0, True); 793 794 /* 795 * if the icon name is NoName, set the name of the icon to be 796 * the same as the window 797 */ 798 if (Tmp_win->icon_name == NoName) { 799 Tmp_win->icon_name = Tmp_win->name; 800 RedoIconName(); 801 } 802 break; 803 804 case XA_WM_ICON_NAME: 805 if (!I18N_GetIconName(dpy, Tmp_win->w, &name)) 806 return; 807 free_window_names(Tmp_win, False, False, True); 808 Tmp_win->icon_name = strdup(name ? name : NoName); 809 if (name) 810 free(name); 811 812 RedoIconName(); 813 break; 814 815 case XA_WM_HINTS: 816 if (Tmp_win->wmhints) 817 XFree(Tmp_win->wmhints); 818 Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window); 819 820 if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint)) 821 Tmp_win->group = Tmp_win->wmhints->window_group; 822 823 if (Tmp_win->icon_not_ours && Tmp_win->wmhints && 824 !(Tmp_win->wmhints->flags & IconWindowHint)) { 825 /* IconWindowHint was formerly on, now off; revert 826 // to a default icon */ 827 int icon_x = 0, icon_y = 0; 828 829 XGetGeometry(dpy, Tmp_win->icon_w, &wdummy, 830 &icon_x, &icon_y, 831 &udummy, &udummy, &udummy, &udummy); 832 XSelectInput(dpy, Tmp_win->icon_w, None); 833 XDeleteContext(dpy, Tmp_win->icon_w, TwmContext); 834 XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext); 835 CreateIconWindow(Tmp_win, icon_x, icon_y); 836 break; 837 } 838 839 if (!Tmp_win->forced && Tmp_win->wmhints && 840 Tmp_win->wmhints->flags & IconWindowHint) { 841 if (Tmp_win->icon_w) { 842 int icon_x, icon_y; 843 844 /* 845 * There's already an icon window. 846 * Try to find out where it is; if we succeed, move the new 847 * window to where the old one is. 848 */ 849 if (XGetGeometry(dpy, Tmp_win->icon_w, &wdummy, &icon_x, 850 &icon_y, &udummy, &udummy, &udummy, 851 &udummy)) { 852 /* 853 * Move the new icon window to where the old one was. 854 */ 855 XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x, 856 icon_y); 857 } 858 859 /* 860 * If the window is iconic, map the new icon window. 861 */ 862 if (Tmp_win->icon) 863 XMapWindow(dpy, Tmp_win->wmhints->icon_window); 864 865 /* 866 * Now, if the old window isn't ours, unmap it, otherwise 867 * just get rid of it completely. 868 */ 869 if (Tmp_win->icon_not_ours) { 870 if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window) 871 XUnmapWindow(dpy, Tmp_win->icon_w); 872 } 873 else 874 XDestroyWindow(dpy, Tmp_win->icon_w); 875 876 XDeleteContext(dpy, Tmp_win->icon_w, TwmContext); 877 XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext); 878 879 /* 880 * The new icon window isn't our window, so note that fact 881 * so that we don't treat it as ours. 882 */ 883 Tmp_win->icon_not_ours = TRUE; 884 885 /* 886 * Now make the new window the icon window for this window, 887 * and set it up to work as such (select for key presses 888 * and button presses/releases, set up the contexts for it, 889 * and define the cursor for it). 890 */ 891 Tmp_win->icon_w = Tmp_win->wmhints->icon_window; 892 XSelectInput(dpy, Tmp_win->icon_w, 893 KeyPressMask | ButtonPressMask | 894 ButtonReleaseMask); 895 XSaveContext(dpy, Tmp_win->icon_w, TwmContext, 896 (XPointer) Tmp_win); 897 XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, 898 (XPointer) Scr); 899 XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor); 900 } 901 } 902 903 if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints && 904 (Tmp_win->wmhints->flags & IconPixmapHint)) { 905 unsigned long valuemask; /* mask for create windows */ 906 907 if (!XGetGeometry(dpy, Tmp_win->wmhints->icon_pixmap, &wdummy, 908 &dummy, &dummy, 909 (unsigned int *) &Tmp_win->icon_width, 910 (unsigned int *) &Tmp_win->icon_height, &udummy, 911 &udummy)) { 912 return; 913 } 914 915 pm = XCreatePixmap(dpy, Scr->Root, (unsigned) Tmp_win->icon_width, 916 (unsigned) Tmp_win->icon_height, 917 (unsigned) Scr->d_depth); 918 919 FB(Tmp_win->iconc.fore, Tmp_win->iconc.back); 920 XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, 921 Scr->NormalGC, 922 0, 0, (unsigned) Tmp_win->icon_width, 923 (unsigned) Tmp_win->icon_height, 0, 0, 1); 924 925 valuemask = CWBackPixmap; 926 attributes.background_pixmap = pm; 927 928 if (Tmp_win->icon_bm_w) 929 XDestroyWindow(dpy, Tmp_win->icon_bm_w); 930 931 Tmp_win->icon_bm_w = 932 XCreateWindow(dpy, Tmp_win->icon_w, 0, 0, 933 (unsigned int) Tmp_win->icon_width, 934 (unsigned int) Tmp_win->icon_height, 935 (unsigned int) 0, Scr->d_depth, 936 (unsigned int) CopyFromParent, Scr->d_visual, 937 valuemask, &attributes); 938 939 XFreePixmap(dpy, pm); 940 RedoIconName(); 941 } 942 break; 943 944 case XA_WM_NORMAL_HINTS: 945 GetWindowSizeHints(Tmp_win); 946 break; 947 948 default: 949 if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) { 950 FetchWmColormapWindows(Tmp_win); /* frees old data */ 951 break; 952 } 953 else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) { 954 FetchWmProtocols(Tmp_win); 955 break; 956 } 957 break; 958 } 959} 960 961/** 962 * procedure to re-position the icon window and name 963 */ 964static void 965RedoIconName(void) 966{ 967 int x, y; 968 969 if (Tmp_win->list) { 970 /* let the expose event cause the repaint */ 971 XClearArea(dpy, Tmp_win->list->w, 0, 0, 0, 0, True); 972 973 if (Scr->SortIconMgr) 974 SortIconManager(Tmp_win->list->iconmgr); 975 } 976 977 if (Tmp_win->icon_w == (Window) 0) 978 return; 979 980 if (Tmp_win->icon_not_ours) 981 return; 982 983 Tmp_win->icon_w_width = MyFont_TextWidth(&Scr->IconFont, 984 Tmp_win->icon_name, 985 (int) strlen(Tmp_win->icon_name)); 986 987 Tmp_win->icon_w_width += 6; 988 if (Tmp_win->icon_w_width < Tmp_win->icon_width) { 989 Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width) / 2; 990 Tmp_win->icon_x += 3; 991 Tmp_win->icon_w_width = Tmp_win->icon_width; 992 } 993 else { 994 Tmp_win->icon_x = 3; 995 } 996 997 if (Tmp_win->icon_w_width == Tmp_win->icon_width) 998 x = 0; 999 else 1000 x = (Tmp_win->icon_w_width - Tmp_win->icon_width) / 2; 1001 1002 y = 0; 1003 1004 Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4; 1005 Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height; 1006 1007 XResizeWindow(dpy, Tmp_win->icon_w, (unsigned) Tmp_win->icon_w_width, 1008 (unsigned) Tmp_win->icon_w_height); 1009 if (Tmp_win->icon_bm_w) { 1010 XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y); 1011 XMapWindow(dpy, Tmp_win->icon_bm_w); 1012 } 1013 if (Tmp_win->icon) { 1014 XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True); 1015 } 1016} 1017 1018/** 1019 *client message event handler 1020 */ 1021void 1022HandleClientMessage(void) 1023{ 1024 int dummy = 0; 1025 unsigned udummy = 0; 1026 Window wdummy = None; 1027 1028 if (Event.xclient.message_type == _XA_WM_CHANGE_STATE) { 1029 if (Tmp_win != NULL) { 1030 if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon) { 1031 XEvent button; 1032 1033 XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy, 1034 &(button.xmotion.x_root), 1035 &(button.xmotion.y_root), 1036 &dummy, &dummy, &udummy); 1037 1038 ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window, 1039 Tmp_win, &button, FRAME, FALSE); 1040 XUngrabPointer(dpy, CurrentTime); 1041 } 1042 } 1043 } 1044} 1045 1046/** 1047 * expose event handler 1048 */ 1049void 1050HandleExpose(void) 1051{ 1052 XPointer context_data; 1053 1054 if (XFindContext(dpy, Event.xany.window, MenuContext, &context_data) == 0) { 1055 MenuRoot *tmp = (MenuRoot *) context_data; 1056 PaintMenu(tmp, &Event); 1057 1058 return; 1059 } 1060 1061 if (Event.xexpose.count != 0) 1062 return; 1063 1064 if (Event.xany.window == Scr->InfoWindow && InfoLines) { 1065 int i; 1066 int height; 1067 1068 MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back, 1069 &Scr->DefaultFont); 1070 1071 height = Scr->DefaultFont.height + 2; 1072 for (i = 0; i < InfoLines; i++) { 1073 MyFont_DrawString(dpy, Scr->InfoWindow, &Scr->DefaultFont, 1074 Scr->NormalGC, 5, 1075 (i * height) + Scr->DefaultFont.y, Info[i], 1076 (int) strlen(Info[i])); 1077 } 1078 flush_expose(Event.xany.window); 1079 } 1080 else if (Tmp_win != NULL) { 1081 if (Event.xany.window == Tmp_win->title_w) { 1082 MyFont_ChangeGC(Tmp_win->title.fore, Tmp_win->title.back, 1083 &Scr->TitleBarFont); 1084 1085 MyFont_DrawString(dpy, Tmp_win->title_w, &Scr->TitleBarFont, 1086 Scr->NormalGC, Scr->TBInfo.titlex, 1087 Scr->TitleBarFont.y, Tmp_win->name, 1088 (int) strlen(Tmp_win->name)); 1089 flush_expose(Event.xany.window); 1090 } 1091 else if (Event.xany.window == Tmp_win->icon_w) { 1092 MyFont_ChangeGC(Tmp_win->iconc.fore, Tmp_win->iconc.back, 1093 &Scr->IconFont); 1094 1095 MyFont_DrawString(dpy, Tmp_win->icon_w, &Scr->IconFont, 1096 Scr->NormalGC, Tmp_win->icon_x, Tmp_win->icon_y, 1097 Tmp_win->icon_name, 1098 (int) strlen(Tmp_win->icon_name)); 1099 flush_expose(Event.xany.window); 1100 1101 return; 1102 } 1103 else if (Tmp_win->titlebuttons) { 1104 int i; 1105 Window w = Event.xany.window; 1106 TBWindow *tbw; 1107 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1108 1109 for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) { 1110 if (w == tbw->window) { 1111 TitleButton *tb = tbw->info; 1112 1113 FB(Tmp_win->title.fore, Tmp_win->title.back); 1114 XCopyPlane(dpy, tb->bitmap, w, Scr->NormalGC, 1115 tb->srcx, tb->srcy, tb->width, tb->height, 1116 tb->dstx, tb->dsty, 1); 1117 flush_expose(w); 1118 return; 1119 } 1120 } 1121 } 1122 if (Tmp_win->list) { 1123 if (Event.xany.window == Tmp_win->list->w) { 1124 MyFont_ChangeGC(Tmp_win->list->fore, Tmp_win->list->back, 1125 &Scr->IconManagerFont); 1126 MyFont_DrawString(dpy, Event.xany.window, 1127 &Scr->IconManagerFont, Scr->NormalGC, 1128 iconmgr_textx, Scr->IconManagerFont.y + 4, 1129 Tmp_win->icon_name, 1130 (int) strlen(Tmp_win->icon_name)); 1131 DrawIconManagerBorder(Tmp_win->list); 1132 flush_expose(Event.xany.window); 1133 1134 return; 1135 } 1136 if (Event.xany.window == Tmp_win->list->icon) { 1137 FB(Tmp_win->list->fore, Tmp_win->list->back); 1138 XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon, 1139 Scr->NormalGC, 1140 0, 0, (unsigned) iconifybox_width, 1141 (unsigned) iconifybox_height, 0, 0, 1); 1142 flush_expose(Event.xany.window); 1143 1144 return; 1145 } 1146 } 1147 } 1148} 1149 1150static void 1151remove_window_from_ring(TwmWindow *tmp) 1152{ 1153 TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next; 1154 1155 if (enter_win == tmp) { 1156 enter_flag = FALSE; 1157 enter_win = NULL; 1158 } 1159 if (raise_win == Tmp_win) 1160 raise_win = NULL; 1161 1162 /* 1163 * 1. Unlink window 1164 * 2. If window was only thing in ring, null out ring 1165 * 3. If window was ring leader, set to next (or null) 1166 */ 1167 if (prev) 1168 prev->ring.next = next; 1169 if (next) 1170 next->ring.prev = prev; 1171 if (Scr->Ring == tmp) 1172 Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL); 1173 1174 if (!Scr->Ring || Scr->RingLeader == tmp) 1175 Scr->RingLeader = Scr->Ring; 1176} 1177 1178/** 1179 * DestroyNotify event handler 1180 */ 1181void 1182HandleDestroyNotify(void) 1183{ 1184 1185 /* 1186 * Warning, this is also called by HandleUnmapNotify; if it ever needs to 1187 * look at the event, HandleUnmapNotify will have to mash the UnmapNotify 1188 * into a DestroyNotify. 1189 */ 1190 1191 if (Tmp_win == NULL) 1192 return; 1193 1194 if (Tmp_win == Scr->Focus) { 1195 FocusOnRoot(); 1196 } 1197 XDeleteContext(dpy, Tmp_win->w, TwmContext); 1198 XDeleteContext(dpy, Tmp_win->w, ScreenContext); 1199 XDeleteContext(dpy, Tmp_win->frame, TwmContext); 1200 XDeleteContext(dpy, Tmp_win->frame, ScreenContext); 1201 if (Tmp_win->icon_w) { 1202 XDeleteContext(dpy, Tmp_win->icon_w, TwmContext); 1203 XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext); 1204 } 1205 if (Tmp_win->title_height) { 1206 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1207 1208 XDeleteContext(dpy, Tmp_win->title_w, TwmContext); 1209 XDeleteContext(dpy, Tmp_win->title_w, ScreenContext); 1210 if (Tmp_win->hilite_w) { 1211 XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext); 1212 XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext); 1213 } 1214 1215 if (Tmp_win->titlebuttons) { 1216 int i; 1217 1218 for (i = 0; i < nb; i++) { 1219 XDeleteContext(dpy, Tmp_win->titlebuttons[i].window, 1220 TwmContext); 1221 XDeleteContext(dpy, Tmp_win->titlebuttons[i].window, 1222 ScreenContext); 1223 } 1224 } 1225 } 1226 1227 if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps) 1228 InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot); 1229 1230 /* 1231 * TwmWindows contain the following pointers 1232 * 1233 * 1. full_name 1234 * 2. name 1235 * 3. icon_name 1236 * 4. wmhints 1237 * 5. xclass.res_name 1238 * 6. xclass.res_class 1239 * 7. list 1240 * 8. iconmgrp 1241 * 9. cwins 1242 * 10. titlebuttons 1243 * 11. window ring 1244 */ 1245 if (Tmp_win->gray) 1246 XFreePixmap(dpy, Tmp_win->gray); 1247 1248 XDestroyWindow(dpy, Tmp_win->frame); 1249 if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) { 1250 XDestroyWindow(dpy, Tmp_win->icon_w); 1251 IconDown(Tmp_win); 1252 } 1253 RemoveIconManager(Tmp_win); /* 7 */ 1254 Tmp_win->prev->next = Tmp_win->next; 1255 if (Tmp_win->next != NULL) 1256 Tmp_win->next->prev = Tmp_win->prev; 1257 if (Tmp_win->auto_raise) 1258 Scr->NumAutoRaises--; 1259 1260 free_window_names(Tmp_win, True, True, True); /* 1, 2, 3 */ 1261 if (Tmp_win->wmhints) /* 4 */ 1262 XFree(Tmp_win->wmhints); 1263 if (Tmp_win->xclass.res_name && 1264 Tmp_win->xclass.res_name != NoName) /* 5 */ 1265 XFree(Tmp_win->xclass.res_name); 1266 if (Tmp_win->xclass.res_class && 1267 Tmp_win->xclass.res_class != NoName) /* 6 */ 1268 XFree(Tmp_win->xclass.res_class); 1269 free_cwins(Tmp_win); /* 9 */ 1270 if (Tmp_win->titlebuttons) /* 10 */ 1271 free(Tmp_win->titlebuttons); 1272 remove_window_from_ring(Tmp_win); /* 11 */ 1273 1274 if (UnHighLight_win == Tmp_win) 1275 UnHighLight_win = NULL; 1276 1277 free(Tmp_win); 1278} 1279 1280void 1281HandleCreateNotify(void) 1282{ 1283#ifdef DEBUG_EVENTS 1284 fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window); 1285 1286 fflush(stderr); 1287 Bell(XkbBI_Info, 0, Event.xcreatewindow.window); 1288 1289 XSync(dpy, 0); 1290#endif 1291} 1292 1293/** 1294 * HandleMapRequest - MapRequest event handler 1295 */ 1296void 1297HandleMapRequest(void) 1298{ 1299 XPointer context_data; 1300 1301 Event.xany.window = Event.xmaprequest.window; 1302 if (XFindContext(dpy, Event.xany.window, TwmContext, &context_data) == 0) 1303 Tmp_win = (TwmWindow *) context_data; 1304 1305 else 1306 Tmp_win = NULL; 1307 1308 /* If the window has never been mapped before ... */ 1309 if (Tmp_win == NULL) { 1310 /* Add decorations. */ 1311 Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL); 1312 1313 if (Tmp_win == NULL) 1314 return; 1315 } 1316 else { 1317 /* 1318 * If the window has been unmapped by the client, it won't be listed 1319 * in the icon manager. Add it again, if requested. 1320 */ 1321 if (Tmp_win->list == NULL) 1322 (void) AddIconManager(Tmp_win); 1323 } 1324 1325 /* If it's not merely iconified, and we have hints, use them. */ 1326 if ((!Tmp_win->icon) && 1327 Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint)) { 1328 int state; 1329 int zoom_save; 1330 Window icon; 1331 1332 /* use WM_STATE if enabled */ 1333 if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) && 1334 (state == NormalState || state == IconicState))) 1335 state = Tmp_win->wmhints->initial_state; 1336 1337 switch (state) { 1338 case DontCareState: 1339 case NormalState: 1340 case ZoomState: 1341 case InactiveState: 1342 XMapWindow(dpy, Tmp_win->w); 1343 XMapWindow(dpy, Tmp_win->frame); 1344 SetMapStateProp(Tmp_win, NormalState); 1345 SetRaiseWindow(Tmp_win); 1346 break; 1347 1348 case IconicState: 1349 zoom_save = Scr->DoZoom; 1350 Scr->DoZoom = FALSE; 1351 Iconify(Tmp_win, 0, 0); 1352 Scr->DoZoom = (short) zoom_save; 1353 break; 1354 } 1355 } 1356 /* If no hints, or currently an icon, just "deiconify" */ 1357 else { 1358 DeIconify(Tmp_win); 1359 SetRaiseWindow(Tmp_win); 1360 } 1361} 1362 1363void 1364SimulateMapRequest(Window w) 1365{ 1366 Event.xmaprequest.window = w; 1367 1368 HandleMapRequest(); 1369} 1370 1371/** 1372 * MapNotify event handler 1373 */ 1374void 1375HandleMapNotify(void) 1376{ 1377 if (Tmp_win == NULL) 1378 return; 1379 1380 /* 1381 * Need to do the grab to avoid race condition of having server send 1382 * MapNotify to client before the frame gets mapped; this is bad because 1383 * the client would think that the window has a chance of being viewable 1384 * when it really isn't. 1385 */ 1386 XGrabServer(dpy); 1387 if (Tmp_win->icon_w) 1388 XUnmapWindow(dpy, Tmp_win->icon_w); 1389 if (Tmp_win->title_w) 1390 XMapSubwindows(dpy, Tmp_win->title_w); 1391 XMapSubwindows(dpy, Tmp_win->frame); 1392 if (Scr->Focus != Tmp_win && Tmp_win->hilite_w) 1393 XUnmapWindow(dpy, Tmp_win->hilite_w); 1394 1395 XMapWindow(dpy, Tmp_win->frame); 1396 XUngrabServer(dpy); 1397 XFlush(dpy); 1398 Tmp_win->mapped = TRUE; 1399 Tmp_win->icon = FALSE; 1400 Tmp_win->icon_on = FALSE; 1401} 1402 1403/** 1404 * UnmapNotify event handler 1405 */ 1406void 1407HandleUnmapNotify(void) 1408{ 1409 int dstx, dsty; 1410 Window dumwin; 1411 XPointer context_data; 1412 1413 /* 1414 * The July 27, 1988 ICCCM spec states that a client wishing to switch 1415 * to WithdrawnState should send a synthetic UnmapNotify with the 1416 * event field set to (pseudo-)root, in case the window is already 1417 * unmapped (which is the case for twm for IconicState). Unfortunately, 1418 * we looked for the TwmContext using that field, so try the window 1419 * field also. 1420 */ 1421 if (Tmp_win == NULL) { 1422 Event.xany.window = Event.xunmap.window; 1423 if (XFindContext(dpy, Event.xany.window, 1424 TwmContext, &context_data) == 0) 1425 Tmp_win = (TwmWindow *) context_data; 1426 1427 else 1428 Tmp_win = NULL; 1429 } 1430 1431 if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon)) 1432 return; 1433 1434 /* 1435 * The program may have unmapped the client window, from either 1436 * NormalState or IconicState. Handle the transition to WithdrawnState. 1437 * 1438 * We need to reparent the window back to the root (so that twm exiting 1439 * won't cause it to get mapped) and then throw away all state (pretend 1440 * that we've received a DestroyNotify). 1441 */ 1442 1443 XGrabServer(dpy); 1444 if (XTranslateCoordinates(dpy, Event.xunmap.window, Tmp_win->attr.root, 1445 0, 0, &dstx, &dsty, &dumwin)) { 1446 XEvent ev; 1447 Bool reparented = XCheckTypedWindowEvent(dpy, Event.xunmap.window, 1448 ReparentNotify, &ev); 1449 1450 SetMapStateProp(Tmp_win, WithdrawnState); 1451 if (reparented) { 1452 if (Tmp_win->old_bw) 1453 XSetWindowBorderWidth(dpy, 1454 Event.xunmap.window, 1455 (unsigned) Tmp_win->old_bw); 1456 if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint)) 1457 XUnmapWindow(dpy, Tmp_win->wmhints->icon_window); 1458 } 1459 else { 1460 XReparentWindow(dpy, Event.xunmap.window, Tmp_win->attr.root, 1461 dstx, dsty); 1462 RestoreWithdrawnLocation(Tmp_win); 1463 } 1464 XRemoveFromSaveSet(dpy, Event.xunmap.window); 1465 XSelectInput(dpy, Event.xunmap.window, NoEventMask); 1466 1467 HandleDestroyNotify(); /* do not need to mash event before */ 1468 } /* else window no longer exists and we'll get a destroy notify */ 1469 XUngrabServer(dpy); 1470 XFlush(dpy); 1471} 1472 1473/** 1474 * MotionNotify event handler 1475 */ 1476void 1477HandleMotionNotify(void) 1478{ 1479 XPointer context_data; 1480 unsigned udummy = 0; 1481 Window wdummy = None; 1482 1483 if (ResizeWindow != (Window) 0) { 1484 XQueryPointer(dpy, Event.xany.window, 1485 &(Event.xmotion.root), &wdummy, 1486 &(Event.xmotion.x_root), &(Event.xmotion.y_root), 1487 &(Event.xmotion.x), &(Event.xmotion.y), &udummy); 1488 1489 /* Set WindowMoved appropriately so that f.deltastop will 1490 work with resize as well as move. */ 1491 if (abs(Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta 1492 || abs(Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta) 1493 WindowMoved = TRUE; 1494 1495 if (XFindContext(dpy, ResizeWindow, TwmContext, &context_data) == 0) 1496 Tmp_win = (TwmWindow *) context_data; 1497 DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win); 1498 } 1499} 1500 1501/** 1502 * ButtonRelease event handler 1503 */ 1504void 1505HandleButtonRelease(void) 1506{ 1507 unsigned mask; 1508 XPointer context_data; 1509 1510 if (InfoLines) /* delete info box on 2nd button release */ 1511 if (Context == C_IDENTIFY) { 1512 XUnmapWindow(dpy, Scr->InfoWindow); 1513 InfoLines = 0; 1514 Context = C_NO_CONTEXT; 1515 } 1516 1517 if (DragWindow != None) { 1518 int xl, yt; 1519 int w, h; 1520 1521 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 1522 1523 if (XFindContext(dpy, DragWindow, TwmContext, &context_data) == 0) 1524 Tmp_win = (TwmWindow *) context_data; 1525 if (DragWindow == Tmp_win->frame) { 1526 xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw; 1527 yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw; 1528 1529 w = DragWidth + 2 * Tmp_win->frame_bw; 1530 h = DragHeight + 2 * Tmp_win->frame_bw; 1531 } 1532 else { 1533 xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth; 1534 yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth; 1535 1536 w = DragWidth + 2 * Scr->IconBorderWidth; 1537 h = DragHeight + 2 * Scr->IconBorderWidth; 1538 } 1539 1540 if (ConstMove) { 1541 if (ConstMoveDir == MOVE_HORIZ) 1542 yt = ConstMoveY; 1543 1544 if (ConstMoveDir == MOVE_VERT) 1545 xl = ConstMoveX; 1546 1547 if (ConstMoveDir == MOVE_NONE) { 1548 yt = ConstMoveY; 1549 xl = ConstMoveX; 1550 } 1551 } 1552 1553 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) { 1554 int xr = xl + w; 1555 int yb = yt + h; 1556 1557 if (xl < 0) 1558 xl = 0; 1559 if (xr > Scr->MyDisplayWidth) 1560 xl = Scr->MyDisplayWidth - w; 1561 1562 if (yt < 0) 1563 yt = 0; 1564 if (yb > Scr->MyDisplayHeight) 1565 yt = Scr->MyDisplayHeight - h; 1566 } 1567 1568 CurrentDragX = xl; 1569 CurrentDragY = yt; 1570 if (DragWindow == Tmp_win->frame) 1571 SetupWindow(Tmp_win, xl, yt, 1572 Tmp_win->frame_width, Tmp_win->frame_height, -1); 1573 else 1574 XMoveWindow(dpy, DragWindow, xl, yt); 1575 1576 if (!Scr->NoRaiseMove && !Scr->OpaqueMove) /* opaque already did */ 1577 XRaiseWindow(dpy, DragWindow); 1578 1579 if (!Scr->OpaqueMove) 1580 UninstallRootColormap(); 1581 else 1582 XSync(dpy, 0); 1583 1584 if (Scr->NumAutoRaises) { 1585 enter_flag = TRUE; 1586 enter_win = NULL; 1587 raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove) 1588 ? Tmp_win : NULL); 1589 } 1590 1591 DragWindow = (Window) 0; 1592 ConstMove = FALSE; 1593 } 1594 1595 if (ResizeWindow != (Window) 0) { 1596 EndResize(); 1597 } 1598 1599 if (ActiveMenu != NULL && RootFunction == 0) { 1600 if (ActiveItem != NULL) { 1601 int func = ActiveItem->func; 1602 1603 Action = ActiveItem->action; 1604 switch (func) { 1605 case F_MOVE: 1606 case F_FORCEMOVE: 1607 ButtonPressed = -1; 1608 break; 1609 case F_WARPTOSCREEN: 1610 XUngrabPointer(dpy, CurrentTime); 1611 /* fall through */ 1612 case F_CIRCLEUP: 1613 case F_CIRCLEDOWN: 1614 case F_REFRESH: 1615 PopDownMenu(); 1616 break; 1617 default: 1618 break; 1619 } 1620 ExecuteFunction(func, Action, 1621 ButtonWindow ? ButtonWindow->frame : None, 1622 ButtonWindow, &Event /*&ButtonEvent */ , Context, 1623 TRUE); 1624 1625 Context = C_NO_CONTEXT; 1626 ButtonWindow = NULL; 1627 1628 /* if we are not executing a deferred command, then take down the 1629 * menu 1630 */ 1631 if (RootFunction == 0) { 1632 PopDownMenu(); 1633 } 1634 } 1635 else 1636 PopDownMenu(); 1637 } 1638 1639 mask = 1640 (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask); 1641 switch (Event.xbutton.button) { 1642 /* *INDENT-OFF* */ 1643 case Button1: mask &= (unsigned)(~Button1Mask); break; 1644 case Button2: mask &= (unsigned)(~Button2Mask); break; 1645 case Button3: mask &= (unsigned)(~Button3Mask); break; 1646 case Button4: mask &= (unsigned)(~Button4Mask); break; 1647 case Button5: mask &= (unsigned)(~Button5Mask); break; 1648 /* *INDENT-ON* */ 1649 } 1650 1651 if (RootFunction != 0 || ResizeWindow != None || DragWindow != None) 1652 ButtonPressed = -1; 1653 1654 if (RootFunction == 0 && 1655 (Event.xbutton.state & mask) == 0 && 1656 DragWindow == None && ResizeWindow == None) { 1657 XUngrabPointer(dpy, CurrentTime); 1658 XUngrabServer(dpy); 1659 XFlush(dpy); 1660 EventHandler[EnterNotify] = HandleEnterNotify; 1661 EventHandler[LeaveNotify] = HandleLeaveNotify; 1662 ButtonPressed = -1; 1663 if (DownIconManager) { 1664 DownIconManager->down = FALSE; 1665 if (Scr->Highlight) 1666 DrawIconManagerBorder(DownIconManager); 1667 DownIconManager = NULL; 1668 } 1669 Cancel = FALSE; 1670 } 1671} 1672 1673/** 1674 * 1675 * \param menu menu to pop up 1676 * \param w invoking window, or None 1677 */ 1678static void 1679do_menu(MenuRoot *menu, Window w) 1680{ 1681 int x = Event.xbutton.x_root; 1682 int y = Event.xbutton.y_root; 1683 Bool center; 1684 1685 if (!Scr->NoGrabServer) 1686 XGrabServer(dpy); 1687 if (w) { 1688 int h = Scr->TBInfo.width - Scr->TBInfo.border; 1689 Window child; 1690 1691 (void) XTranslateCoordinates(dpy, w, Scr->Root, 0, h, &x, &y, &child); 1692 center = False; 1693 } 1694 else { 1695 center = True; 1696 } 1697 if (PopUpMenu(menu, x, y, center)) { 1698 UpdateMenu(); 1699 } 1700 else { 1701 Bell(XkbBI_MinorError, 0, w); 1702 } 1703} 1704 1705/** 1706 * ButtonPress event handler 1707 */ 1708void 1709HandleButtonPress(void) 1710{ 1711 unsigned int modifier; 1712 Cursor cur; 1713 int dummy = 0; 1714 Window wdummy = None; 1715 1716 /* too much code relies on this assumption */ 1717 if (Event.xbutton.button > MAX_BUTTONS) 1718 return; 1719 1720 /* pop down the menu, if any */ 1721 if (ActiveMenu != NULL) 1722 PopDownMenu(); 1723 1724 XSync(dpy, 0); /* XXX - remove? */ 1725 1726 if (ButtonPressed != -1 && !InfoLines) { /* want menus if we have info box */ 1727 /* we got another butt press in addition to one still held 1728 * down, we need to cancel the operation we were doing 1729 */ 1730 Cancel = TRUE; 1731 CurrentDragX = origDragX; 1732 CurrentDragY = origDragY; 1733 if (!menuFromFrameOrWindowOrTitlebar) { 1734 if (Scr->OpaqueMove && DragWindow != None) { 1735 XMoveWindow(dpy, DragWindow, origDragX, origDragY); 1736 } 1737 else { 1738 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 1739 } 1740 } 1741 XUnmapWindow(dpy, Scr->SizeWindow); 1742 if (!Scr->OpaqueMove) 1743 UninstallRootColormap(); 1744 ResizeWindow = None; 1745 DragWindow = None; 1746 cur = LeftButt; 1747 if (Event.xbutton.button == Button2) 1748 cur = MiddleButt; 1749 else if (Event.xbutton.button >= Button3) 1750 cur = RightButt; 1751 1752 XGrabPointer(dpy, Scr->Root, True, 1753 ButtonReleaseMask | ButtonPressMask, 1754 GrabModeAsync, GrabModeAsync, Scr->Root, cur, CurrentTime); 1755 1756 return; 1757 } 1758 else 1759 ButtonPressed = (int) Event.xbutton.button; 1760 1761 if (ResizeWindow != None || DragWindow != None || ActiveMenu != NULL) 1762 return; 1763 1764 /* check the title bar buttons */ 1765 if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons) { 1766 int i; 1767 TBWindow *tbw; 1768 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1769 1770 for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) { 1771 if (Event.xany.window == tbw->window) { 1772 if (tbw->info->func == F_MENU) { 1773 Context = C_TITLE; 1774 ButtonEvent = Event; 1775 1776 ButtonWindow = Tmp_win; 1777 do_menu(tbw->info->menuroot, tbw->window); 1778 } 1779 else { 1780 ExecuteFunction(tbw->info->func, tbw->info->action, 1781 Event.xany.window, Tmp_win, &Event, 1782 C_TITLE, FALSE); 1783 } 1784 return; 1785 } 1786 } 1787 } 1788 1789 Context = C_NO_CONTEXT; 1790 1791 if (Event.xany.window == Scr->InfoWindow) 1792 Context = C_IDENTIFY; 1793 1794 if (Event.xany.window == Scr->Root) 1795 Context = C_ROOT; 1796 if (Tmp_win) { 1797 if (Tmp_win->list && RootFunction != 0 && 1798 (Event.xany.window == Tmp_win->list->w || 1799 Event.xany.window == Tmp_win->list->icon)) { 1800 int x = 0; 1801 int y = 0; 1802 1803 Tmp_win = Tmp_win->list->iconmgr->twm_win; 1804 1805 XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w, 1806 Event.xbutton.x, Event.xbutton.y, 1807 &x, &y, &wdummy); 1808 1809 Event.xbutton.x = x; 1810 Event.xbutton.y = y - Tmp_win->title_height; 1811 Event.xany.window = Tmp_win->w; 1812 1813 Context = C_WINDOW; 1814 } 1815 else if (Event.xany.window == Tmp_win->title_w) { 1816 Context = C_TITLE; 1817 } 1818 else if (Event.xany.window == Tmp_win->w) { 1819 printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n"); 1820 Context = C_WINDOW; 1821 } 1822 else if (Event.xany.window == Tmp_win->icon_w) { 1823 Context = C_ICON; 1824 } 1825 else if (Event.xany.window == Tmp_win->frame) { 1826 /* since we now place a button grab on the frame instead 1827 * of the window, (see GrabButtons() in add_window.c), we 1828 * need to figure out where the pointer exactly is before 1829 * assigning Context. If the pointer is on the application 1830 * window we will change the event structure to look as if 1831 * it came from the application window. 1832 */ 1833 if (Event.xbutton.subwindow == Tmp_win->w) { 1834 Event.xbutton.window = Tmp_win->w; 1835 Event.xbutton.y -= Tmp_win->title_height; 1836 1837/***** 1838 Event.xbutton.x -= Tmp_win->frame_bw; 1839*****/ 1840 Context = C_WINDOW; 1841 } 1842 else 1843 Context = C_FRAME; 1844 } 1845 else if (Tmp_win->list && 1846 (Event.xany.window == Tmp_win->list->w || 1847 Event.xany.window == Tmp_win->list->icon)) { 1848 Tmp_win->list->down = TRUE; 1849 if (Scr->Highlight) 1850 DrawIconManagerBorder(Tmp_win->list); 1851 DownIconManager = Tmp_win->list; 1852 Context = C_ICONMGR; 1853 } 1854 } 1855 1856 /* this section of code checks to see if we were in the middle of 1857 * a command executed from a menu 1858 */ 1859 if (RootFunction != 0) { 1860 if (Event.xany.window == Scr->Root) { 1861 /* if the window was the Root, we don't know for sure it 1862 * it was the root. We must check to see if it happened to be 1863 * inside of a client that was getting button press events. 1864 */ 1865 XPointer context_data; 1866 int x = 0; 1867 int y = 0; 1868 1869 XTranslateCoordinates(dpy, Scr->Root, Scr->Root, 1870 Event.xbutton.x, 1871 Event.xbutton.y, 1872 &dummy, &dummy, &Event.xany.window); 1873 1874 if (Event.xany.window == 0 || 1875 (XFindContext(dpy, Event.xany.window, TwmContext, 1876 &context_data) == XCNOENT)) { 1877 RootFunction = 0; 1878 Bell(XkbBI_MinorError, 0, Event.xany.window); 1879 1880 return; 1881 } 1882 else 1883 Tmp_win = (TwmWindow *) context_data; 1884 1885 XTranslateCoordinates(dpy, Scr->Root, Event.xany.window, 1886 Event.xbutton.x, 1887 Event.xbutton.y, &x, &y, &wdummy); 1888 1889 Event.xbutton.x = x; 1890 Event.xbutton.y = y; 1891 1892 Context = C_WINDOW; 1893 } 1894 1895 /* make sure we are not trying to move an identify window */ 1896 if (Event.xany.window != Scr->InfoWindow) 1897 ExecuteFunction(RootFunction, Action, Event.xany.window, 1898 Tmp_win, &Event, Context, FALSE); 1899 1900 RootFunction = 0; 1901 return; 1902 } 1903 1904 ButtonEvent = Event; 1905 1906 ButtonWindow = Tmp_win; 1907 1908 /* if we get to here, we have to execute a function or pop up a 1909 * menu 1910 */ 1911 modifier = (Event.xbutton.state & mods_used); 1912 1913 if (Context == C_NO_CONTEXT) 1914 return; 1915 1916 RootFunction = 0; 1917 if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU) { 1918 do_menu(Scr->Mouse[Event.xbutton.button][Context][modifier].menu, 1919 (Window) None); 1920 } 1921 else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != 0) { 1922 Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ? 1923 Scr->Mouse[Event.xbutton.button][Context][modifier]. 1924 item->action : NULL; 1925 ExecuteFunction(Scr-> 1926 Mouse[Event.xbutton.button][Context][modifier].func, 1927 Action, Event.xany.window, Tmp_win, &Event, Context, 1928 FALSE); 1929 } 1930 else if (Scr->DefaultFunction.func != 0) { 1931 if (Scr->DefaultFunction.func == F_MENU) { 1932 do_menu(Scr->DefaultFunction.menu, (Window) None); 1933 } 1934 else { 1935 Action = Scr->DefaultFunction.item ? 1936 Scr->DefaultFunction.item->action : NULL; 1937 ExecuteFunction(Scr->DefaultFunction.func, Action, 1938 Event.xany.window, Tmp_win, &Event, Context, FALSE); 1939 } 1940 } 1941} 1942 1943/** \fn HENQueueScanner 1944 * EnterNotify event q scanner. 1945 * 1946 * Looks at the queued events and determines if any matching 1947 * LeaveNotify events or EnterEvents deriving from the 1948 * termination of a grab are behind this event to allow 1949 * skipping of unnecessary processing. 1950 */ 1951typedef struct HENScanArgs { 1952 Window w; /**< Window we are currently entering */ 1953 Bool leaves; /**< Any LeaveNotifies found for this window */ 1954 Bool inferior; /**< Was NotifyInferior the mode for LeaveNotify */ 1955 Bool enters; /**< Any EnterNotify events with NotifyUngrab */ 1956} HENScanArgs; 1957 1958static Bool 1959HENQueueScanner(Display *dpy2 _X_UNUSED, XEvent *ev, char *args) 1960{ 1961 if (ev->type == LeaveNotify) { 1962 if (ev->xcrossing.window == ((HENScanArgs *) args)->w && 1963 ev->xcrossing.mode == NotifyNormal) { 1964 ((HENScanArgs *) args)->leaves = True; 1965 /* 1966 * Only the last event found matters for the Inferior field. 1967 */ 1968 ((HENScanArgs *) args)->inferior = 1969 (ev->xcrossing.detail == NotifyInferior); 1970 } 1971 } 1972 else if (ev->type == EnterNotify) { 1973 if (ev->xcrossing.mode == NotifyUngrab) 1974 ((HENScanArgs *) args)->enters = True; 1975 } 1976 1977 return (False); 1978} 1979 1980/** 1981 * EnterNotify event handler 1982 */ 1983void 1984HandleEnterNotify(void) 1985{ 1986 MenuRoot *mr; 1987 XEnterWindowEvent *ewp = &Event.xcrossing; 1988 HENScanArgs scanArgs; 1989 XEvent dummy; 1990 XPointer context_data; 1991 1992 /* 1993 * Save the id of the window entered. This will be used to remove 1994 * border highlight on entering the next application window. 1995 */ 1996 if (UnHighLight_win && ewp->window != UnHighLight_win->w) { 1997 SetBorder(UnHighLight_win, False); /* application window */ 1998 if (UnHighLight_win->list) /* in the icon box */ 1999 NotActiveIconManager(UnHighLight_win->list); 2000 } 2001 if (ewp->window == Scr->Root) 2002 UnHighLight_win = NULL; 2003 else if (Tmp_win) 2004 UnHighLight_win = Tmp_win; 2005 2006 /* 2007 * if we aren't in the middle of menu processing 2008 */ 2009 if (!ActiveMenu) { 2010 /* 2011 * We're not interested in pseudo Enter/Leave events generated 2012 * from grab initiations. 2013 */ 2014 if (ewp->mode == NotifyGrab) 2015 return; 2016 2017 /* 2018 * Scan for Leave and Enter Notify events to see if we can avoid some 2019 * unnecessary processing. 2020 */ 2021 scanArgs.w = ewp->window; 2022 scanArgs.leaves = scanArgs.enters = False; 2023 (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs); 2024 2025 /* 2026 * if entering root window, restore twm default colormap so that 2027 * titlebars are legible 2028 */ 2029 if (ewp->window == Scr->Root) { 2030 if (!scanArgs.leaves && !scanArgs.enters) 2031 InstallWindowColormaps(EnterNotify, &Scr->TwmRoot); 2032 return; 2033 } 2034 2035 /* 2036 * if we have an event for a specific one of our windows 2037 */ 2038 if (Tmp_win) { 2039 /* 2040 * If currently in PointerRoot mode (indicated by FocusRoot), then 2041 * focus on this window 2042 */ 2043 if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) { 2044 if (Tmp_win->list) 2045 ActiveIconManager(Tmp_win->list); 2046 if (Tmp_win->mapped) { 2047 /* 2048 * unhighlight old focus window 2049 */ 2050 if (Scr->Focus && 2051 Scr->Focus != Tmp_win && Tmp_win->hilite_w) 2052 XUnmapWindow(dpy, Scr->Focus->hilite_w); 2053 2054 /* 2055 * If entering the frame or the icon manager, then do 2056 * "window activation things": 2057 * 2058 * 1. turn on highlight window (if any) 2059 * 2. install frame colormap 2060 * 3. set frame and highlight window (if any) border 2061 * 4. focus on client window to forward typing 2062 * 4a. same as 4 but for icon mgr w/with NoTitlebar on. 2063 * 5. send WM_TAKE_FOCUS if requested 2064 */ 2065 if (ewp->window == Tmp_win->frame || 2066 (Tmp_win->list && ewp->window == Tmp_win->list->w)) { 2067 if (Tmp_win->hilite_w) /* 1 */ 2068 XMapWindow(dpy, Tmp_win->hilite_w); 2069 if (!scanArgs.leaves && !scanArgs.enters) 2070 InstallWindowColormaps(EnterNotify, /* 2 */ 2071 &Scr->TwmRoot); 2072 SetBorder(Tmp_win, True); /* 3 */ 2073 if (Tmp_win->title_w && Scr->TitleFocus && /* 4 */ 2074 Tmp_win->wmhints && Tmp_win->wmhints->input) 2075 SetFocus(Tmp_win, ewp->time); 2076 if (Scr->NoTitlebar && Scr->TitleFocus && /*4a */ 2077 Tmp_win->wmhints && Tmp_win->wmhints->input) 2078 SetFocus(Tmp_win, ewp->time); 2079 if (Tmp_win->protocols & DoesWmTakeFocus) /* 5 */ 2080 SendTakeFocusMessage(Tmp_win, ewp->time); 2081 Scr->Focus = Tmp_win; 2082 } 2083 else if (ewp->window == Tmp_win->w) { 2084 /* 2085 * If we are entering the application window, install 2086 * its colormap(s). 2087 */ 2088 if (!scanArgs.leaves || scanArgs.inferior) 2089 InstallWindowColormaps(EnterNotify, Tmp_win); 2090 } 2091 } /* end if Tmp_win->mapped */ 2092 if (Tmp_win->wmhints != NULL && 2093 ewp->window == Tmp_win->wmhints->icon_window && 2094 (!scanArgs.leaves || scanArgs.inferior)) 2095 InstallWindowColormaps(EnterNotify, Tmp_win); 2096 } /* end if FocusRoot */ 2097 /* 2098 * If this window is to be autoraised, mark it so 2099 */ 2100 if (Tmp_win->auto_raise) { 2101 enter_win = Tmp_win; 2102 if (enter_flag == FALSE) 2103 AutoRaiseWindow(Tmp_win); 2104 } 2105 else if (enter_flag && raise_win == Tmp_win) 2106 enter_win = Tmp_win; 2107 /* 2108 * set ring leader 2109 */ 2110 if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win)) 2111 Scr->RingLeader = Tmp_win; 2112 XSync(dpy, 0); 2113 return; 2114 } /* end if Tmp_win */ 2115 } /* end if !ActiveMenu */ 2116 2117 /* 2118 * Find the menu that we are dealing with now; punt if unknown 2119 */ 2120 if (XFindContext(dpy, ewp->window, MenuContext, &context_data) == 0) 2121 mr = (MenuRoot *) context_data; 2122 else 2123 return; 2124 2125 mr->entered = TRUE; 2126 if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == 0) { 2127 if (Scr->Shadow) 2128 XUnmapWindow(dpy, ActiveMenu->shadow); 2129 XUnmapWindow(dpy, ActiveMenu->w); 2130 ActiveMenu->mapped = UNMAPPED; 2131 UninstallRootColormap(); 2132 if (ActiveItem) { 2133 ActiveItem->state = 0; 2134 PaintEntry(ActiveMenu, ActiveItem, False); 2135 } 2136 ActiveItem = NULL; 2137 ActiveMenu = mr; 2138 MenuDepth--; 2139 } 2140 return; 2141} 2142 2143/** \fn HLNQueueScanner 2144 * LeaveNotify event q scanner. 2145 * 2146 * Looks at the queued events and determines if any 2147 * EnterNotify events are behind this event to allow 2148 * skipping of unnecessary processing. 2149 */ 2150 2151typedef struct HLNScanArgs { 2152 Window w; /**< The window getting the LeaveNotify */ 2153 Bool enters; /**< Any EnterNotify event at all */ 2154 Bool matches; /**< Any matching EnterNotify events */ 2155} HLNScanArgs; 2156 2157static Bool 2158HLNQueueScanner(Display *dpy2 _X_UNUSED, XEvent *ev, char *args) 2159{ 2160 if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) { 2161 ((HLNScanArgs *) args)->enters = True; 2162 if (ev->xcrossing.window == ((HLNScanArgs *) args)->w) 2163 ((HLNScanArgs *) args)->matches = True; 2164 } 2165 2166 return (False); 2167} 2168 2169/** 2170 * LeaveNotify event handler 2171 */ 2172void 2173HandleLeaveNotify(void) 2174{ 2175 HLNScanArgs scanArgs; 2176 XEvent dummy; 2177 2178 if (Tmp_win != NULL) { 2179 Bool inicon; 2180 2181 /* 2182 * We're not interested in pseudo Enter/Leave events generated 2183 * from grab initiations and terminations. 2184 */ 2185 if (Event.xcrossing.mode != NotifyNormal) 2186 return; 2187 2188 inicon = (Tmp_win->list && Tmp_win->list->w == Event.xcrossing.window); 2189 2190 if (Scr->RingLeader && Scr->RingLeader == Tmp_win && 2191 (Event.xcrossing.detail != NotifyInferior && 2192 Event.xcrossing.window != Tmp_win->w)) { 2193 if (!inicon) { 2194 if (Tmp_win->mapped) { 2195 Tmp_win->ring.cursor_valid = False; 2196 } 2197 else { 2198 Tmp_win->ring.cursor_valid = True; 2199 Tmp_win->ring.curs_x = (Event.xcrossing.x_root - 2200 Tmp_win->frame_x); 2201 Tmp_win->ring.curs_y = (Event.xcrossing.y_root - 2202 Tmp_win->frame_y); 2203 } 2204 } 2205 Scr->RingLeader = (TwmWindow *) NULL; 2206 } 2207 if (Scr->FocusRoot) { 2208 2209 if (Event.xcrossing.detail != NotifyInferior && 2210 Event.xcrossing.detail != NotifyVirtual && 2211 Event.xcrossing.detail != NotifyNonlinearVirtual) { 2212 2213 /* 2214 * Scan for EnterNotify events to see if we can avoid some 2215 * unnecessary processing. 2216 */ 2217 scanArgs.w = Event.xcrossing.window; 2218 2219 scanArgs.enters = scanArgs.matches = False; 2220 (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner, 2221 (char *) &scanArgs); 2222 2223 if ((Event.xcrossing.window == Tmp_win->frame && 2224 !scanArgs.matches) ||inicon) { 2225 if (Tmp_win->list) 2226 NotActiveIconManager(Tmp_win->list); 2227 if (Tmp_win->hilite_w) 2228 XUnmapWindow(dpy, Tmp_win->hilite_w); 2229 SetBorder(Tmp_win, False); 2230 if (Scr->TitleFocus || Tmp_win->protocols & DoesWmTakeFocus) 2231 SetFocus((TwmWindow *) NULL, Event.xcrossing.time); 2232 2233 Scr->Focus = NULL; 2234 } 2235 else if (Event.xcrossing.window == Tmp_win->w && 2236 !scanArgs.enters) { 2237 InstallWindowColormaps(LeaveNotify, &Scr->TwmRoot); 2238 } 2239 } 2240 } 2241 XSync(dpy, 0); 2242 return; 2243 } 2244} 2245 2246/** 2247 * HandleConfigureRequest - ConfigureRequest event handler 2248 */ 2249void 2250HandleConfigureRequest(void) 2251{ 2252 XWindowChanges xwc; 2253 int x, y, width, height, bw; 2254 int gravx, gravy; 2255 XConfigureRequestEvent *cre = &Event.xconfigurerequest; 2256 XPointer context_data; 2257 2258#ifdef DEBUG_EVENTS 2259 fprintf(stderr, "ConfigureRequest\n"); 2260 if (cre->value_mask & CWX) 2261 fprintf(stderr, " x = %d\n", cre->x); 2262 if (cre->value_mask & CWY) 2263 fprintf(stderr, " y = %d\n", cre->y); 2264 if (cre->value_mask & CWWidth) 2265 fprintf(stderr, " width = %d\n", cre->width); 2266 if (cre->value_mask & CWHeight) 2267 fprintf(stderr, " height = %d\n", cre->height); 2268 if (cre->value_mask & CWSibling) 2269 fprintf(stderr, " above = 0x%x\n", cre->above); 2270 if (cre->value_mask & CWStackMode) 2271 fprintf(stderr, " stack = %d\n", cre->detail); 2272#endif 2273 2274 /* 2275 * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will 2276 * be wrong 2277 */ 2278 Event.xany.window = cre->window; /* mash parent field */ 2279 2280 if (XFindContext(dpy, cre->window, TwmContext, &context_data) == 0) 2281 Tmp_win = (TwmWindow *) context_data; 2282 else 2283 Tmp_win = NULL; 2284 2285 /* 2286 * According to the July 27, 1988 ICCCM draft, we should ignore size and 2287 * position fields in the WM_NORMAL_HINTS property when we map a window. 2288 * Instead, we'll read the current geometry. Therefore, we should respond 2289 * to configuration requests for windows which have never been mapped. 2290 */ 2291 if (!Tmp_win || Tmp_win->icon_w == cre->window) { 2292 unsigned long xwcm; 2293 2294 xwcm = cre->value_mask & 2295 (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); 2296 xwc.x = cre->x; 2297 xwc.y = cre->y; 2298 xwc.width = cre->width; 2299 xwc.height = cre->height; 2300 xwc.border_width = cre->border_width; 2301 XConfigureWindow(dpy, Event.xany.window, (unsigned) xwcm, &xwc); 2302 2303 return; 2304 } 2305 2306 if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) { 2307 TwmWindow *otherwin = NULL; 2308 2309 if (cre->value_mask & CWSibling) { 2310 if (XFindContext(dpy, cre->above, TwmContext, &context_data) == 0) 2311 otherwin = (TwmWindow *) context_data; 2312 } 2313 2314 xwc.sibling = (otherwin != NULL) ? otherwin->frame : cre->above; 2315 xwc.stack_mode = cre->detail; 2316 XConfigureWindow(dpy, Tmp_win->frame, 2317 cre->value_mask & (CWSibling | CWStackMode), &xwc); 2318 } 2319 2320 /* Don't modify frame_XXX fields before calling SetupWindow! */ 2321 x = Tmp_win->frame_x; 2322 y = Tmp_win->frame_y; 2323 width = Tmp_win->frame_width; 2324 height = Tmp_win->frame_height; 2325 bw = Tmp_win->frame_bw; 2326 2327 /* 2328 * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the 2329 * configure request are for the upper-left outer corner of the window. 2330 * This means that we need to adjust for the additional title height as 2331 * well as for any border width changes that we decide to allow. The 2332 * current window gravity is to be used in computing the adjustments, just 2333 * as when initially locating the window. Note that if we do decide to 2334 * allow border width changes, we will need to send the synthetic 2335 * ConfigureNotify event. 2336 */ 2337 GetGravityOffsets(Tmp_win, &gravx, &gravy); 2338 2339 if (cre->value_mask & CWBorderWidth) { 2340 int bwdelta = cre->border_width - Tmp_win->old_bw; /* posit growth */ 2341 2342 if (bwdelta && Scr->ClientBorderWidth) { /* if change allowed */ 2343 x += gravx * bwdelta; /* change default values only */ 2344 y += gravy * bwdelta; /* ditto */ 2345 bw = cre->border_width; 2346 if (Tmp_win->title_height) 2347 height += bwdelta; 2348 x += (gravx < 0) ? bwdelta : -bwdelta; 2349 y += (gravy < 0) ? bwdelta : -bwdelta; 2350 } 2351 Tmp_win->old_bw = cre->border_width; /* for restoring */ 2352 } 2353 2354 if (cre->value_mask & CWX) { /* override even if border change */ 2355 x = cre->x - bw; 2356 } 2357 if (cre->value_mask & CWY) { 2358 y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw; 2359 } 2360 2361 if (cre->value_mask & CWWidth) { 2362 width = cre->width; 2363 } 2364 if (cre->value_mask & CWHeight) { 2365 height = cre->height + Tmp_win->title_height; 2366 } 2367 2368 if (width != Tmp_win->frame_width || height != Tmp_win->frame_height) 2369 Tmp_win->zoomed = ZOOM_NONE; 2370 2371 /* 2372 * SetupWindow (x,y) are the location of the upper-left outer corner and 2373 * are passed directly to XMoveResizeWindow (frame). The (width,height) 2374 * are the inner size of the frame. The inner width is the same as the 2375 * requested client window width; the inner height is the same as the 2376 * requested client window height plus any title bar slop. 2377 */ 2378 SetupWindow(Tmp_win, x, y, width, height, bw); 2379} 2380 2381/** 2382 * shape notification event handler 2383 */ 2384void 2385HandleShapeNotify(void) 2386{ 2387 XShapeEvent *sev = (XShapeEvent *) & Event; 2388 2389 if (Tmp_win == NULL) 2390 return; 2391 if (sev->kind != ShapeBounding) 2392 return; 2393 if (!Tmp_win->wShaped && sev->shaped) { 2394 XShapeCombineMask(dpy, Tmp_win->frame, ShapeClip, 0, 0, None, ShapeSet); 2395 } 2396 Tmp_win->wShaped = (short) sev->shaped; 2397 SetFrameShape(Tmp_win); 2398} 2399 2400#ifdef HAVE_XRANDR 2401/** 2402 * xrandr screen configuration change-notification handler 2403 */ 2404void 2405HandleScreenChangeNotify(void) 2406{ 2407 XRRScreenChangeNotifyEvent *xev = (XRRScreenChangeNotifyEvent *) & Event; 2408 int scrnum; 2409 2410 for (scrnum = 0; scrnum < NumScreens; scrnum++) { 2411 if (ScreenList[scrnum]->Root == xev->root) { 2412 ScreenList[scrnum]->MyDisplayWidth = xev->width; 2413 ScreenList[scrnum]->MyDisplayHeight = xev->height; 2414 } 2415 } 2416 2417 XRRUpdateConfiguration(&Event); 2418} 2419#endif 2420 2421/** 2422 * unknown event handler 2423 */ 2424void 2425HandleUnknown(void) 2426{ 2427#ifdef DEBUG_EVENTS 2428 fprintf(stderr, "type = %d\n", Event.type); 2429#endif 2430} 2431 2432/** 2433 * checks to see if the window is a transient. 2434 * 2435 * \return TRUE if window is a transient 2436 * \return FALSE if window is not a transient 2437 * 2438 * \param w the window to check 2439 */ 2440int 2441Transient(Window w, Window *propw) 2442{ 2443 return (XGetTransientForHint(dpy, w, propw)); 2444} 2445 2446/** 2447 * get ScreenInfo struct associated with a given window 2448 * 2449 * \return ScreenInfo struct 2450 * \param w the window 2451 */ 2452ScreenInfo * 2453FindScreenInfo(Window w) 2454{ 2455 XWindowAttributes attr; 2456 2457 attr.screen = NULL; 2458 2459 if (XGetWindowAttributes(dpy, w, &attr)) { 2460 int scrnum; 2461 2462 for (scrnum = 0; scrnum < NumScreens; scrnum++) { 2463 if (ScreenList[scrnum] != NULL && 2464 (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) == 2465 attr.screen)) 2466 return ScreenList[scrnum]; 2467 } 2468 } 2469 2470 return NULL; 2471} 2472 2473static void 2474flush_expose(Window w) 2475{ 2476 XEvent dummy; 2477 2478 /* SUPPRESS 530 */ 2479 while (XCheckTypedWindowEvent(dpy, w, Expose, &dummy)); 2480} 2481 2482/** 2483 * install the colormaps for one twm window. 2484 * 2485 * \param type type of event that caused the installation 2486 * \param tmp for a subset of event types, the address of the 2487 * window structure, whose colormaps are to be installed. 2488 */ 2489void 2490InstallWindowColormaps(int type, TwmWindow *tmp) 2491{ 2492 int i, j, n, number_cwins, state; 2493 ColormapWindow **cwins, *cwin, **maxcwin = NULL; 2494 TwmColormap *cmap; 2495 char *row, *scoreboard; 2496 2497 switch (type) { 2498 case EnterNotify: 2499 case LeaveNotify: 2500 case DestroyNotify: 2501 default: 2502 /* Save the colormap to be loaded for when force loading of 2503 * root colormap(s) ends. 2504 */ 2505 Scr->cmapInfo.pushed_window = tmp; 2506 /* Don't load any new colormap if root colormap(s) has been 2507 * force loaded. 2508 */ 2509 if (Scr->cmapInfo.root_pushes) 2510 return; 2511 /* Don't reload the currend window colormap list. 2512 */ 2513 if (Scr->cmapInfo.cmaps == &tmp->cmaps) 2514 return; 2515 if (Scr->cmapInfo.cmaps) 2516 for (i = Scr->cmapInfo.cmaps->number_cwins, 2517 cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++) 2518 (*cwins)->colormap->state &= ~CM_INSTALLABLE; 2519 Scr->cmapInfo.cmaps = &tmp->cmaps; 2520 break; 2521 2522 case PropertyNotify: 2523 case VisibilityNotify: 2524 case ColormapNotify: 2525 break; 2526 } 2527 2528 number_cwins = Scr->cmapInfo.cmaps->number_cwins; 2529 cwins = Scr->cmapInfo.cmaps->cwins; 2530 scoreboard = Scr->cmapInfo.cmaps->scoreboard; 2531 2532 ColortableThrashing = FALSE; /* in case installation aborted */ 2533 2534 state = CM_INSTALLED; 2535 2536 for (i = 0; i < number_cwins; i++) { 2537 cwin = cwins[i]; 2538 cmap = cwin->colormap; 2539 cmap->state |= CM_INSTALLABLE; 2540 cmap->state &= ~CM_INSTALL; 2541 cmap->w = cwin->w; 2542 } 2543 for (i = n = 0; i < number_cwins; i++) { 2544 cwin = cwins[i]; 2545 cmap = cwin->colormap; 2546 if (cwin->visibility != VisibilityFullyObscured && 2547 n < Scr->cmapInfo.maxCmaps) { 2548 row = scoreboard + (i * (i - 1) / 2); 2549 for (j = 0; j < i; j++) 2550 if (row[j] && (cwins[j]->colormap->state & CM_INSTALL)) 2551 break; 2552 if (j != i) 2553 continue; 2554 n++; 2555 maxcwin = &cwins[i]; 2556 state &= (cmap->state & CM_INSTALLED); 2557 cmap->state |= CM_INSTALL; 2558 } 2559 } 2560 2561 Scr->cmapInfo.first_req = NextRequest(dpy); 2562 2563 for (; n > 0 && maxcwin >= cwins; maxcwin--) { 2564 cmap = (*maxcwin)->colormap; 2565 if (cmap->state & CM_INSTALL) { 2566 cmap->state &= ~CM_INSTALL; 2567 if (!(state & CM_INSTALLED)) { 2568 cmap->install_req = NextRequest(dpy); 2569 XInstallColormap(dpy, cmap->c); 2570 } 2571 cmap->state |= CM_INSTALLED; 2572 n--; 2573 } 2574 } 2575} 2576 2577/** \fn InstallRootColormap 2578 * \fn UninstallRootColormap 2579 * 2580 * Force (un)loads root colormap(s) 2581 * 2582 * These matching routines provide a mechanism to insure that 2583 * the root colormap(s) is installed during operations like 2584 * rubber banding or menu display that require colors from 2585 * that colormap. Calls may be nested arbitrarily deeply, 2586 * as long as there is one UninstallRootColormap call per 2587 * InstallRootColormap call. 2588 * 2589 * The final UninstallRootColormap will cause the colormap list 2590 * which would otherwise have be loaded to be loaded, unless 2591 * Enter or Leave Notify events are queued, indicating some 2592 * other colormap list would potentially be loaded anyway. 2593 */ 2594void 2595InstallRootColormap(void) 2596{ 2597 TwmWindow *tmp; 2598 2599 if (Scr->cmapInfo.root_pushes == 0) { 2600 /* 2601 * The saving and restoring of cmapInfo.pushed_window here 2602 * is a slimy way to remember the actual pushed list and 2603 * not that of the root window. 2604 */ 2605 tmp = Scr->cmapInfo.pushed_window; 2606 InstallWindowColormaps(0, &Scr->TwmRoot); 2607 Scr->cmapInfo.pushed_window = tmp; 2608 } 2609 Scr->cmapInfo.root_pushes++; 2610} 2611 2612static Bool 2613UninstallRootColormapQScanner(Display *dpy2 _X_UNUSED, XEvent *ev, char *args) 2614{ 2615 if (!*args) { 2616 if (ev->type == EnterNotify) { 2617 if (ev->xcrossing.mode != NotifyGrab) 2618 *args = 1; 2619 } 2620 else if (ev->type == LeaveNotify) { 2621 if (ev->xcrossing.mode == NotifyNormal) 2622 2623 *args = 1; 2624 } 2625 } 2626 return (False); 2627} 2628 2629void 2630UninstallRootColormap(void) 2631{ 2632 char args; 2633 XEvent dummy; 2634 2635 if (Scr->cmapInfo.root_pushes) 2636 Scr->cmapInfo.root_pushes--; 2637 2638 if (!Scr->cmapInfo.root_pushes) { 2639 /* 2640 * If we have subsequent Enter or Leave Notify events, 2641 * we can skip the reload of pushed colormaps. 2642 */ 2643 XSync(dpy, 0); 2644 args = 0; 2645 (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args); 2646 2647 if (!args) 2648 InstallWindowColormaps(0, Scr->cmapInfo.pushed_window); 2649 } 2650} 2651 2652#ifdef TRACE 2653void 2654dumpevent(XEvent *e) 2655{ 2656 char *name = NULL; 2657 2658 switch (e->type) { 2659 /* *INDENT-OFF* */ 2660 case KeyPress: name = "KeyPress"; break; 2661 case KeyRelease: name = "KeyRelease"; break; 2662 case ButtonPress: name = "ButtonPress"; break; 2663 case ButtonRelease: name = "ButtonRelease"; break; 2664 case MotionNotify: name = "MotionNotify"; break; 2665 case EnterNotify: name = "EnterNotify"; break; 2666 case LeaveNotify: name = "LeaveNotify"; break; 2667 case FocusIn: name = "FocusIn"; break; 2668 case FocusOut: name = "FocusOut"; break; 2669 case KeymapNotify: name = "KeymapNotify"; break; 2670 case Expose: name = "Expose"; break; 2671 case GraphicsExpose: name = "GraphicsExpose"; break; 2672 case NoExpose: name = "NoExpose"; break; 2673 case VisibilityNotify: name = "VisibilityNotify"; break; 2674 case CreateNotify: name = "CreateNotify"; break; 2675 case DestroyNotify: name = "DestroyNotify"; break; 2676 case UnmapNotify: name = "UnmapNotify"; break; 2677 case MapNotify: name = "MapNotify"; break; 2678 case MapRequest: name = "MapRequest"; break; 2679 case ReparentNotify: name = "ReparentNotify"; break; 2680 case ConfigureNotify: name = "ConfigureNotify"; break; 2681 case ConfigureRequest: name = "ConfigureRequest"; break; 2682 case GravityNotify: name = "GravityNotify"; break; 2683 case ResizeRequest: name = "ResizeRequest"; break; 2684 case CirculateNotify: name = "CirculateNotify"; break; 2685 case CirculateRequest: name = "CirculateRequest"; break; 2686 case PropertyNotify: name = "PropertyNotify"; break; 2687 case SelectionClear: name = "SelectionClear"; break; 2688 case SelectionRequest: name = "SelectionRequest"; break; 2689 case SelectionNotify: name = "SelectionNotify"; break; 2690 case ColormapNotify: name = "ColormapNotify"; break; 2691 case ClientMessage: name = "ClientMessage"; break; 2692 case MappingNotify: name = "MappingNotify"; break; 2693 /* *INDENT-ON* */ 2694 } 2695 2696 if (name) { 2697 printf("event: %s, %d remaining\n", name, QLength(dpy)); 2698 } 2699 else { 2700 printf("unknown event %d, %d remaining\n", e->type, QLength(dpy)); 2701 } 2702} 2703#endif /* TRACE */ 2704