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