chiark / gitweb /
debian/changelog: start -4~
[vtwm.git] / events.c
1 /*****************************************************************************/
2 /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
3 /**                          Salt Lake City, Utah                           **/
4 /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
5 /**                        Cambridge, Massachusetts                         **/
6 /**                                                                         **/
7 /**                           All Rights Reserved                           **/
8 /**                                                                         **/
9 /**    Permission to use, copy, modify, and distribute this software and    **/
10 /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
11 /**    granted, provided that the above copyright notice appear  in  all    **/
12 /**    copies and that both  that  copyright  notice  and  this  permis-    **/
13 /**    sion  notice appear in supporting  documentation,  and  that  the    **/
14 /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
15 /**    in publicity pertaining to distribution of the  software  without    **/
16 /**    specific, written prior permission.                                  **/
17 /**                                                                         **/
18 /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
19 /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
20 /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
21 /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
22 /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
23 /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
24 /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
25 /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
26 /*****************************************************************************/
27
28
29 /***********************************************************************
30  *
31  * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $
32  *
33  * twm event handling
34  *
35  * 17-Nov-87 Thomas E. LaStrange                File created
36  *
37  ***********************************************************************/
38
39 #include <stdio.h>
40 #include <string.h>
41 #include "twm.h"
42 #include <X11/Xatom.h>
43 #include "add_window.h"
44 #include "menus.h"
45 #include "events.h"
46 #include "resize.h"
47 #include "parse.h"
48 #include "gram.h"
49 #include "util.h"
50 #include "screen.h"
51 #include "iconmgr.h"
52 #include "version.h"
53 #include "desktop.h"
54 /* djhjr - 6/22/01 */
55 #ifndef NO_SOUND_SUPPORT
56 #include "sound.h"
57 #endif
58 /* Submitted by Takeharu Kato */
59 #ifdef NEED_SELECT_H
60 #include <sys/select.h> /* RAISEDELAY */
61 #else
62 #include <sys/time.h>   /* RAISEDELAY */
63 #include <sys/types.h>  /* RAISEDELAY */
64 #include <unistd.h>
65 #endif
66
67 extern void IconDown();
68 /* djhjr - 4/26/99 */
69 extern void AppletDown();
70
71 static void do_menu ();
72 void RedoIconName();
73
74 extern int iconifybox_width, iconifybox_height;
75 extern unsigned int mods_used;
76 extern int menuFromFrameOrWindowOrTitlebar;
77 /* djhjr - 6/22/01 */
78 #ifndef NO_SOUND_SUPPORT
79 extern int createSoundFromFunction;
80 extern int destroySoundFromFunction;
81 #endif
82
83 #define MAX_X_EVENT 256
84 event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */
85 char *Action;
86 int Context = C_NO_CONTEXT;     /* current button press context */
87 TwmWindow *ButtonWindow;        /* button press window structure */
88 XEvent ButtonEvent;             /* button press event */
89 XEvent Event;                   /* the current event */
90 TwmWindow *Tmp_win;             /* the current twm window */
91
92 /* Used in HandleEnterNotify to remove border highlight from a window
93  * that has not recieved a LeaveNotify event because of a pointer grab
94  */
95 TwmWindow *UnHighLight_win = NULL;
96
97 Window DragWindow;              /* variables used in moving windows */
98 int origDragX;
99 int origDragY;
100 int DragX;
101 int DragY;
102 int DragWidth;
103 int DragHeight;
104 int CurrentDragX;
105 int CurrentDragY;
106
107 /* Vars to tell if the resize has moved. */
108 extern int ResizeOrigX;
109 extern int ResizeOrigY;
110
111 static int enter_flag;
112 static int ColortableThrashing;
113 static TwmWindow *enter_win, *raise_win;
114
115 ScreenInfo *FindScreenInfo();
116 int ButtonPressed = -1;
117 int Cancel = FALSE;
118 int GlobalFirstTime = True;
119 int GlobalMenuButton = False;
120
121 void HandleCreateNotify();
122
123 void HandleShapeNotify ();
124 extern int ShapeEventBase, ShapeErrorBase;
125
126 void AutoRaiseWindow (tmp)
127         TwmWindow *tmp;
128 {
129         XRaiseWindow (dpy, tmp->frame);
130         XRaiseWindow (dpy, tmp->VirtualDesktopDisplayWindow);
131
132         RaiseStickyAbove(); /* DSE */
133         RaiseAutoPan();
134         
135         XSync (dpy, 0);
136         enter_win = NULL;
137         enter_flag = TRUE;
138         raise_win = tmp;
139 }
140
141 void SetRaiseWindow (tmp)
142         TwmWindow *tmp;
143 {
144         enter_flag = TRUE;
145         enter_win = NULL;
146         raise_win = tmp;
147         XSync (dpy, 0);
148 }
149
150 \f
151
152 /***********************************************************************
153  *
154  *  Procedure:
155  *      InitEvents - initialize the event jump table
156  *
157  ***********************************************************************
158  */
159
160 void
161 InitEvents()
162 {
163         int i;
164
165
166         ResizeWindow = 0;
167         DragWindow = 0;
168         enter_flag = FALSE;
169         enter_win = raise_win = NULL;
170
171         for (i = 0; i < MAX_X_EVENT; i++)
172         EventHandler[i] = HandleUnknown;
173
174         EventHandler[Expose] = HandleExpose;
175         EventHandler[CreateNotify] = HandleCreateNotify;
176         EventHandler[DestroyNotify] = HandleDestroyNotify;
177         EventHandler[MapRequest] = HandleMapRequest;
178         EventHandler[MapNotify] = HandleMapNotify;
179         EventHandler[UnmapNotify] = HandleUnmapNotify;
180 #if 0 /* functionality moved to menus.c:ExecuteFunction() - djhjr - 11/7/03 */
181         EventHandler[MotionNotify] = HandleMotionNotify;
182 #endif
183         EventHandler[ButtonRelease] = HandleButtonRelease;
184         EventHandler[ButtonPress] = HandleButtonPress;
185         EventHandler[EnterNotify] = HandleEnterNotify;
186         EventHandler[LeaveNotify] = HandleLeaveNotify;
187         EventHandler[ConfigureRequest] = HandleConfigureRequest;
188         EventHandler[ClientMessage] = HandleClientMessage;
189         EventHandler[PropertyNotify] = HandlePropertyNotify;
190         EventHandler[KeyPress] = HandleKeyPress;
191         EventHandler[ColormapNotify] = HandleColormapNotify;
192         EventHandler[VisibilityNotify] = HandleVisibilityNotify;
193         if (HasShape)
194         EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
195 }
196
197
198 \f
199
200 Time lastTimestamp = CurrentTime;       /* until Xlib does this for us */
201
202 Bool StashEventTime (ev)
203         register XEvent *ev;
204 {
205         switch (ev->type) {
206           case KeyPress:
207           case KeyRelease:
208         lastTimestamp = ev->xkey.time;
209         return True;
210           case ButtonPress:
211           case ButtonRelease:
212         lastTimestamp = ev->xbutton.time;
213         return True;
214           case MotionNotify:
215         lastTimestamp = ev->xmotion.time;
216         return True;
217           case EnterNotify:
218           case LeaveNotify:
219         lastTimestamp = ev->xcrossing.time;
220         return True;
221           case PropertyNotify:
222         lastTimestamp = ev->xproperty.time;
223         return True;
224           case SelectionClear:
225         lastTimestamp = ev->xselectionclear.time;
226         return True;
227           case SelectionRequest:
228         lastTimestamp = ev->xselectionrequest.time;
229         return True;
230           case SelectionNotify:
231         lastTimestamp = ev->xselection.time;
232         return True;
233         }
234         return False;
235 }
236
237 \f
238
239 /*
240  * WindowOfEvent - return the window about which this event is concerned; this
241  * window may not be the same as XEvent.xany.window (the first window listed
242  * in the structure).
243  */
244 Window WindowOfEvent (e)
245         XEvent *e;
246 {
247         /*
248          * Each window subfield is marked with whether or not it is the same as
249          * XEvent.xany.window or is different (which is the case for some of the
250          * notify events).
251          */
252         switch (e->type) {
253           case KeyPress:
254           case KeyRelease:  return e->xkey.window;                           /* same */
255           case ButtonPress:
256           case ButtonRelease:  return e->xbutton.window;                     /* same */
257           case MotionNotify:  return e->xmotion.window;              /* same */
258           case EnterNotify:
259           case LeaveNotify:  return e->xcrossing.window;                     /* same */
260           case FocusIn:
261           case FocusOut:  return e->xfocus.window;                           /* same */
262           case KeymapNotify:  return e->xkeymap.window;              /* same */
263           case Expose:  return e->xexpose.window;                            /* same */
264           case GraphicsExpose:  return e->xgraphicsexpose.drawable;          /* same */
265           case NoExpose:  return e->xnoexpose.drawable;              /* same */
266           case VisibilityNotify:  return e->xvisibility.window;      /* same */
267           case CreateNotify:  return e->xcreatewindow.window;        /* DIFF */
268           case DestroyNotify:  return e->xdestroywindow.window;      /* DIFF */
269           case UnmapNotify:  return e->xunmap.window;                /* DIFF */
270           case MapNotify:  return e->xmap.window;                            /* DIFF */
271           case MapRequest:  return e->xmaprequest.window;                    /* DIFF */
272           case ReparentNotify:  return e->xreparent.window;                  /* DIFF */
273           case ConfigureNotify:  return e->xconfigure.window;        /* DIFF */
274           case ConfigureRequest:  return e->xconfigurerequest.window;    /* DIFF */
275           case GravityNotify:  return e->xgravity.window;                    /* DIFF */
276           case ResizeRequest:  return e->xresizerequest.window;      /* same */
277           case CirculateNotify:  return e->xcirculate.window;        /* DIFF */
278           case CirculateRequest:  return e->xcirculaterequest.window;    /* DIFF */
279           case PropertyNotify:  return e->xproperty.window;                  /* same */
280           case SelectionClear:  return e->xselectionclear.window;            /* same */
281           case SelectionRequest: return e->xselectionrequest.requestor;  /* DIFF */
282           case SelectionNotify:  return e->xselection.requestor;             /* same */
283           case ColormapNotify:  return e->xcolormap.window;                  /* same */
284           case ClientMessage:  return e->xclient.window;                     /* same */
285           case MappingNotify:  return None;
286         }
287         return None;
288 }
289
290 \f
291
292 /***********************************************************************
293  *
294  *  Procedure:
295  *      DispatchEvent2 -
296  *      handle a single X event stored in global var Event
297  *      this routine for is for a call during an f.move
298  *
299  **********************************************************************/
300 /*
301  * Merged into DispatchEvent()
302  * djhjr - 10/6/02
303  */
304 #if 0
305 Bool DispatchEvent2 ()
306 {
307         Window w = Event.xany.window;
308         StashEventTime (&Event);
309
310         if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
311           Tmp_win = NULL;
312
313         if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
314         Scr = FindScreenInfo (WindowOfEvent (&Event));
315         }
316
317         if (!Scr) return False;
318
319         if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose)
320           HandleExpose();
321
322         if (!menuFromFrameOrWindowOrTitlebar && Event.type>= 0 && Event.type < MAX_X_EVENT) {
323         (*EventHandler[Event.type])();
324         }
325
326         return True;
327 }
328 #endif
329
330 /***********************************************************************
331  *
332  *  Procedure:
333  *      DispatchEvent - handle a single X event stored in global var Event
334  *
335  ***********************************************************************
336  */
337 Bool DispatchEvent ()
338 {
339         Window w = Event.xany.window;
340         StashEventTime (&Event);
341
342         if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
343                 Tmp_win = NULL;
344
345         if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT)
346                 Scr = FindScreenInfo (WindowOfEvent (&Event));
347
348         if (!Scr) return False;
349
350         if (MoveFunction != F_NOFUNCTION && menuFromFrameOrWindowOrTitlebar)
351         {
352                 if (Event.type == Expose)
353                         HandleExpose();
354         }
355         else if (Event.type >= 0 && Event.type < MAX_X_EVENT)
356                 (*EventHandler[Event.type])();
357
358         return True;
359 }
360
361 \f
362
363 /***********************************************************************
364  *
365  *  Procedure:
366  *      HandleEvents - handle X events
367  *
368  ***********************************************************************
369  */
370
371 void
372 HandleEvents()
373 {
374         while (TRUE)
375         {
376         if (enter_flag && !QLength(dpy)) {
377             if (enter_win && enter_win != raise_win) {
378                 AutoRaiseWindow (enter_win);  /* sets enter_flag T */
379             } else {
380                 enter_flag = FALSE;
381             }
382         }
383         if (ColortableThrashing && !QLength(dpy) && Scr) {
384             InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
385         }
386         WindowMoved = FALSE;
387         XNextEvent(dpy, &Event);
388         (void) DispatchEvent ();
389         }
390 }
391
392 \f
393
394 /***********************************************************************
395  *
396  *  Procedure:
397  *      HandleColormapNotify - colormap notify event handler
398  *
399  * This procedure handles both a client changing its own colormap, and
400  * a client explicitly installing its colormap itself (only the window
401  * manager should do that, so we must set it correctly).
402  *
403  ***********************************************************************
404  */
405
406 void
407 HandleColormapNotify()
408 {
409         XColormapEvent *cevent = (XColormapEvent *) &Event;
410         ColormapWindow *cwin, **cwins;
411         TwmColormap *cmap;
412         int lost, won, n, number_cwins;
413         extern TwmColormap *CreateTwmColormap();
414
415         if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
416         return;
417         cmap = cwin->colormap;
418
419         if (cevent->new)
420         {
421         if (XFindContext(dpy, cevent->colormap, ColormapContext,
422                          (caddr_t *)&cwin->colormap) == XCNOENT)
423             cwin->colormap = CreateTwmColormap(cevent->colormap);
424         else
425             cwin->colormap->refcnt++;
426
427         cmap->refcnt--;
428
429         if (cevent->state == ColormapUninstalled)
430             cmap->state &= ~CM_INSTALLED;
431         else
432             cmap->state |= CM_INSTALLED;
433
434         if (cmap->state & CM_INSTALLABLE)
435             InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
436
437         if (cmap->refcnt == 0)
438         {
439             XDeleteContext(dpy, cmap->c, ColormapContext);
440             free((char *) cmap);
441         }
442
443         return;
444         }
445
446         if (cevent->state == ColormapUninstalled &&
447         (cmap->state & CM_INSTALLABLE))
448         {
449         if (!(cmap->state & CM_INSTALLED))
450             return;
451         cmap->state &= ~CM_INSTALLED;
452
453         if (!ColortableThrashing)
454         {
455             ColortableThrashing = TRUE;
456             XSync(dpy, 0);
457         }
458
459         if (cevent->serial >= Scr->cmapInfo.first_req)
460         {
461             number_cwins = Scr->cmapInfo.cmaps->number_cwins;
462
463             /*
464              * Find out which colortables collided.
465              */
466
467             cwins = Scr->cmapInfo.cmaps->cwins;
468             for (lost = won = -1, n = 0;
469                  (lost == -1 || won == -1) && n < number_cwins;
470                  n++)
471             {
472                 if (lost == -1 && cwins[n] == cwin)
473                 {
474                     lost = n;   /* This is the window which lost its colormap */
475                     continue;
476                 }
477
478                 if (won == -1 &&
479                     cwins[n]->colormap->install_req == cevent->serial)
480                 {
481                     won = n;    /* This is the window whose colormap caused */
482                     continue;   /* the de-install of the previous colormap */
483                 }
484             }
485
486             /*
487             ** Cases are:
488             ** Both the request and the window were found:
489             **          One of the installs made honoring the WM_COLORMAP
490             **          property caused another of the colormaps to be
491             **          de-installed, just mark the scoreboard.
492             **
493             ** Only the request was found:
494             **          One of the installs made honoring the WM_COLORMAP
495             **          property caused a window not in the WM_COLORMAP
496             **          list to lose its map.  This happens when the map
497             **          it is losing is one which is trying to be installed,
498             **          but is getting getting de-installed by another map
499             **          in this case, we'll get a scoreable event later,
500             **          this one is meaningless.
501             **
502             ** Neither the request nor the window was found:
503             **          Somebody called installcolormap, but it doesn't
504             **          affect the WM_COLORMAP windows.  This case will
505             **          probably never occur.
506             **
507             ** Only the window was found:
508             **          One of the WM_COLORMAP windows lost its colormap
509             **          but it wasn't one of the requests known.  This is
510             **          probably because someone did an "InstallColormap".
511             **          The colormap policy is "enforced" by re-installing
512             **          the colormaps which are believed to be correct.
513             */
514
515             if (won != -1)
516                 if (lost != -1)
517                 {
518                     /* lower diagonal index calculation */
519                     if (lost > won)
520                         n = lost*(lost-1)/2 + won;
521                     else
522                         n = won*(won-1)/2 + lost;
523                     Scr->cmapInfo.cmaps->scoreboard[n] = 1;
524                 } else
525                 {
526                     /*
527                     ** One of the cwin installs caused one of the cwin
528                     ** colormaps to be de-installed, so I'm sure to get an
529                     ** UninstallNotify for the cwin I know about later.
530                     ** I haven't got it yet, or the test of CM_INSTALLED
531                     ** above would have failed.  Turning the CM_INSTALLED
532                     ** bit back on makes sure we get back here to score
533                     ** the collision.
534                     */
535                     cmap->state |= CM_INSTALLED;
536                 }
537             else if (lost != -1)
538                 InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
539         }
540         }
541
542         else if (cevent->state == ColormapUninstalled)
543         cmap->state &= ~CM_INSTALLED;
544
545         else if (cevent->state == ColormapInstalled)
546         cmap->state |= CM_INSTALLED;
547 }
548
549 \f
550
551 /***********************************************************************
552  *
553  *  Procedure:
554  *      HandleVisibilityNotify - visibility notify event handler
555  *
556  * This routine keeps track of visibility events so that colormap
557  * installation can keep the maximum number of useful colormaps
558  * installed at one time.
559  *
560  ***********************************************************************
561  */
562
563 void
564 HandleVisibilityNotify()
565 {
566         XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
567         ColormapWindow *cwin;
568         TwmColormap *cmap;
569
570         if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
571         return;
572
573         /*
574          * when Saber complains about retreiving an <int> from an <unsigned int>
575          * just type "touch vevent->state" and "cont"
576          */
577         cmap = cwin->colormap;
578         if ((cmap->state & CM_INSTALLABLE) &&
579         vevent->state != cwin->visibility &&
580         (vevent->state == VisibilityFullyObscured ||
581          cwin->visibility == VisibilityFullyObscured) &&
582         cmap->w == cwin->w) {
583         cwin->visibility = vevent->state;
584         InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
585         } else
586         cwin->visibility = vevent->state;
587 }
588
589 \f
590
591 /***********************************************************************
592  *
593  *  Procedure:
594  *      HandleKeyPress - key press event handler
595  *
596  ***********************************************************************
597  */
598
599 int MovedFromKeyPress = False;
600
601 void
602 HandleKeyPress()
603 {
604         FuncKey *key;
605         int len;
606         unsigned int modifier;
607         TwmWindow *tmp_win;
608
609         /* djhjr - 6/5/98 */
610         int have_ScrFocus = 0;
611
612 #if 0
613         if (InfoLines)
614         {       XUnmapWindow(dpy, Scr->InfoWindow);
615 RFB july 28 1993 this code was wrong anyway because
616 InfoLines should have been set to 0.
617 Simply remove it...
618         }
619 #endif
620         Context = C_NO_CONTEXT;
621
622         if (Event.xany.window == Scr->Root)
623         Context = C_ROOT;
624         if ((Event.xany.window == Scr->VirtualDesktopDisplay) ||
625         (Event.xany.window == Scr->VirtualDesktopDisplayOuter))
626         {
627                 if (Event.xkey.subwindow &&
628                     (XFindContext(dpy, Event.xkey.subwindow, VirtualContext, (caddr_t *) &tmp_win)
629                      != XCNOENT)) {
630                         Tmp_win = tmp_win;
631                         Context = C_VIRTUAL_WIN;
632                 } else {
633                         Context = C_VIRTUAL;
634                         Tmp_win = Scr->VirtualDesktopDisplayTwin;
635                 }
636         }
637         if (Tmp_win)
638         {
639         if (Event.xany.window == Tmp_win->title_w)
640             Context = C_TITLE;
641         if (Event.xany.window == Tmp_win->w)
642             Context = C_WINDOW;
643         if (Event.xany.window == Tmp_win->icon_w)
644             Context = C_ICON;
645         if (Event.xany.window == Tmp_win->frame)
646             Context = C_FRAME;
647         if (Tmp_win->list && Event.xany.window == Tmp_win->list->w)
648             Context = C_ICONMGR;
649         if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon)
650             Context = C_ICONMGR;
651         }
652
653         /*
654          * Now HERE'S a fine little kludge: Make an icon manager's frame or
655          * the virtual desktop's frame or a door and it's frame context-
656          * sensitive to key bindings, and make the frames of windows without
657          * titlebars forward key events.
658          *
659          * djhjr - 6/5/98 7/2/98 7/14/98
660          */
661         if (Scr->Focus && (Context == C_NO_CONTEXT || Context == C_ROOT))
662         {
663                 /* ugly, but it works! see also iconmgr.c:RemoveIconManager() */
664                 if (Scr->Focus->iconmgr)
665                 {
666 #ifdef NEVER /* warps to icon managers uniquely handled in menus.c:WarpToWindow() */
667                         if (!Scr->Focus->iconmgrp->active)
668                         {
669                                 ActiveIconManager(Scr->Focus->iconmgrp->last);
670                                 Tmp_win = Scr->Focus;
671                         }
672                         else
673                                 Tmp_win = Scr->Focus->iconmgrp->active->twm;
674 #endif
675
676                         have_ScrFocus = 1;
677                 }
678                 else if (Scr->VirtualDesktopDisplayTwin == Scr->Focus)
679                 {
680                         Tmp_win = Scr->Focus;
681                         Context = C_VIRTUAL;
682                 }
683                 /* XFindContext() doesn't seem to work here!?! */
684                 else if (Scr->Doors)
685                 {
686                         TwmDoor *door_win;
687
688                         for (door_win = Scr->Doors; door_win != NULL;
689                                         door_win = door_win->next)
690                                 if (door_win->twin == Scr->Focus)
691                                 {
692                                         Tmp_win = Scr->Focus;
693                                         Context = C_DOOR;
694
695                                         break;
696                                 }
697                 }
698                 else if (Scr->Focus->frame && !Scr->Focus->title_w)
699                 {
700                         Tmp_win = Scr->Focus;
701                         Event.xany.window = Tmp_win->frame;
702                         Context = C_FRAME;
703                 }
704         }
705
706         modifier = (Event.xkey.state & mods_used);
707         for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
708         {
709         if (key->keycode == Event.xkey.keycode &&
710             key->mods == modifier &&
711             (key->cont == Context || key->cont == C_NAME))
712         {
713             /* it doesn't make sense to resize from a key press? */
714             if (key->func == F_RESIZE)
715                         return;
716
717                 /*
718                  * Exceptions for warps from icon managers (see the above kludge)
719                  *
720                  * djhjr - 6/5/98 7/2/98 7/14/98
721                  */
722                 switch (key->func)
723                 {
724                         case F_WARP:
725                                 if (have_ScrFocus && Context == C_ROOT)
726                                         return;
727
728                                 break;
729                         case F_WARPCLASSNEXT:
730                         case F_WARPCLASSPREV:
731                         case F_WARPRING:
732                                 if (Context == C_ICONMGR)
733                                         Scr->Focus = Tmp_win = Tmp_win->list->iconmgr->twm_win;
734
735                                 if (have_ScrFocus)
736                                 {
737                                         Tmp_win = Scr->Focus;
738                                         Context = C_ICONMGR;
739                                 }
740
741                                 break;
742 /*                      case F_WARPTO:*/
743 /*                      case F_WARPTOICONMGR:*/
744 /*                      case F_WARPTONEWEST:*/
745                         default:
746                                 break;
747                 }
748
749                 /* special case for moves */
750                 if (key->func == F_MOVE || key->func == F_FORCEMOVE)
751                         MovedFromKeyPress = True;
752
753             if (key->cont != C_NAME)
754             {
755                 ExecuteFunction(key->func, key->action, Event.xany.window,
756                     Tmp_win, &Event, Context, FALSE);
757
758                 /*
759                  * Added this 'if ()' for deferred keyboard events (see also menus.c)
760                  * Submitted by Michel Eyckmans
761                  */
762                 if (!(Context = C_ROOT && RootFunction != F_NOFUNCTION))
763                   XUngrabPointer(dpy, CurrentTime);
764
765                 return;
766             }
767             else
768             {
769                 int matched = FALSE;
770                 len = strlen(key->win_name);
771
772                 /* try and match the name first */
773                 for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
774                     Tmp_win = Tmp_win->next)
775                 {
776                     if (!strncmp(key->win_name, Tmp_win->name, len))
777                     {
778                         matched = TRUE;
779                         ExecuteFunction(key->func, key->action, Tmp_win->frame,
780                             Tmp_win, &Event, C_FRAME, FALSE);
781                         XUngrabPointer(dpy, CurrentTime);
782                     }
783                 }
784
785                 /* now try the res_name */
786                 if (!matched)
787                 for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
788                     Tmp_win = Tmp_win->next)
789                 {
790                     if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
791                     {
792                         matched = TRUE;
793                         ExecuteFunction(key->func, key->action, Tmp_win->frame,
794                             Tmp_win, &Event, C_FRAME, FALSE);
795                         XUngrabPointer(dpy, CurrentTime);
796                     }
797                 }
798
799                 /* now try the res_class */
800                 if (!matched)
801                 for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
802                     Tmp_win = Tmp_win->next)
803                 {
804                     if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
805                     {
806                         matched = TRUE;
807                         ExecuteFunction(key->func, key->action, Tmp_win->frame,
808                             Tmp_win, &Event, C_FRAME, FALSE);
809                         XUngrabPointer(dpy, CurrentTime);
810                     }
811                 }
812                 if (matched)
813                     return;
814             }
815         }
816         }
817
818         /*
819          * If we get here, no function was bound to the key.  Send it
820          * to the client if it was in a window we know about.
821          */
822         if (Tmp_win)
823         {
824             if (Event.xany.window == Tmp_win->icon_w ||
825             Event.xany.window == Tmp_win->frame ||
826             Event.xany.window == Tmp_win->title_w ||
827             (Tmp_win->list && (Event.xany.window == Tmp_win->list->w)))
828             {
829                 Event.xkey.window = Tmp_win->w;
830                 XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
831             }
832         }
833
834 }
835
836 \f
837
838 static void free_window_names (tmp, nukefull, nukename, nukeicon)
839         TwmWindow *tmp;
840         Bool nukefull, nukename, nukeicon;
841 {
842         /*  the other two "free()"s were "XFree()"s - djhjr - 9/14/03 */
843 /*
844
845  * XXX - are we sure that nobody ever sets these to another constant (check
846  * twm windows)?
847  */
848         if (tmp->name == tmp->full_name) nukefull = False;
849
850 /* this test is never true anymore... - djhjr - 2/20/99
851         if (tmp->name == tmp->icon_name) nukename = False;
852 */
853
854 #define isokay(v) ((v) && (v) != NoName)
855
856         if (nukefull && isokay(tmp->full_name)) free (tmp->full_name);
857         if (nukename && isokay(tmp->name)) free (tmp->name);
858
859 /* ...because the icon name is now alloc()'d locally - djhjr - 2/20/99
860         if (nukeicon && isokay(tmp->icon_name)) XFree (tmp->icon_name);
861 */
862         if (nukeicon && tmp->icon_name) free(tmp->icon_name);
863
864 #undef isokay
865         return;
866 }
867
868 \f
869
870 void free_cwins (tmp)
871         TwmWindow *tmp;
872 {
873         int i;
874         TwmColormap *cmap;
875
876         if (tmp->cmaps.number_cwins) {
877         for (i = 0; i < tmp->cmaps.number_cwins; i++) {
878              if (--tmp->cmaps.cwins[i]->refcnt == 0) {
879                 cmap = tmp->cmaps.cwins[i]->colormap;
880                 if (--cmap->refcnt == 0) {
881                     XDeleteContext(dpy, cmap->c, ColormapContext);
882                     free((char *) cmap);
883                 }
884                 XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
885                 free((char *) tmp->cmaps.cwins[i]);
886             }
887         }
888         free((char *) tmp->cmaps.cwins);
889         if (tmp->cmaps.number_cwins > 1) {
890             free(tmp->cmaps.scoreboard);
891             tmp->cmaps.scoreboard = NULL;
892         }
893         tmp->cmaps.number_cwins = 0;
894         }
895 }
896
897 \f
898
899 /***********************************************************************
900  *
901  *  Procedure:
902  *      HandlePropertyNotify - property notify event handler
903  *
904  ***********************************************************************
905  */
906
907 void
908 HandlePropertyNotify()
909 {
910         char *prop = NULL;
911 #ifdef NO_I18N_SUPPORT
912         Atom actual = None;
913         int actual_format;
914         unsigned long nitems, bytesafter;
915 #endif
916         unsigned long valuemask;                /* mask for create windows */
917         XSetWindowAttributes attributes;        /* attributes for create windows */
918         Pixmap pm;
919
920         /* watch for standard colormap changes */
921         if (Event.xproperty.window == Scr->Root) {
922         XStandardColormap *maps = NULL;
923         int nmaps;
924
925         switch (Event.xproperty.state) {
926           case PropertyNewValue:
927             if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps,
928                                   Event.xproperty.atom)) {
929                 /* if got one, then replace any existing entry */
930                 InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
931             }
932             return;
933
934           case PropertyDelete:
935             RemoveRGBColormap (Event.xproperty.atom);
936             return;
937         }
938         }
939
940         if (!Tmp_win) return;           /* unknown window */
941
942 #define MAX_NAME_LEN 200L               /* truncate to this many */
943 #define MAX_ICON_NAME_LEN 200L          /* ditto */
944
945         switch (Event.xproperty.atom) {
946           case XA_WM_NAME:
947 /* djhjr - 9/14/03 */
948 #ifndef NO_I18N_SUPPORT
949         if (!I18N_FetchName(dpy, Tmp_win->w, &prop))
950 #else
951         if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L,
952                         MAX_NAME_LEN, False, XA_STRING, &actual,
953                         &actual_format, &nitems, &bytesafter,
954                         (unsigned char **) &prop) != Success || actual == None)
955 #endif
956                 return;
957
958         free_window_names (Tmp_win, True, True, False);
959         Tmp_win->full_name = (prop) ? strdup(prop) : NoName;
960         Tmp_win->name = (prop) ? strdup(prop) : NoName;
961 /* djhjr - 9/14/03 */
962 #ifndef NO_I18N_SUPPORT
963         if (prop) free(prop);
964 #else
965         if (prop) XFree(prop);
966 #endif
967
968 /* djhjr - 9/14/03 */
969 #ifndef NO_I18N_SUPPORT
970         Tmp_win->name_width = MyFont_TextWidth (&Scr->TitleBarFont,
971 #else
972         Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font,
973 #endif
974                                           Tmp_win->name,
975                                           strlen (Tmp_win->name));
976
977         SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
978                      Tmp_win->frame_width, Tmp_win->frame_height, -1);
979
980         if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
981
982         /*
983          * if the icon name is NoName, set the name of the icon to be
984          * the same as the window
985          */
986 /* see that the icon name is it's own memory - djhjr - 2/20/99
987         if (Tmp_win->icon_name == NoName) {
988             Tmp_win->icon_name = Tmp_win->name;
989 */
990         if (!strcmp(Tmp_win->icon_name, NoName)) {
991             free(Tmp_win->icon_name);
992             Tmp_win->icon_name = strdup(Tmp_win->name);
993
994             RedoIconName();
995         }
996         break;
997
998           case XA_WM_ICON_NAME:
999 /* djhjr - 9/14/03 */
1000 #ifndef NO_I18N_SUPPORT
1001         if (!I18N_GetIconName(dpy, Tmp_win->w, &prop))
1002 #else
1003         if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0,
1004                         MAX_ICON_NAME_LEN, False, XA_STRING, &actual,
1005                         &actual_format, &nitems, &bytesafter,
1006                         (unsigned char **) &prop) != Success || actual == None)
1007 #endif
1008                 return;
1009
1010 /* see that the icon name is it's own memory - djhjr - 2/20/99
1011         if (!prop) prop = NoName;
1012         free_window_names (Tmp_win, False, False, True);
1013         Tmp_win->icon_name = prop;
1014 */
1015         free_window_names (Tmp_win, False, False, True);
1016         Tmp_win->icon_name = (prop) ? strdup(prop) : NoName;
1017 /* djhjr - 9/14/03 */
1018 #ifndef NO_I18N_SUPPORT
1019         if (prop) free(prop);
1020 #else
1021         if (prop) XFree(prop);
1022 #endif
1023
1024         RedoIconName();
1025
1026         break;
1027
1028           case XA_WM_HINTS:
1029         if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
1030         Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
1031
1032         if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint))
1033           Tmp_win->group = Tmp_win->wmhints->window_group;
1034
1035         if (!Tmp_win->forced && Tmp_win->wmhints &&
1036             Tmp_win->wmhints->flags & IconWindowHint) {
1037             if (Tmp_win->icon_w) {
1038                 int icon_x, icon_y;
1039
1040                 /*
1041                  * There's already an icon window.
1042                  * Try to find out where it is; if we succeed, move the new
1043                  * window to where the old one is.
1044                  */
1045                 if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
1046                   &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
1047                     /*
1048                      * Move the new icon window to where the old one was.
1049                      */
1050                     XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
1051                       icon_y);
1052                 }
1053
1054                 /*
1055                  * If the window is iconic, map the new icon window.
1056                  */
1057                 if (Tmp_win->icon)
1058                     XMapWindow(dpy, Tmp_win->wmhints->icon_window);
1059
1060                 /*
1061                  * Now, if the old window isn't ours, unmap it, otherwise
1062                  * just get rid of it completely.
1063                  */
1064                 if (Tmp_win->icon_not_ours) {
1065                     if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window)
1066                         XUnmapWindow(dpy, Tmp_win->icon_w);
1067                 } else
1068                     XDestroyWindow(dpy, Tmp_win->icon_w);
1069
1070                 /*
1071                  * The new icon window isn't our window, so note that fact
1072                  * so that we don't treat it as ours.
1073                  */
1074                 Tmp_win->icon_not_ours = TRUE;
1075
1076                 /*
1077                  * Now make the new window the icon window for this window,
1078                  * and set it up to work as such (select for key presses
1079                  * and button presses/releases, set up the contexts for it,
1080                  * and define the cursor for it).
1081                  */
1082                 Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
1083                 XSelectInput (dpy, Tmp_win->icon_w,
1084                   KeyPressMask | ButtonPressMask | ButtonReleaseMask);
1085                 XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
1086                 XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
1087                 XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
1088             }
1089         }
1090
1091         if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
1092             (Tmp_win->wmhints->flags & IconPixmapHint)) {
1093             if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
1094                                &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width,
1095                                (unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) {
1096                 return;
1097             }
1098
1099             pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width,
1100                                 Tmp_win->icon_height, Scr->d_depth);
1101             if (!pm) return;
1102
1103             FB(Tmp_win->iconc.fore, Tmp_win->iconc.back);
1104
1105 /*
1106  * adapted from CTWM-3.5 - djhjr - 9/4/98
1107  */
1108 #ifdef ORIGINAL_PIXMAPS
1109             XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm,
1110                 Scr->NormalGC,
1111                 0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
1112 #else
1113             if (JunkDepth == Scr->d_depth)
1114                         XCopyArea  (dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
1115                                         0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0);
1116             else
1117                         XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
1118                                         0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
1119 #endif
1120
1121             valuemask = CWBackPixmap;
1122             attributes.background_pixmap = pm;
1123
1124             if (Tmp_win->icon_bm_w)
1125                 XDestroyWindow(dpy, Tmp_win->icon_bm_w);
1126
1127             Tmp_win->icon_bm_w =
1128               XCreateWindow (dpy, Tmp_win->icon_w, 0, 0,
1129                              (unsigned int) Tmp_win->icon_width,
1130                              (unsigned int) Tmp_win->icon_height,
1131                              (unsigned int) 0, Scr->d_depth,
1132                              (unsigned int) CopyFromParent, Scr->d_visual,
1133                              valuemask, &attributes);
1134
1135 /*
1136  * adapted from CTWM-3.5 - djhjr - 9/4/98
1137  */
1138 #ifndef ORIGINAL_PIXMAPS
1139             if (! (Tmp_win->wmhints->flags & IconMaskHint)) {
1140                         XRectangle rect;
1141
1142                         rect.x = rect.y = 0;
1143                         rect.width  = Tmp_win->icon_width;
1144                         rect.height = Tmp_win->icon_height;
1145                         XShapeCombineRectangles (dpy, Tmp_win->icon_w, ShapeBounding,
1146                                         0, 0, &rect, 1, ShapeUnion, 0);
1147             }
1148 #endif
1149
1150             XFreePixmap (dpy, pm);
1151             RedoIconName();
1152         }
1153
1154 /*
1155  * adapted from CTWM-3.5 - djhjr - 9/4/98
1156  */
1157 #ifndef ORIGINAL_PIXMAPS
1158         if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
1159             (Tmp_win->wmhints->flags & IconMaskHint)) {
1160             GC gc;
1161
1162             if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_mask, &JunkRoot,
1163                                &JunkX, &JunkY, &JunkWidth, &JunkHeight, &JunkBW,
1164                                &JunkDepth)) {
1165                 return;
1166             }
1167             if (JunkDepth != 1) return;
1168
1169             pm = XCreatePixmap (dpy, Scr->Root, JunkWidth, JunkHeight, 1);
1170             if (!pm) return;
1171
1172             gc = XCreateGC (dpy, pm, 0, NULL);
1173             if (!gc) return;
1174
1175             XCopyArea (dpy, Tmp_win->wmhints->icon_mask, pm, gc,
1176                        0, 0, JunkWidth, JunkHeight, 0, 0);
1177             XFreeGC (dpy, gc);
1178
1179             XFreePixmap (dpy, pm);
1180                 RedoIconName();
1181         }
1182 #endif
1183
1184         break;
1185
1186           case XA_WM_NORMAL_HINTS:
1187         GetWindowSizeHints (Tmp_win);
1188         break;
1189
1190           default:
1191         if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
1192             FetchWmColormapWindows (Tmp_win);   /* frees old data */
1193             break;
1194         } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
1195             FetchWmProtocols (Tmp_win);
1196             break;
1197         }
1198         break;
1199         }
1200 }
1201
1202 \f
1203
1204 /***********************************************************************
1205  *
1206  *  Procedure:
1207  *      RedoIconName - procedure to re-position the icon window and name
1208  *
1209  ***********************************************************************
1210  */
1211
1212 void RedoIconName()
1213 {
1214         int x, y;
1215
1216         if (Tmp_win->list)
1217         {
1218         /* let the expose event cause the repaint */
1219         XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True);
1220
1221         if (Scr->SortIconMgr)
1222             SortIconManager(Tmp_win->list->iconmgr);
1223         }
1224
1225         if (Scr->Virtual &&
1226         Scr->NamesInVirtualDesktop &&
1227         Tmp_win->VirtualDesktopDisplayWindow)
1228             XClearArea(dpy, Tmp_win->VirtualDesktopDisplayWindow,
1229                        0, 0, 0, 0, True);
1230
1231         if ( ! Tmp_win->icon_w ) return;
1232
1233         if (Tmp_win->icon_not_ours)
1234         return;
1235
1236 /* djhjr - 9/14/03 */
1237 #ifndef NO_I18N_SUPPORT
1238         Tmp_win->icon_w_width = MyFont_TextWidth(&Scr->IconFont,
1239 #else
1240         Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
1241 #endif
1242                         Tmp_win->icon_name, strlen(Tmp_win->icon_name));
1243
1244 /* djhjr - 6/11/96
1245         Tmp_win->icon_w_width += 6;
1246         if (Tmp_win->icon_w_width < Tmp_win->icon_width)
1247         {
1248         Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2;
1249         Tmp_win->icon_x += 3;
1250         Tmp_win->icon_w_width = Tmp_win->icon_width;
1251         }
1252         else
1253         {
1254         Tmp_win->icon_x = 3;
1255         }
1256 */
1257     Tmp_win->icon_w_width += 8;
1258     if (Tmp_win->icon_w_width < Tmp_win->icon_width + 8)
1259     {
1260                 Tmp_win->icon_x = (((Tmp_win->icon_width + 8) - Tmp_win->icon_w_width)/2) + 4;
1261                 Tmp_win->icon_w_width = Tmp_win->icon_width + 8;
1262     }
1263     else
1264                 Tmp_win->icon_x = 4;
1265
1266         if (Tmp_win->icon_w_width == Tmp_win->icon_width)
1267         x = 0;
1268         else
1269         x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2;
1270
1271 /* djhjr - 6/11/96
1272         y = 0;
1273 */
1274         y = 4;
1275
1276 /* djhjr - 6/11/96
1277         Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4;
1278         Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height;
1279 */
1280         Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 8;
1281         Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height + 2;
1282
1283         XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width,
1284         Tmp_win->icon_w_height);
1285         if (Tmp_win->icon_bm_w)
1286         {
1287         XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y);
1288         XMapWindow(dpy, Tmp_win->icon_bm_w);
1289         }
1290         if (Tmp_win->icon)
1291         {
1292         XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
1293         }
1294 }
1295
1296 /*
1297  * RedoDoorName - Redraw the contents of a door's window
1298  *
1299  * djhjr - 2/10/99 2/28/99
1300  */
1301 void
1302 RedoDoorName(twin, door)
1303 TwmWindow *twin;
1304 TwmDoor *door;
1305 {
1306         TwmWindow *tmp_win;
1307
1308         /* font was font.font->fid - djhjr - 9/14/03 */
1309         FBF(door->colors.fore, door->colors.back, Scr->DoorFont);
1310
1311         /* find it's twm window to get the current width, etc. */
1312 /*
1313  * The TWM window is passed from Do*Resize(),
1314  * as it may be undeterminable in HandleExpose()!?
1315  *
1316  * djhjr - 2/28/99
1317  *
1318         if (XFindContext(dpy, Event.xany.window, TwmContext,
1319                         (caddr_t *)&tmp_win) != XCNOENT)
1320 */
1321         if (twin)
1322                 tmp_win = twin;
1323         else
1324                 XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&tmp_win);
1325
1326         if (tmp_win)
1327         {
1328                 int tw, bw;
1329
1330 /* djhjr - 9/14/03 */
1331 #ifndef NO_I18N_SUPPORT
1332                 tw = MyFont_TextWidth(&Scr->DoorFont,
1333 #else
1334                 tw = XTextWidth(Scr->DoorFont.font,
1335 #endif
1336                                 door->name, strlen(door->name));
1337
1338                 /* djhjr - 4/26/96 */
1339 /* djhjr - 8/11/98
1340                 * was 'Scr->use3Dborders' - djhjr - 8/11/98 *
1341                 bw = (Scr->BorderBevelWidth > 0) ? Scr->ThreeDBorderWidth : 0;
1342 */
1343                 bw = (Scr->BorderBevelWidth > 0) ? Scr->BorderWidth : 0;
1344
1345                 /* change the little internal one to fit the external */
1346                 XResizeWindow(dpy, door->w,
1347                           tmp_win->frame_width,
1348                           tmp_win->frame_height);
1349
1350                 /* draw the text in the right place */
1351 /* And it IS the right place.
1352 ** If your font has its characters starting 20 pixels
1353 ** over to the right, it just looks wrong!
1354 ** For example grog-9 from ISC's X11R3 distribution.
1355 */
1356 /* djhjr - 9/14/03 */
1357 #ifndef NO_I18N_SUPPORT
1358                 MyFont_DrawString(dpy, door->w, &Scr->DoorFont,
1359 #else
1360                 XDrawString(dpy, door->w,
1361 #endif
1362                         Scr->NormalGC,
1363 /* gets 'SIZE_VINDENT' out of here... djhjr - 5/14/96
1364                         (tmp_win->frame_width - tw)/2,
1365                         tmp_win->frame_height - SIZE_VINDENT -
1366                         (tmp_win->frame_height - Scr->DoorFont.height)/2,
1367 ** ...and NOW it's in the right place! */
1368                         (tmp_win->frame_width - tw - 2 * bw) / 2,
1369                         (tmp_win->frame_height - tmp_win->title_height -
1370                                         Scr->DoorFont.height - 2 * bw) / 2 +
1371 /* djhjr - 9/14/03
1372                                         Scr->DoorFont.font->ascent,
1373 */
1374                                         Scr->DoorFont.ascent,
1375                         door->name, strlen(door->name));
1376
1377                 /* djhjr - 2/7/99 */
1378                 if (Scr->DoorBevelWidth > 0)
1379                         Draw3DBorder(door->w, 0, 0, tmp_win->frame_width - (bw * 2),
1380                                         tmp_win->frame_height - (bw * 2),
1381                                         Scr->DoorBevelWidth, Scr->DoorC, off, False, False);
1382         } else {
1383 /* djhjr - 9/14/03 */
1384 #ifndef NO_I18N_SUPPORT
1385                 MyFont_DrawString(dpy, door->w, &Scr->DoorFont,
1386 #else
1387                 XDrawString(dpy, door->w,
1388 #endif
1389                         Scr->NormalGC,
1390                         SIZE_HINDENT/2, 0/*Scr->DoorFont.height*/,
1391                         door->name, strlen(door->name));
1392         }
1393 }
1394
1395 /*
1396  * RedoListWindow - Redraw the contents of an icon manager's entry
1397  *
1398  * djhjr - 3/1/99
1399  */
1400 void
1401 RedoListWindow(twin)
1402 TwmWindow *twin;
1403 {
1404 /* djhjr - 4/19/96
1405         * font was font.font->fid - djhjr - 9/14/03 *
1406         FBF(twin->list->fore, twin->list->back, Scr->IconManagerFont);
1407 * djhjr - 9/14/03 *
1408 #ifndef NO_I18N_SUPPORT
1409         MyFont_DrawString (dpy, Event.xany.window, &Scr->IconManagerFont,
1410 #else
1411         XDrawString (dpy, Event.xany.window,
1412 #endif
1413                 Scr->NormalGC,
1414                 iconmgr_textx, Scr->IconManagerFont.y+4,
1415                 twin->icon_name, strlen(twin->icon_name));
1416         DrawIconManagerBorder(twin->list);
1417 */
1418         /* made static - djhjr - 6/18/99 */
1419         static int en = 0, dots = 0;
1420
1421         /* djhjr - 3/29/98 */
1422         int i, j, slen = strlen(twin->icon_name);
1423         char *a = NULL;
1424
1425         /* djhjr - 10/2/01 */
1426         if (!twin->list) return;
1427
1428         /*
1429          * clip the title a couple of characters less than the width of the
1430          * icon window plus padding, and tack on ellipses - this is a little
1431          * different than the titlebar's...
1432          *
1433          * djhjr - 3/29/98
1434          */
1435         if (Scr->NoPrettyTitles == FALSE) /* for rader - djhjr - 2/9/99 */
1436         {
1437 /* djhjr - 9/14/03 */
1438 #ifndef NO_I18N_SUPPORT
1439                 i = MyFont_TextWidth(&Scr->IconManagerFont,
1440 #else
1441                 i = XTextWidth(Scr->IconManagerFont.font,
1442 #endif
1443                                 twin->icon_name, slen);
1444
1445 /* DUH! - djhjr - 6/18/99
1446                 j = twin->list->width - iconmgr_textx - en;
1447 */
1448 /* djhjr - 9/14/03 */
1449 #ifndef NO_I18N_SUPPORT
1450                 if (!en) en = MyFont_TextWidth(&Scr->IconManagerFont, "n", 1);
1451                 if (!dots) dots = MyFont_TextWidth(&Scr->IconManagerFont, "...", 3);
1452 #else
1453                 if (!en) en = XTextWidth(Scr->IconManagerFont.font, "n", 1);
1454                 if (!dots) dots = XTextWidth(Scr->IconManagerFont.font, "...", 3);
1455 #endif
1456                 j = twin->list->width - iconmgr_textx - dots;
1457
1458                 /* djhjr - 5/5/98 */
1459                 /* was 'Scr->use3Diconmanagers' - djhjr - 8/11/98 */
1460                 if (Scr->IconMgrBevelWidth > 0)
1461                         j -= Scr->IconMgrBevelWidth;
1462                 else
1463                         j -= Scr->BorderWidth;
1464
1465 /* djhjr - 6/18/99
1466                 if (2 * en >= j)
1467 */
1468                 if (en >= j)
1469                         slen = 0;
1470                 else if (i >= j)
1471                 {
1472                         for (i = slen; i >= 0; i--)
1473
1474 /* djhjr - 6/18/99
1475                                 if (XTextWidth(Scr->IconManagerFont.font, twin->icon_name, i) + 2 * en < j)
1476 */
1477 /* djhjr - 9/14/03 */
1478 #ifndef NO_I18N_SUPPORT
1479                                 if (MyFont_TextWidth(&Scr->IconManagerFont,
1480 #else
1481                                 if (XTextWidth(Scr->IconManagerFont.font,
1482 #endif
1483                                                 twin->icon_name, i) + en < j)
1484                                 {
1485                                         slen = i;
1486                                         break;
1487                                 }
1488
1489                         a = (char *)malloc(slen + 4);
1490                         memcpy(a, twin->icon_name, slen);
1491                         strcpy(a + slen, "...");
1492                         slen += 3;
1493                 }
1494         }
1495
1496         /* font was font.font->fid - djhjr - 9/14/03 */
1497         FBF(twin->list->cp.fore, twin->list->cp.back, Scr->IconManagerFont);
1498
1499 /* what's the point of this? - djhjr - 5/2/98
1500         if (Scr->use3Diconmanagers && (Scr->Monochrome != COLOR))
1501 * djhjr - 9/14/03 *
1502 #ifndef NO_I18N_SUPPORT
1503                 MyFont_DrawImageString (dpy, twin->list->w,
1504                                 &Scr->IconManagerFont,
1505 #else
1506                 XDrawImageString (dpy, twin->list->w,
1507 #endif
1508                 Scr->NormalGC, iconmgr_textx,
1509
1510 * djhjr - 5/2/98
1511                 Scr->IconManagerFont.y+4,
1512 *
1513                 (twin->list->height - Scr->IconManagerFont.height) / 2 +
1514                         Scr->IconManagerFont.y,
1515
1516                 (a) ? a : twin->icon_name, slen);
1517         else
1518 */
1519 /* djhjr - 9/14/03 */
1520 #ifndef NO_I18N_SUPPORT
1521                 MyFont_DrawString (dpy, twin->list->w,
1522                                 &Scr->IconManagerFont,
1523 #else
1524                 XDrawString (dpy, twin->list->w,
1525 #endif
1526                 Scr->NormalGC, iconmgr_textx,
1527
1528 /* djhjr - 5/2/98
1529                 Scr->IconManagerFont.y+4,
1530 */
1531                 (twin->list->height - Scr->IconManagerFont.height) / 2 +
1532                         Scr->IconManagerFont.y,
1533
1534                 (a) ? a : twin->icon_name, slen);
1535
1536         /* free the clipped title - djhjr - 3/29/98 */
1537         if (a) free(a);
1538
1539         DrawIconManagerBorder(twin->list, False);
1540 }
1541 \f
1542
1543 /***********************************************************************
1544  *
1545  *  Procedure:
1546  *      HandleClientMessage - client message event handler
1547  *
1548  ***********************************************************************
1549  */
1550
1551 void
1552 HandleClientMessage()
1553 {
1554         extern void RestartVtwm();
1555
1556         if (Event.xclient.message_type == _XA_WM_CHANGE_STATE)
1557         {
1558                 if (Tmp_win != NULL)
1559                 {
1560                         if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon)
1561                         {
1562                         XEvent button;
1563
1564                         XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild,
1565                                           &(button.xmotion.x_root),
1566                                           &(button.xmotion.y_root),
1567                                           &JunkX, &JunkY, &JunkMask);
1568
1569                         ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
1570                                 Tmp_win, &button, FRAME, FALSE);
1571                         XUngrabPointer(dpy, CurrentTime);
1572                         }
1573                 }
1574         }
1575         /* djhjr - 7/31/98 */
1576         else if (Event.xclient.message_type == _XA_TWM_RESTART)
1577                 RestartVtwm(CurrentTime);
1578 }
1579
1580 \f
1581
1582 /***********************************************************************
1583  *
1584  *  Procedure:
1585  *      HandleExpose - expose event handler
1586  *
1587  ***********************************************************************
1588  */
1589
1590 static void flush_expose();
1591
1592 void
1593 HandleExpose()
1594 {
1595         MenuRoot *tmp;
1596         TwmDoor *door = NULL;
1597         int j;
1598
1599         if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0)
1600         {
1601                 PaintMenu(tmp, &Event);
1602                 return;
1603         }
1604
1605         if (XFindContext(dpy, Event.xany.window, DoorContext, (caddr_t *)&door) != XCNOENT)
1606         {
1607                 /* see also resize.c - djhjr - 2/28/99 */
1608                 RedoDoorName(NULL, door);
1609                 flush_expose(Event.xany.window);
1610                 return;
1611         }
1612
1613         if (Event.xexpose.count != 0)
1614         return;
1615
1616         if (Event.xany.window == Scr->InfoWindow && InfoLines)
1617         {
1618         int i, k;
1619         int height;
1620
1621         /* font was font.font->fid - djhjr - 9/14/03 */
1622         FBF(Scr->DefaultC.fore, Scr->DefaultC.back, Scr->InfoFont);
1623
1624         /* djhjr - 5/10/96 */
1625         XGetGeometry (dpy, Scr->InfoWindow, &JunkRoot, &JunkX, &JunkY,
1626                                 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
1627
1628         height = Scr->InfoFont.height+2;
1629         for (i = 0; i < InfoLines; i++)
1630         {
1631                 /* djhjr - 5/10/96 */
1632                 j = strlen(Info[i]);
1633
1634                 /* djhjr - 4/29/98 */
1635                 k = 5;
1636                 /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
1637                 if (!i && Scr->BorderBevelWidth > 0) k += Scr->InfoBevelWidth;
1638
1639 /* djhjr - 9/14/03 */
1640 #ifndef NO_I18N_SUPPORT
1641             MyFont_DrawString(dpy, Scr->InfoWindow, &Scr->InfoFont,
1642 #else
1643             XDrawString(dpy, Scr->InfoWindow,
1644 #endif
1645                 Scr->NormalGC,
1646 /* centers the lines... djhjr - 5/10/96
1647                 10,
1648 */
1649 /* djhjr - 9/14/03 */
1650 #ifndef NO_I18N_SUPPORT
1651                 (JunkWidth - MyFont_TextWidth(&Scr->InfoFont, Info[i], j)) / 2,
1652 #else
1653                 (JunkWidth - XTextWidth(Scr->InfoFont.font, Info[i], j)) / 2,
1654 #endif
1655
1656                 /* 'k' was a hard-coded '5' - djhjr - 4/29/98 */
1657                 (i*height) + Scr->InfoFont.y + k, Info[i], j);
1658         }
1659
1660         /* djhjr - 5/9/96 */
1661         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
1662         if (Scr->InfoBevelWidth > 0)
1663             Draw3DBorder(Scr->InfoWindow, 0, 0, JunkWidth, JunkHeight,
1664 /* djhjr - 4/29/98
1665                                 BW, Scr->DefaultC, off, False, False);
1666 */
1667                                 Scr->InfoBevelWidth, Scr->DefaultC, off, False, False);
1668
1669         flush_expose (Event.xany.window);
1670         }
1671
1672         /* see that the desktop's bevel gets redrawn - djhjr - 2/10/99 */
1673         else if (Event.xany.window == Scr->VirtualDesktopDisplay)
1674         {
1675                 Draw3DBorder(Scr->VirtualDesktopDisplayOuter, 0, 0,
1676                                 Scr->VirtualDesktopMaxWidth + (Scr->VirtualDesktopBevelWidth * 2),
1677                                 Scr->VirtualDesktopMaxHeight + (Scr->VirtualDesktopBevelWidth * 2),
1678                                 Scr->VirtualDesktopBevelWidth, Scr->VirtualC, off, False, False);
1679                 flush_expose (Event.xany.window);
1680                 return;
1681         }
1682
1683         else if (Tmp_win != NULL)
1684         {
1685         /* djhjr - 4/20/96 */
1686         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
1687         if (Scr->BorderBevelWidth > 0 && (Event.xany.window == Tmp_win->frame)) {
1688             PaintBorders (Tmp_win, ((Tmp_win == Scr->Focus) ? True : False));
1689             flush_expose (Event.xany.window);
1690             return;
1691         }
1692         else
1693
1694         if (Event.xany.window == Tmp_win->title_w)
1695         {
1696 /* djhjr - 4/20/96
1697             * font was font.font->fid - djhjr - 9/14/03 *
1698             FBF(Tmp_win->title.fore, Tmp_win->title.back, Scr->TitleBarFont);
1699
1700 * djhjr - 9/14/03 *
1701 #ifndef NO_I18N_SUPPORT
1702             MyFont_DrawString (dpy, Tmp_win->title_w, &Scr->TitleBarFont,
1703 #else
1704             XDrawString (dpy, Tmp_win->title_w,
1705 #endif
1706                          Scr->NormalGC,
1707                          Scr->TBInfo.titlex, Scr->TitleBarFont.y,
1708                          Tmp_win->name, strlen(Tmp_win->name));
1709 */
1710                 PaintTitle (Tmp_win);
1711
1712                 /* djhjr - 10/25/02 */
1713                 PaintTitleHighlight(Tmp_win, (Tmp_win == Scr->Focus) ? on : off);
1714
1715             flush_expose (Event.xany.window);
1716                 return;
1717         }
1718         else if (Event.xany.window == Tmp_win->icon_w)
1719         {
1720
1721 /* djhjr - 4/21/96
1722             * font was font.font->fid - djhjr - 9/14/03 *
1723             FBF(Tmp_win->iconc.fore, Tmp_win->iconc.back, Scr->IconFont);
1724
1725 * djhjr - 9/14/03 *
1726 #ifndef NO_I18N_SUPPORT
1727             MyFont_DrawString (dpy, Tmp_win->icon_w, &Scr->IconManagerFont,
1728 #else
1729             XDrawString (dpy, Tmp_win->icon_w,
1730 #endif
1731                 Scr->NormalGC,
1732                 Tmp_win->icon_x, Tmp_win->icon_y,
1733                 Tmp_win->icon_name, strlen(Tmp_win->icon_name));
1734 */
1735                 PaintIcon(Tmp_win);
1736
1737             flush_expose (Event.xany.window);
1738             return;
1739         } else if (Tmp_win->titlebuttons) {
1740             int i;
1741             Window w = Event.xany.window;
1742             TBWindow *tbw;
1743             int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1744
1745             for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
1746                         if (w == tbw->window) {
1747 /* djhjr - 4/19/96
1748                             register TitleButton *tb = tbw->info;
1749
1750                             FB(Tmp_win->title.fore, Tmp_win->title.back);
1751                             XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC,
1752                                         tb->srcx, tb->srcy, tb->width, tb->height,
1753                                         tb->dstx, tb->dsty, 1);
1754 */
1755                                 /* djhjr - 11/17/97 8/10/98 */
1756                                 /* added the test for window highlighting - djhjr - 3/14/98 */
1757                                 /* collapsed two functions - djhjr - 8/10/98 */
1758                                 if (Scr->ButtonColorIsFrame && Tmp_win->highlight)
1759                                         PaintTitleButton(Tmp_win, tbw, (Scr->Focus == Tmp_win) ? 2 : 1);
1760                                 else
1761                                         PaintTitleButton(Tmp_win, tbw, 0);
1762
1763                             flush_expose (w);
1764                         return;
1765                         }
1766             }
1767         }
1768         if (Tmp_win->list) {
1769             if (Event.xany.window == Tmp_win->list->w)
1770             {
1771                         /* see also resize.c - djhjr - 3/1/99 */
1772                         RedoListWindow(Tmp_win);
1773                         flush_expose (Event.xany.window);
1774                         return;
1775             }
1776             if (Event.xany.window == Tmp_win->list->icon)
1777             {
1778 /* djhjr - 4/19/96
1779                 FB(Tmp_win->list->fore, Tmp_win->list->back);
1780                 XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon,
1781                     Scr->NormalGC,
1782                     0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
1783 */
1784 /* djhjr - 10/30/02
1785                 * was 'Scr->use3Diconmanagers' - djhjr - 8/11/98 *
1786                 if (Scr->IconMgrBevelWidth > 0 && Tmp_win->list->iconifypm)
1787                     XCopyArea (dpy, Tmp_win->list->iconifypm, Tmp_win->list->icon,
1788                                 Scr->NormalGC, 0, 0,
1789                                 iconifybox_width, iconifybox_height, 0, 0);
1790                 else {
1791                     FB(Tmp_win->list->cp.fore, Tmp_win->list->cp.back);
1792                     XCopyPlane(dpy, Scr->siconifyPm->pixmap, Tmp_win->list->icon, Scr->NormalGC,
1793                         0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
1794                 }
1795 */
1796                 XCopyArea(dpy, Tmp_win->list->iconifypm->pixmap,
1797                           Tmp_win->list->icon, Scr->NormalGC, 0, 0,
1798                           iconifybox_width, iconifybox_height, 0, 0);
1799
1800                 flush_expose (Event.xany.window);
1801                 return;
1802             }
1803         }
1804         }
1805
1806         /* update the virtual desktop display names */
1807         if (Scr->Virtual && Scr->NamesInVirtualDesktop) {
1808             TwmWindow *tmp_win;
1809             char *name = NULL;
1810
1811             if (XFindContext(dpy, Event.xany.window, VirtualContext,
1812                              (caddr_t *)&tmp_win) != XCNOENT) {
1813                     /* font was font.font->fid - djhjr - 9/14/03 */
1814                     FBF(tmp_win->virtual.fore, tmp_win->virtual.back,
1815                         Scr->VirtualFont);
1816                     if (tmp_win->icon_name)
1817                             name = tmp_win->icon_name;
1818                     else if (tmp_win->name)
1819                             name = tmp_win->name;
1820                     if (name)
1821 /* djhjr - 9/14/03 */
1822 #ifndef NO_I18N_SUPPORT
1823                             MyFont_DrawImageString(dpy, Event.xany.window,
1824                                              &Scr->VirtualFont,
1825 #else
1826                             XDrawImageString(dpy, Event.xany.window,
1827 #endif
1828                                              Scr->NormalGC,
1829                                              0, Scr->VirtualFont.height,
1830                                              name, strlen(name));
1831             }
1832         }
1833 }
1834
1835 \f
1836
1837 /***********************************************************************
1838  *
1839  *  Procedure:
1840  *      HandleDestroyNotify - DestroyNotify event handler
1841  *
1842  ***********************************************************************
1843  */
1844
1845 void
1846 HandleDestroyNotify()
1847 {
1848         int i;
1849
1850         /*
1851          * Warning, this is also called by HandleUnmapNotify; if it ever needs to
1852          * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
1853          * into a DestroyNotify.
1854          */
1855
1856         if (Tmp_win == NULL)
1857         return;
1858
1859 /* djhjr - 6/22/01 */
1860 #ifndef NO_SOUND_SUPPORT
1861         if (destroySoundFromFunction == FALSE)
1862                 PlaySound(S_CUNMAP);
1863         else
1864                 destroySoundFromFunction = FALSE;
1865 #endif
1866
1867         if (Tmp_win == Scr->Focus)
1868         {
1869         FocusOnRoot();
1870         }
1871
1872         if (Tmp_win == Scr->Newest) /* PF */
1873                 Scr->Newest = NULL; /* PF */
1874
1875         /* djhjr - 5/16/98 */
1876         if (Tmp_win == UnHighLight_win) UnHighLight_win = NULL;
1877
1878         XDeleteContext(dpy, Tmp_win->w, TwmContext);
1879         XDeleteContext(dpy, Tmp_win->w, ScreenContext);
1880         XDeleteContext(dpy, Tmp_win->frame, TwmContext);
1881         XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
1882         XDeleteContext(dpy, Tmp_win->VirtualDesktopDisplayWindow, VirtualContext);
1883         if (Tmp_win->icon_w)
1884         {
1885         XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
1886         XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
1887         }
1888         if (Tmp_win->title_height)
1889         {
1890         int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1891         XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
1892         XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
1893         if (Tmp_win->hilite_w)
1894         {
1895             XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext);
1896             XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext);
1897         }
1898         if (Tmp_win->titlebuttons) {
1899             for (i = 0; i < nb; i++) {
1900                 XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
1901                                 TwmContext);
1902                 XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
1903                                 ScreenContext);
1904             }
1905             }
1906         }
1907
1908         if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps)
1909         InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot);
1910
1911         /*
1912          * TwmWindows contain the following pointers
1913          *
1914          *     1.  full_name
1915          *     2.  name
1916          *     3.  icon_name
1917          *     4.  wmhints
1918          *     5.  class.res_name
1919          *     6.  class.res_class
1920          *     7.  list
1921          *     8.  iconmgrp
1922          *     9.  cwins
1923          *     10. titlebuttons
1924          *     11. window ring
1925          *     12. virtual desktop display window
1926          */
1927         if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
1928
1929         /* djhjr - 4/26/99 */
1930         AppletDown(Tmp_win);
1931
1932         XDestroyWindow(dpy, Tmp_win->frame);
1933         if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
1934         XDestroyWindow(dpy, Tmp_win->icon_w);
1935         IconDown (Tmp_win);
1936         }
1937         XDestroyWindow(dpy, Tmp_win->VirtualDesktopDisplayWindow);      /* 12 */
1938         RemoveIconManager(Tmp_win);                                     /* 7 */
1939         Tmp_win->prev->next = Tmp_win->next;
1940         if (Tmp_win->next != NULL)
1941         Tmp_win->next->prev = Tmp_win->prev;
1942         if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
1943
1944         free_window_names (Tmp_win, True, True, True);          /* 1, 2, 3 */
1945         if (Tmp_win->wmhints)                                   /* 4 */
1946           XFree ((char *)Tmp_win->wmhints);
1947         if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName)  /* 5 */
1948           XFree ((char *)Tmp_win->class.res_name);
1949         if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */
1950           XFree ((char *)Tmp_win->class.res_class);
1951         free_cwins (Tmp_win);                           /* 9 */
1952         if (Tmp_win->titlebuttons)                                      /* 10 */
1953           free ((char *) Tmp_win->titlebuttons);
1954         /*
1955          * 11a through 11c was handled in a local function, but
1956          * is now broken out (11a & 11b), and uses a public function
1957          * in menus.c (11c) - djhjr - 10/27/02
1958          */
1959         if (enter_win == Tmp_win) {                     /* 11a */
1960           enter_flag = FALSE;
1961           enter_win = NULL;
1962         }
1963         if (raise_win == Tmp_win) raise_win = NULL;     /* 11b */
1964         RemoveWindowFromRing(Tmp_win);                  /* 11c */
1965
1966         free((char *)Tmp_win);
1967 }
1968
1969 \f
1970
1971 void
1972 HandleCreateNotify()
1973 {
1974 #ifdef DEBUG_EVENTS
1975         fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
1976         fflush(stderr);
1977         XBell(dpy, 0);
1978         XSync(dpy, 0);
1979 #endif
1980 }
1981
1982 \f
1983
1984 /***********************************************************************
1985  *
1986  *  Procedure:
1987  *      HandleMapRequest - MapRequest event handler
1988  *
1989  ***********************************************************************
1990  */
1991
1992 void
1993 HandleMapRequest()
1994 {
1995
1996         int stat;
1997         int zoom_save;
1998
1999         Event.xany.window = Event.xmaprequest.window;
2000         stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win);
2001         if (stat == XCNOENT)
2002         Tmp_win = NULL;
2003
2004         /* If the window has never been mapped before ... */
2005         if (Tmp_win == NULL)
2006         {
2007         /* Add decorations. */
2008         Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
2009         if (Tmp_win == NULL)
2010             return;
2011
2012 /* djhjr - 6/22/01 */
2013 #ifndef NO_SOUND_SUPPORT
2014         if (createSoundFromFunction == FALSE)
2015                 PlaySound(S_CMAP);
2016         else
2017                 createSoundFromFunction = FALSE;
2018 #endif
2019
2020         }
2021         else
2022         {
2023         /*
2024          * If the window has been unmapped by the client, it won't be listed
2025          * in the icon manager.  Add it again, if requested.
2026          */
2027         if (Tmp_win->list == NULL)
2028             (void) AddIconManager (Tmp_win);
2029         }
2030
2031         /* If it's not merely iconified, and we have hints, use them. */
2032         if ((! Tmp_win->icon) &&
2033         Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
2034         {
2035         int state;
2036         Window icon;
2037
2038         /* use WM_STATE if enabled */
2039         if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
2040               (state == NormalState || state == IconicState)))
2041           state = Tmp_win->wmhints->initial_state;
2042
2043         switch (state)
2044         {
2045             case DontCareState:
2046             case NormalState:
2047             case ZoomState:
2048             case InactiveState:
2049                 XMapWindow(dpy, Tmp_win->w);
2050                 XMapWindow(dpy, Tmp_win->frame);
2051                 SetMapStateProp(Tmp_win, NormalState);
2052                 SetRaiseWindow (Tmp_win);
2053
2054                 /* djhjr - 10/2/01 */
2055                 if (Scr->StrictIconManager)
2056                     if (Tmp_win->list)
2057                         RemoveIconManager(Tmp_win);
2058
2059                 break;
2060
2061             case IconicState:
2062                 zoom_save = Scr->DoZoom;
2063                 Scr->DoZoom = FALSE;
2064                 Iconify(Tmp_win, 0, 0);
2065                 Scr->DoZoom = zoom_save;
2066                 break;
2067         }
2068         }
2069         /* If no hints, or currently an icon, just "deiconify" */
2070         else
2071         {
2072         DeIconify(Tmp_win);
2073         SetRaiseWindow (Tmp_win);
2074         }
2075
2076         RaiseStickyAbove(); /* DSE */
2077         RaiseAutoPan(); /* DSE */
2078
2079 }
2080
2081 \f
2082
2083 void SimulateMapRequest (w)
2084         Window w;
2085 {
2086         Event.xmaprequest.window = w;
2087         HandleMapRequest ();
2088 }
2089
2090 \f
2091
2092 /***********************************************************************
2093  *
2094  *  Procedure:
2095  *      HandleMapNotify - MapNotify event handler
2096  *
2097  ***********************************************************************
2098  */
2099
2100 void
2101 HandleMapNotify()
2102 {
2103         if (Tmp_win == NULL)
2104         return;
2105
2106         /*
2107          * Need to do the grab to avoid race condition of having server send
2108          * MapNotify to client before the frame gets mapped; this is bad because
2109          * the client would think that the window has a chance of being viewable
2110          * when it really isn't.
2111          */
2112         XGrabServer (dpy);
2113         if (Tmp_win->icon_w)
2114         XUnmapWindow(dpy, Tmp_win->icon_w);
2115         if (Tmp_win->title_w)
2116         XMapSubwindows(dpy, Tmp_win->title_w);
2117         XMapSubwindows(dpy, Tmp_win->frame);
2118
2119 /* djhjr - 4/25/96
2120         if (Scr->Focus != Tmp_win && Tmp_win->hilite_w)
2121         XUnmapWindow(dpy, Tmp_win->hilite_w);
2122 */
2123         if (Scr->Focus != Tmp_win)
2124                 PaintTitleHighlight(Tmp_win, off);
2125
2126         XMapWindow(dpy, Tmp_win->frame);
2127         XUngrabServer (dpy);
2128         XFlush (dpy);
2129         Tmp_win->mapped = TRUE;
2130         Tmp_win->icon = FALSE;
2131         Tmp_win->icon_on = FALSE;
2132
2133         /* Race condition if in menus.c:DeIconify() - djhjr - 10/2/01 */
2134         if (Scr->StrictIconManager)
2135             if (Tmp_win->list)
2136                 RemoveIconManager(Tmp_win);
2137 }
2138
2139 \f
2140
2141 /***********************************************************************
2142  *
2143  *  Procedure:
2144  *      HandleUnmapNotify - UnmapNotify event handler
2145  *
2146  ***********************************************************************
2147  */
2148
2149 void
2150 HandleUnmapNotify()
2151 {
2152         int dstx, dsty;
2153         Window dumwin;
2154
2155         /*
2156          * The July 27, 1988 ICCCM spec states that a client wishing to switch
2157          * to WithdrawnState should send a synthetic UnmapNotify with the
2158          * event field set to (pseudo-)root, in case the window is already
2159          * unmapped (which is the case for twm for IconicState).  Unfortunately,
2160          * we looked for the TwmContext using that field, so try the window
2161          * field also.
2162          */
2163         if (Tmp_win == NULL)
2164         {
2165         Event.xany.window = Event.xunmap.window;
2166         if (XFindContext(dpy, Event.xany.window,
2167             TwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
2168             Tmp_win = NULL;
2169         }
2170
2171         if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon))
2172         return;
2173
2174         /*
2175          * The program may have unmapped the client window, from either
2176          * NormalState or IconicState.  Handle the transition to WithdrawnState.
2177          *
2178          * We need to reparent the window back to the root (so that twm exiting
2179          * won't cause it to get mapped) and then throw away all state (pretend
2180          * that we've received a DestroyNotify).
2181          */
2182
2183         XGrabServer (dpy);
2184         if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
2185                                0, 0, &dstx, &dsty, &dumwin)) {
2186         XEvent ev;
2187         Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window,
2188                                                   ReparentNotify, &ev);
2189         SetMapStateProp (Tmp_win, WithdrawnState);
2190         if (reparented) {
2191             if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
2192                                                         Event.xunmap.window,
2193                                                         Tmp_win->old_bw);
2194             if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
2195               XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
2196         } else {
2197             XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
2198                              dstx, dsty);
2199             RestoreWithdrawnLocation (Tmp_win);
2200         }
2201         XRemoveFromSaveSet (dpy, Event.xunmap.window);
2202         XSelectInput (dpy, Event.xunmap.window, NoEventMask);
2203         HandleDestroyNotify ();         /* do not need to mash event before */
2204         } /* else window no longer exists and we'll get a destroy notify */
2205         XUngrabServer (dpy);
2206         XFlush (dpy);
2207 }
2208
2209 \f
2210
2211 /***********************************************************************
2212  *
2213  *  Procedure:
2214  *      HandleMotionNotify - MotionNotify event handler
2215  *
2216  ***********************************************************************
2217  */
2218
2219 #if 0 /* functionality moved to menus.c:ExecuteFunction() - djhjr - 11/7/03 */
2220 void
2221 HandleMotionNotify()
2222 {
2223 #if 0 /* done in menus.c:ExecuteFunction() now - djhjr - 11/4/03 */
2224         if (moving_window) {
2225             DoMoveWindowOnDesktop(Event.xmotion.x, Event.xmotion.y);
2226         }
2227 #endif
2228
2229 #if 0 /* done in menus.c:ExecuteFunction() now - djhjr - 5/27/03 */
2230         if ( ResizeWindow )
2231         {
2232         XQueryPointer( dpy, Event.xany.window,
2233             &(Event.xmotion.root), &JunkChild,
2234             &(Event.xmotion.x_root), &(Event.xmotion.y_root),
2235             &(Event.xmotion.x), &(Event.xmotion.y),
2236             &JunkMask);
2237
2238         /* Set WindowMoved appropriately so that f.deltastop will
2239            work with resize as well as move. */
2240         if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
2241             || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
2242         {
2243           /* djhjr - 9/5/98 */
2244           resizing_window = 1;
2245
2246           WindowMoved = TRUE;
2247         }
2248
2249         /* added this 'if ()' for applying MoveDelta - djhjr - 9/5/98 */
2250         if (resizing_window)
2251         {
2252                 XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win);
2253                 DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
2254         }
2255         }
2256 #endif
2257 }
2258 #endif
2259
2260 \f
2261
2262 /***********************************************************************
2263  *
2264  *  Procedure:
2265  *      HandleButtonRelease - ButtonRelease event handler
2266  *
2267  ***********************************************************************
2268  */
2269 void
2270 HandleButtonRelease()
2271 {
2272 /* djhjr - 10/6/02
2273         int xl, xr, yt, yb, w, h;
2274 */
2275         unsigned mask;
2276
2277         if (Scr->StayUpMenus)
2278         {
2279             if (GlobalFirstTime == True && GlobalMenuButton == True )
2280             {
2281                 ButtonPressed = -1;
2282                 GlobalFirstTime = False;
2283                 return;
2284             } /* end if  */
2285
2286             GlobalFirstTime = True;
2287         } /* end if  */
2288
2289 #if 0
2290 0 For StayUpMenus, delete infobox after buttonpress!
2291 0       if (InfoLines)          /* delete info box on 2nd button release  */
2292 0         /* if (Context == C_IDENTIFY)  */
2293 0               /* This would force you to click on the box itself */
2294 0         {
2295 0fprintf( stderr, "Kill info B\n" );
2296 0       XUnmapWindow(dpy, Scr->InfoWindow);
2297 0       InfoLines = 0;
2298 0       Context = C_NO_CONTEXT;
2299 0         }
2300 #endif
2301
2302 #if 0 /* done in menus.c:ExecuteFunction() now - djhjr - 11/4/03 */
2303         if (moving_window)
2304         {       EndMoveWindowOnDesktop();
2305         }
2306 #endif
2307
2308         if (DragWindow != None)
2309         {
2310 /*
2311  * Most all of this is redundant (see menus.c:ExecuteFunction()),
2312  * and I don't see why. Everything except local functionality is
2313  * '#if 0'd out, with just a few lines moved (copied) to menus.c.
2314  * djhjr - 10/6/02
2315  */
2316 #if 0
2317                 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
2318
2319                 XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win);
2320                 if (DragWindow == Tmp_win->frame)
2321                 {
2322                         xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
2323                         yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
2324                         w = DragWidth + 2 * Tmp_win->frame_bw;
2325                         h = DragHeight + 2 * Tmp_win->frame_bw;
2326                 }
2327                 else
2328                 {
2329 /*
2330  * Deskset/Openwin apps change the icon's border width attribute.
2331  * Submitted by Caveh Frank Jalali
2332  *
2333                         xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth;
2334                         yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth;
2335                         w = DragWidth + 2 * Scr->IconBorderWidth;
2336                         h = DragHeight + 2 * Scr->IconBorderWidth;
2337 */
2338                         XWindowAttributes wat;
2339  
2340                         XGetWindowAttributes(dpy, DragWindow, &wat);
2341                         xl = Event.xbutton.x_root - DragX - wat.border_width;
2342                         yt = Event.xbutton.y_root - DragY - wat.border_width;
2343                         w = DragWidth + 2 * wat.border_width;
2344                         h = DragHeight + 2 * wat.border_width;
2345                 }
2346
2347                 if (ConstMove)
2348                 {
2349                         if (ConstMoveDir == MOVE_HORIZ)
2350                         yt = ConstMoveY;
2351
2352                         if (ConstMoveDir == MOVE_VERT)
2353                         xl = ConstMoveX;
2354
2355                         if (ConstMoveDir == MOVE_NONE)
2356                         {
2357                         yt = ConstMoveY;
2358                         xl = ConstMoveX;
2359                         }
2360                 }
2361
2362                 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2363                 {
2364                         xr = xl + w;
2365                         yb = yt + h;
2366
2367                         if (xl < 0)
2368                         xl = 0;
2369                         if (xr > Scr->MyDisplayWidth)
2370                         xl = Scr->MyDisplayWidth - w;
2371
2372                         if (yt < 0)
2373                         yt = 0;
2374                         if (yb > Scr->MyDisplayHeight)
2375                         yt = Scr->MyDisplayHeight - h;
2376                 }
2377
2378                 CurrentDragX = xl;
2379                 CurrentDragY = yt;
2380                 if (DragWindow == Tmp_win->frame)
2381                   SetupWindow (Tmp_win, xl, yt,
2382                                Tmp_win->frame_width, Tmp_win->frame_height, -1);
2383                 else
2384                         XMoveWindow (dpy, DragWindow, xl, yt);
2385
2386 /* djhjr - 4/7/98
2387                 if (!Scr->NoRaiseMove && !Scr->OpaqueMove)    * opaque already did *
2388                         XRaiseWindow(dpy, DragWindow);
2389 */
2390                 if (!Scr->NoRaiseMove)
2391                         /* opaque already did, so test the individual window, methinks */
2392                         if (DragWindow == Tmp_win->frame)
2393                         {
2394                                 if (!Tmp_win->opaque_move)
2395                                         XRaiseWindow(dpy, DragWindow);
2396                         }
2397                         else if (!Scr->OpaqueMove)
2398                                 XRaiseWindow(dpy, DragWindow);
2399
2400                 RaiseStickyAbove(); /* DSE */
2401                 RaiseAutoPan();
2402
2403                 if (!Scr->OpaqueMove)
2404                         UninstallRootColormap();
2405                 else
2406                         XSync(dpy, 0);
2407
2408                 if (Scr->NumAutoRaises) {
2409                         enter_flag = TRUE;
2410                         enter_win = NULL;
2411                         raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
2412                                  ? Tmp_win : NULL);
2413                 }
2414 #endif
2415
2416                 DragWindow = None;
2417                 ConstMove = FALSE;
2418         }
2419
2420 #ifdef NEVER /* djhjr - 5/27/03 */
2421         if ( ResizeWindow )
2422         {
2423                 EndResize();
2424         }
2425 #endif
2426
2427         if ( ActiveMenu && RootFunction == F_NOFUNCTION )
2428         {
2429                 if ( ActiveItem )
2430                 {
2431                         int func = ActiveItem->func;
2432                         Action = ActiveItem->action;
2433                         switch (func)
2434                         {       case F_MOVE:
2435                                 case F_FORCEMOVE:
2436                                 ButtonPressed = -1;
2437                                 break;
2438 #if (0)
2439 0                       case F_IDENTIFY:
2440 0             case F_CIRCLEUP:
2441 0             case F_CIRCLEDOWN:
2442 0             case F_REFRESH:
2443 0             case F_WARPTOSCREEN:
2444 0               case F_AUTOPAN: /*RFB */
2445 0               case F_SNAPREALSCREEN:/*RFB*/
2446 0               PopDownMenu();
2447 0               break;
2448 #endif
2449                                 default:
2450                                         break;
2451                         }
2452                         ExecuteFunction(func, Action,
2453                                 ButtonWindow ? ButtonWindow->frame : None,
2454                                 ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE);
2455                         Context = C_NO_CONTEXT;
2456                         ButtonWindow = NULL;
2457
2458 /* djhjr - 9/15/99
2459                         * if we are not executing a defered command, then take down the
2460                          * menu
2461                          *
2462                         if (RootFunction == F_NOFUNCTION)
2463                         {
2464                                 PopDownMenu();
2465                         }
2466 */
2467                 }
2468 /* djhjr - 9/15/99
2469                 else
2470 */
2471                         PopDownMenu();
2472         }
2473
2474         mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
2475         switch (Event.xbutton.button)
2476         {
2477                 case Button1: mask &= ~Button1Mask; break;
2478                 case Button2: mask &= ~Button2Mask; break;
2479                 case Button3: mask &= ~Button3Mask; break;
2480                 case Button4: mask &= ~Button4Mask; break;
2481                 case Button5: mask &= ~Button5Mask; break;
2482         }
2483
2484         if (RootFunction != F_NOFUNCTION ||
2485         ResizeWindow != None ||
2486         moving_window != None ||
2487         DragWindow != None)
2488         {       ButtonPressed = -1;
2489         }
2490
2491         if (RootFunction == F_NOFUNCTION &&
2492         (Event.xbutton.state & mask) == 0 &&
2493         DragWindow == None &&
2494         moving_window == None &&
2495         ResizeWindow == None)
2496         {
2497                 XUngrabPointer(dpy, CurrentTime);
2498                 XUngrabServer(dpy);
2499                 XFlush(dpy);
2500                 EventHandler[EnterNotify] = HandleEnterNotify;
2501                 EventHandler[LeaveNotify] = HandleLeaveNotify;
2502         menuFromFrameOrWindowOrTitlebar = FALSE;
2503                 ButtonPressed = -1;
2504                 if (DownIconManager)
2505                 {
2506                         DownIconManager->down = FALSE;
2507
2508 /* djhjr - 4/19/96
2509                         if (Scr->Highlight) DrawIconManagerBorder(DownIconManager);
2510 */
2511                         if (Scr->Highlight) DrawIconManagerBorder(DownIconManager, False);
2512
2513                         DownIconManager = NULL;
2514                 }
2515                 Cancel = FALSE;
2516         }
2517 }
2518
2519 \f
2520
2521 static void do_menu (menu, wnd)
2522         MenuRoot *menu;                 /* menu to pop up */
2523         Window wnd;                             /* invoking window or None */
2524 {
2525         int x = Event.xbutton.x_root;
2526         int y = Event.xbutton.y_root;
2527         Bool center = True;
2528
2529         if (Scr->StayUpMenus)
2530         {       GlobalMenuButton = True;
2531         }
2532
2533         if (!Scr->NoGrabServer)
2534         XGrabServer(dpy);
2535         if (wnd) {
2536         Window child;
2537         /* djhjr - 1/20/98 */
2538         int w = Scr->TBInfo.width / 2;
2539 /* djhjr - 1/20/98
2540         int h = Scr->TBInfo.width - Scr->TBInfo.border;
2541 */
2542         int h = Scr->TBInfo.width;
2543
2544 /* djhjr - 1/20/98
2545         (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
2546 */
2547         (void) XTranslateCoordinates (dpy, wnd, Scr->Root, w, h, &x, &y, &child);
2548
2549 /* djhjr - 1/20/98
2550         * djhjr - 3/12/97 *
2551         y -= Scr->TitleHeight;
2552 */
2553         y -= Scr->TitleHeight / 2;
2554
2555 /* djhjr - 1/20/98
2556         center = False;
2557 */
2558         }
2559         if (PopUpMenu (menu, x, y, center)) {
2560         UpdateMenu();
2561         } else {
2562         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2563         }
2564 }
2565
2566 \f
2567
2568 /***********************************************************************
2569  *
2570  *  Procedure:
2571  *      HandleButtonPress - ButtonPress event handler
2572  *
2573  ***********************************************************************
2574  */
2575 void
2576 HandleButtonPress()
2577 {
2578         unsigned int modifier;
2579         Cursor cur;
2580         TwmDoor *door = NULL;
2581
2582         /* Submitted by Jennifer Elaan */
2583         if (Event.xbutton.button > MAX_BUTTONS)
2584                 return;
2585
2586         if (Scr->StayUpMenus)
2587         {
2588                 /* added '&& ButtonPressed == -1' - Submitted by Steve Ratcliffe */
2589                 if (GlobalFirstTime == False && GlobalMenuButton == True
2590                                 && ButtonPressed == -1)
2591                 {
2592                         return;
2593                 }
2594         }
2595         else
2596         {       /* pop down the menu, if any */
2597                 if (ActiveMenu != NULL) PopDownMenu();
2598         }
2599
2600         if ( InfoLines )        /* StayUpMenus */
2601         {
2602 /* djhjr - 6/22/01 */
2603 #ifndef NO_SOUND_SUPPORT
2604                 PlaySound(S_IUNMAP);
2605 #endif
2606
2607                 XUnmapWindow(dpy, Scr->InfoWindow);
2608                 InfoLines = 0;
2609         }
2610
2611         XSync(dpy, 0);                  /* XXX - remove? */
2612
2613         if (ButtonPressed != -1
2614         && !InfoLines /* want menus if we have info box */
2615         )
2616         {       /* we got another butt press in addition to one still held
2617                 * down, we need to cancel the operation we were doing
2618                 */
2619                 Cancel = TRUE;
2620             if (DragWindow != None)
2621             {
2622                 CurrentDragX = origDragX;
2623                 CurrentDragY = origDragY;
2624                 if (!menuFromFrameOrWindowOrTitlebar)
2625                 {
2626                         /* added this 'if ... else' - djhjr - 4/7/98 */
2627                         if (Tmp_win && DragWindow == Tmp_win->frame && Tmp_win->opaque_move)
2628                                 XMoveWindow (dpy, DragWindow, origDragX, origDragY);
2629                         else
2630                         if (Scr->OpaqueMove && DragWindow != None)
2631                                 XMoveWindow (dpy, DragWindow, origDragX, origDragY);
2632                         else
2633                                 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
2634                 }
2635                 if (!Scr->OpaqueMove) UninstallRootColormap();
2636             }
2637
2638 #if 0 /* done in menus.c:ExecuteFunction() now - djhjr - 11/4/03 */
2639             /* this 'else if ...' - djhjr - 11/3/03 */
2640             else if (moving_window)
2641                 EndMoveWindowOnDesktop();
2642 #endif
2643
2644                 XUnmapWindow(dpy, Scr->SizeWindow);
2645                 ResizeWindow = None;
2646                 DragWindow = None;
2647                 cur = LeftButt;
2648                 if (Event.xbutton.button == Button2) cur = MiddleButt;
2649                 else if (Event.xbutton.button >= Button3) cur = RightButt;
2650
2651                 XGrabPointer(dpy, Scr->Root, True,
2652                         ButtonReleaseMask | ButtonPressMask,
2653                         GrabModeAsync, GrabModeAsync,
2654                         Scr->Root, cur, CurrentTime);
2655                 return;
2656         }
2657         else
2658         {       ButtonPressed = Event.xbutton.button;
2659         }
2660
2661         if ( ResizeWindow != None
2662         || DragWindow != None
2663         || moving_window != None
2664         /* ||ActiveMenu != NULL ** tvtwm StayUpMenus */
2665         )
2666         {
2667                 return;
2668         }
2669
2670         if ( ButtonPressed == Button1 && Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons )
2671         {       /* check the title bar buttons */
2672                 register int i;
2673                 register TBWindow *tbw;
2674                 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
2675
2676                 for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++)
2677                 {
2678                         if (Event.xany.window == tbw->window)
2679                         {
2680                                 if (tbw->info->func == F_MENU)
2681                                 {
2682                                         Context = C_TITLE;
2683                                         ButtonEvent = Event;
2684                                         ButtonWindow = Tmp_win;
2685                                         do_menu (tbw->info->menuroot, tbw->window);
2686                                 }
2687                                 else
2688                                 {
2689                                         /* djhjr - 9/15/99 */
2690                                         Context = C_TITLE;
2691
2692                                         ExecuteFunction (tbw->info->func, tbw->info->action,
2693                                                 Event.xany.window, Tmp_win, &Event, C_TITLE, FALSE);
2694
2695                                         /*
2696                                          * For some reason, we don't get the button up event.
2697                                          * Submitted by Caveh Frank Jalali
2698                                          */
2699                                         ButtonPressed = -1;
2700                                 }
2701
2702                                 return;
2703                         }
2704                 }
2705         }
2706
2707         Context = C_NO_CONTEXT;
2708         if ( Event.xany.window == Scr->InfoWindow ) Context = C_IDENTIFY;
2709         if ( Event.xany.window == Scr->Root ) Context = C_ROOT;
2710
2711 /* djhjr - 9/12/96 - moved to the bottom of this context decision chain...
2712         if
2713         (       Context == C_NO_CONTEXT
2714                 &&
2715                 (       Tmp_win == Scr->VirtualDesktopDisplayTwin
2716                         ||
2717                         Event.xany.window == Scr->VirtualDesktopDisplayOuter
2718                         ||
2719                         Event.xany.window == Scr->VirtualDesktopDisplay
2720                 )
2721         )
2722         {       TwmWindow *tmp_win;
2723
2724                 if ( Event.xbutton.subwindow
2725                 && XFindContext( dpy, Event.xbutton.subwindow, VirtualContext,
2726                         (caddr_t *) &tmp_win )
2727                                 != XCNOENT
2728                 )
2729                 {       * Click in a little window in the panner. *
2730                         Tmp_win = tmp_win;
2731                         Context = C_VIRTUAL_WIN;
2732                 }
2733                 else
2734                 {       * Click in the panner. *
2735                         Tmp_win = Scr->VirtualDesktopDisplayTwin;
2736                         Context = C_VIRTUAL;
2737                 }
2738         }
2739 */
2740
2741         if (XFindContext(dpy, Event.xany.window,
2742                 DoorContext, (caddr_t *)&door) != XCNOENT)
2743                         Context = C_DOOR;
2744
2745         if ( Tmp_win && Context == C_NO_CONTEXT )
2746         {
2747 /* have I really determined that this isn't needed? - djhjr - 9/15/99
2748                 if
2749                 (       Tmp_win->list
2750                         &&
2751                         RootFunction != F_NOFUNCTION
2752                         &&
2753                         (       Event.xany.window == Tmp_win->list->w
2754                                 ||
2755                                 Event.xany.window == Tmp_win->list->icon
2756                         )
2757                 )
2758                 {
2759                         Tmp_win = Tmp_win->list->iconmgr->twm_win;
2760                         XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
2761                                 Event.xbutton.x, Event.xbutton.y,
2762                                 &JunkX, &JunkY, &JunkChild);
2763
2764 * djhjr - 4/21/96
2765                         Event.xbutton.x = JunkX;
2766                         Event.xbutton.y = JunkY - Tmp_win->title_height;
2767 *
2768                         Event.xbutton.x = JunkX - Tmp_win->frame_bw3D;
2769                         Event.xbutton.y = JunkY - Tmp_win->title_height - Tmp_win->frame_bw3D;
2770
2771                         Event.xany.window = Tmp_win->w;
2772                         Context = C_WINDOW;
2773                 }
2774                 else
2775 */
2776                 if ( Event.xany.window == Tmp_win->title_w )
2777                 {
2778                         Context = C_TITLE;
2779                 }
2780                 else if (Event.xany.window == Tmp_win->w)
2781                 {
2782                         printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
2783                         Context = C_WINDOW;
2784                 }
2785                 else if (Event.xany.window == Tmp_win->icon_w)
2786                 {
2787                         Context = C_ICON;
2788                 }
2789                 else if (Event.xany.window == Tmp_win->frame)
2790                 {       /* since we now place a button grab on the frame instead
2791                         * of the window, (see GrabButtons() in add_window.c), we
2792                         * need to figure out where the pointer exactly is before
2793                         * assigning Context.  If the pointer is on the application
2794                         * window we will change the event structure to look as if
2795                         * it came from the application window.
2796                         */
2797                         if (Event.xbutton.subwindow == Tmp_win->w)
2798                         {       Event.xbutton.window = Tmp_win->w;
2799
2800 /* djhjr - 4/21/96
2801                                 Event.xbutton.y -= Tmp_win->title_height;
2802 */
2803                                 Event.xbutton.x -= Tmp_win->frame_bw3D;
2804                                 Event.xbutton.y -= (Tmp_win->title_height + Tmp_win->frame_bw3D);
2805
2806                                 /*****
2807                                 Event.xbutton.x -= Tmp_win->frame_bw;
2808                                 *****/
2809                                 Context = C_WINDOW;
2810                         }
2811
2812 /* not needed after all - djhjr - 9/10/99
2813                         * djhjr - 5/13/99 *
2814                         else if (Scr->Doors)
2815                         {
2816                                 for (door = Scr->Doors; door != NULL; door = door->next)
2817                                         if (door->twin->frame == Tmp_win->frame)
2818                                         {
2819                                                 Context = C_DOOR;
2820
2821                                                 break;
2822                                         }
2823
2824                                 if (!door) Context = C_FRAME;
2825                         }
2826 */
2827
2828                         else Context = C_FRAME;
2829                 }
2830                 else if
2831                 (       Tmp_win->list
2832                         &&
2833                         (       Event.xany.window == Tmp_win->list->w
2834                                 ||
2835                                 Event.xany.window == Tmp_win->list->icon
2836                         )
2837                 )
2838                 {
2839                         Tmp_win->list->down = TRUE;
2840
2841 /* djhjr - 4/19/96
2842                         if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list);
2843 */
2844                         if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list, False);
2845
2846                         DownIconManager = Tmp_win->list;
2847                         Context = C_ICONMGR;
2848                 }
2849         }
2850
2851 /* djhjr - 9/12/96 - moved from the top of this context decision chain...*/
2852         if
2853         (       Context == C_NO_CONTEXT
2854                 &&
2855                 (       Tmp_win == Scr->VirtualDesktopDisplayTwin
2856                         ||
2857                         Event.xany.window == Scr->VirtualDesktopDisplayOuter
2858                         ||
2859                         Event.xany.window == Scr->VirtualDesktopDisplay
2860                 )
2861         )
2862         {       TwmWindow *tmp_win;
2863
2864                 if ( Event.xbutton.subwindow
2865                 && XFindContext( dpy, Event.xbutton.subwindow, VirtualContext,
2866                         (caddr_t *) &tmp_win )
2867                                 != XCNOENT
2868                 )
2869                 {       /* Click in a little window in the panner. */
2870                         Tmp_win = tmp_win;
2871                         Context = C_VIRTUAL_WIN;
2872                 }
2873                 else
2874                 {       /* Click in the panner. */
2875                         Tmp_win = Scr->VirtualDesktopDisplayTwin;
2876                         Context = C_VIRTUAL;
2877                 }
2878         }
2879
2880         /* this section of code checks to see if we were in the middle of
2881         * a command executed from a menu
2882         */
2883         if (RootFunction != F_NOFUNCTION)
2884         {
2885                 if (Event.xany.window == Scr->Root)
2886                 {
2887                         /* if the window was the Root, we don't know for sure it
2888                         * it was the root.  We must check to see if it happened to be
2889                         * inside of a client that was getting button press events.
2890                         */
2891                         XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
2892                                 Event.xbutton.x,
2893                                 Event.xbutton.y,
2894                                 &JunkX, &JunkY, &Event.xany.window);
2895
2896                         if (Event.xany.window == 0 ||
2897                                         XFindContext(dpy, Event.xany.window, TwmContext,
2898                                                         (caddr_t *)&Tmp_win) == XCNOENT)
2899                         {
2900                                 RootFunction = F_NOFUNCTION;
2901                                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2902
2903                                 /*
2904                                  * If stay up menus is set, then the menu may still be active
2905                                  * and should be popped down - Submitted by Steve Ratcliffe
2906                                  */
2907                                 if (ActiveMenu != NULL)
2908                                         PopDownMenu();
2909
2910                                 return;
2911                         }
2912
2913                         XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
2914                                 Event.xbutton.x,
2915                                 Event.xbutton.y,
2916                                 &JunkX, &JunkY, &JunkChild);
2917
2918                         Event.xbutton.x = JunkX;
2919                         Event.xbutton.y = JunkY;
2920                         Context = C_WINDOW;
2921                 }
2922
2923                 /* make sure we are not trying to move an identify window */
2924                 if (Scr->InfoWindow && Event.xany.window != Scr->InfoWindow)
2925                 {
2926                         ExecuteFunction(RootFunction, Action, Event.xany.window,
2927                                 Tmp_win, &Event, Context, FALSE);
2928                         if (Scr->StayUpMenus)
2929                         {       /* pop down the menu, if any */
2930                                 if (ActiveMenu != NULL) PopDownMenu();
2931                         }
2932                 }
2933
2934                 RootFunction = F_NOFUNCTION;
2935                 return;
2936         }
2937
2938         ButtonEvent = Event;
2939         ButtonWindow = Tmp_win;
2940
2941         /* if we get to here, we have to execute a function or pop up a
2942         * menu
2943         */
2944         modifier = (Event.xbutton.state & mods_used);
2945
2946         if (Context == C_NO_CONTEXT) return;
2947
2948         RootFunction = F_NOFUNCTION;
2949         if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU)
2950         {
2951                 do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu,
2952                 (Window) None);
2953                 if (Scr->StayUpMenus)
2954                 {
2955                         GlobalMenuButton = False;
2956                 }
2957         }
2958         else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != F_NOFUNCTION)
2959         {
2960                 Action = Scr->Mouse
2961                         [Event.xbutton.button][Context][modifier].item
2962                                 ? Scr->Mouse
2963                                         [Event.xbutton.button][Context][modifier]
2964                                                 .item->action
2965                                 : NULL;
2966                 ExecuteFunction( Scr->Mouse
2967                         [Event.xbutton.button][Context][modifier].func,
2968                         Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
2969         }
2970         else if (Scr->DefaultFunction.func != F_NOFUNCTION)
2971         {
2972                 if (Scr->DefaultFunction.func == F_MENU)
2973                 {
2974                         do_menu (Scr->DefaultFunction.menu, (Window) None);
2975                 }
2976                 else
2977                 {
2978                         Action = Scr->DefaultFunction.item
2979                                 ? Scr->DefaultFunction.item->action
2980                                 : NULL;
2981                         ExecuteFunction(Scr->DefaultFunction.func, Action,
2982                                 Event.xany.window, Tmp_win, &Event, Context, FALSE);
2983                 }
2984         }
2985 }
2986
2987 \f
2988
2989 /***********************************************************************
2990  *
2991  *  Procedure:
2992  *      HENQueueScanner - EnterNotify event q scanner
2993  *
2994  *      Looks at the queued events and determines if any matching
2995  *      LeaveNotify events or EnterEvents deriving from the
2996  *      termination of a grab are behind this event to allow
2997  *      skipping of unnecessary processing.
2998  *
2999  ***********************************************************************
3000  */
3001
3002 typedef struct HENScanArgs {
3003         Window w;               /* Window we are currently entering */
3004         Bool leaves;    /* Any LeaveNotifies found for this window */
3005         Bool inferior;  /* Was NotifyInferior the mode for LeaveNotify */
3006         Bool enters;    /* Any EnterNotify events with NotifyUngrab */
3007 } HENScanArgs;
3008
3009 /* ARGSUSED*/
3010 static Bool
3011 HENQueueScanner(dpy, ev, args)
3012         Display *dpy;
3013         XEvent *ev;
3014         char *args;
3015 {
3016         if (ev->type == LeaveNotify) {
3017         if (ev->xcrossing.window == ((HENScanArgs *) args)->w &&
3018                 ev->xcrossing.mode == NotifyNormal) {
3019                 ((HENScanArgs *) args)->leaves = True;
3020                 /*
3021                  * Only the last event found matters for the Inferior field.
3022                  */
3023                 ((HENScanArgs *) args)->inferior =
3024                 (ev->xcrossing.detail == NotifyInferior);
3025         }
3026         } else if (ev->type == EnterNotify) {
3027         if (ev->xcrossing.mode == NotifyUngrab)
3028                 ((HENScanArgs *) args)->enters = True;
3029         }
3030
3031         return (False);
3032 }
3033
3034 \f
3035
3036 /***********************************************************************
3037  *
3038  *  Procedure:
3039  *      HandleEnterNotify - EnterNotify event handler
3040  *
3041  ***********************************************************************
3042  */
3043
3044 void
3045 HandleEnterNotify()
3046 {
3047         MenuRoot *mr;
3048         XEnterWindowEvent *ewp = &Event.xcrossing;
3049         HENScanArgs scanArgs;
3050         XEvent dummy;
3051         short l;
3052         extern int RaiseDelay;/*RAISEDELAY*/
3053
3054         /*
3055          * Save the id of the window entered.  This will be used to remove
3056          * border highlight on entering the next application window.
3057          */
3058         if (UnHighLight_win && ewp->window != UnHighLight_win->w) {
3059           SetBorder (UnHighLight_win, False);   /* application window */
3060           if (UnHighLight_win->list) /* in the icon box */
3061         NotActiveIconManager(UnHighLight_win->list);
3062         }
3063         if (ewp->window == Scr->Root)
3064           UnHighLight_win = NULL;
3065         else if (Tmp_win)
3066           UnHighLight_win = Tmp_win;
3067
3068         /*
3069          * if we aren't in the middle of menu processing
3070          */
3071         if (!ActiveMenu) {
3072         /*
3073          * We're not interested in pseudo Enter/Leave events generated
3074          * from grab initiations.
3075          */
3076         if (ewp->mode == NotifyGrab)
3077                 return;
3078
3079         /*
3080          * Scan for Leave and Enter Notify events to see if we can avoid some
3081          * unnecessary processing.
3082          */
3083         scanArgs.w = ewp->window;
3084         scanArgs.leaves = scanArgs.enters = False;
3085         (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
3086
3087         /*
3088          * if it is one of the autopan windows, do the pan
3089          */
3090         if ( Scr->AutoPanX )/*RFB F_AUTOPAN*/
3091         for (l = 0; l <= 3; l++)
3092                 if (ewp->window == Scr->VirtualDesktopAutoPan[l])
3093                 {
3094                         int xdiff, ydiff, xwarp, ywarp;
3095
3096                         /*
3097                          * Code from FVWM-1.23b, modified to reflect "real time"
3098                          * values of the resource.
3099                          *
3100                          * djhjr - 9/8/98
3101                          */
3102                         if (Scr->VirtualDesktopPanResistance > 0 &&
3103                                         Scr->VirtualDesktopPanResistance < 10000)
3104                         {
3105                                 int x, y, i;
3106                                 static struct timeval timeoutval = {0, 12500};
3107                                 struct timeval timeout;
3108
3109                                 /* The granularity of PanResistance is about 25 ms.
3110                                  * The timeout variable is set to 12.5 ms since we
3111                                  * pass this way twice each time an autopan window
3112                                  * is entered.
3113                                  */
3114                                 for (i = 25; i < Scr->VirtualDesktopPanResistance; i += 25)
3115                                 {
3116                                         timeout = timeoutval;
3117                                         select(0, 0, 0, 0, &timeout);
3118
3119                                         scanArgs.w = ewp->window;
3120                                         scanArgs.leaves = scanArgs.enters = False;
3121                                         (void)XCheckIfEvent(dpy, &dummy, HENQueueScanner,
3122                                                         (char *)&scanArgs);
3123
3124                                         if (scanArgs.leaves)
3125                                                 return;
3126                                 }
3127
3128                                 XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
3129                                                 &x, &y, &JunkX, &JunkY, &JunkMask);
3130
3131                                 if (x < Scr->AutoPanBorderWidth)
3132                                         l = 0;
3133                                 else if (x >= Scr->MyDisplayWidth - Scr->AutoPanBorderWidth)
3134                                         l = 1;
3135                                 else if (y < Scr->AutoPanBorderWidth)
3136                                         l = 2;
3137                                 else if (y >= Scr->MyDisplayHeight - Scr->AutoPanBorderWidth)
3138                                         l = 3;
3139                                 else
3140                                         l = 4; /* oops */
3141                         }
3142
3143                         /* figure out which one it is */
3144                         switch (l)
3145                         {
3146                                 case 0: /* left */
3147                                         xdiff = -(Scr->AutoPanX);
3148                                         ydiff = 0;
3149                                         /* xwarp = AP_SIZE + 2; */
3150                                         xwarp = AP_SIZE + Scr->AutoPanExtraWarp; /* DSE */
3151                                         ywarp = 0;
3152                                         break;
3153                                 case 1: /* right */
3154                                         xdiff = Scr->AutoPanX;
3155                                         ydiff = 0;
3156                                         /* xwarp = -(AP_SIZE + 2); */
3157                                         xwarp = -(AP_SIZE + Scr->AutoPanExtraWarp); /* DSE */
3158                                         ywarp = 0;
3159                                         break;
3160                                 case 2: /* up */
3161                                         xdiff = 0;
3162                                         ydiff = -(Scr->AutoPanY);
3163                                         xwarp = 0;
3164                                         /* ywarp = AP_SIZE + 2; */
3165                                         ywarp = AP_SIZE + Scr->AutoPanExtraWarp; /* DSE */
3166                                         break;
3167                                 case 3: /* down */
3168                                         xdiff = 0;
3169                                         ydiff = Scr->AutoPanY;
3170                                         xwarp = 0;
3171                                         /* ywarp = -(AP_SIZE + 2); */
3172                                         ywarp = -(AP_SIZE + Scr->AutoPanExtraWarp); /* DSE */
3173                                         break;
3174                                 default: /* oops */
3175                                         /* this is to stop the compiler complaining */
3176                                         xdiff = ydiff = xwarp = ywarp = 0;
3177 /* not with the PanResistance resource! - djhjr - 9/8/98
3178                                         fprintf(stderr, "vtwm: major problems with autopan\n");
3179 */
3180                         }
3181
3182 /* djhjr - 6/22/01 */
3183 #ifndef NO_SOUND_SUPPORT
3184                         PlaySound(S_APAN);
3185 #endif
3186
3187                         /* do the pan */
3188                         PanRealScreen(xdiff, ydiff, &xwarp, &ywarp); /* DSE */
3189
3190                         /*
3191                          * warp the pointer out of the window so that they can keep
3192                          * moving the mouse
3193                          */
3194                         XWarpPointer(dpy, None, None, 0, 0, 0, 0, xwarp, ywarp);
3195
3196                         return;
3197                 } /* end if ewp->window = autopan */
3198
3199         /*
3200          * if entering root window, restore twm default colormap so that
3201          * titlebars are legible
3202          */
3203         if (ewp->window == Scr->Root) {
3204                 if (!scanArgs.leaves && !scanArgs.enters)
3205                 InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
3206                 return;
3207         }
3208
3209 /*RAISEDELAY*/  /* Handle RaiseDelay, if any..... */
3210 /*RAISEDELAY*/  if (RaiseDelay > 0) {
3211 /*RAISEDELAY*/      if (Tmp_win && Tmp_win->auto_raise
3212 /*RAISEDELAY*/          && (!Tmp_win->list || Tmp_win->list->w != ewp->window)) {
3213 /*RAISEDELAY*/          ColormapWindow *cwin;
3214
3215 #ifdef NEVER
3216 /*RAISEDELAY*/          static struct timeval timeout = {0,12500};
3217 #else
3218 /*
3219  * Submitted by Steve Ratcliffe
3220  */
3221 /*RAISEDELAY*/          static struct timeval timeoutval = {0,12500};
3222 /*RAISEDELAY*/          struct timeval timeout;
3223 #endif
3224
3225 /*RAISEDELAY*/
3226 /*RAISEDELAY*/          if (XFindContext(dpy, Tmp_win->w, ColormapContext,
3227 /*RAISEDELAY*/                           (caddr_t *)&cwin) == XCNOENT) {
3228 /*RAISEDELAY*/              cwin = (ColormapWindow *)NULL;
3229 /*RAISEDELAY*/          }
3230 /*RAISEDELAY*/
3231 /*RAISEDELAY*/          if ((ewp->detail != NotifyInferior
3232 /*RAISEDELAY*/               || Tmp_win->frame == ewp->window)
3233 /*RAISEDELAY*/               && (!cwin || cwin->visibility != VisibilityUnobscured)) {
3234 /*RAISEDELAY*/              int x, y, px, py, d, i;
3235 /*RAISEDELAY*/              Window w;
3236 /*RAISEDELAY*/
3237 /*RAISEDELAY*/              XQueryPointer(dpy, Scr->Root, &w, &w, &px, &py,
3238 /*RAISEDELAY*/                            &d, &d, (unsigned int *)&d);
3239 /*RAISEDELAY*/
3240 /*RAISEDELAY*/              /* The granularity of RaiseDelay is about 25 ms.
3241                                                 * The timeout variable is set to 12.5 ms since we
3242                                                 * pass this way twice each time a twm window is
3243                                                 * entered.
3244                                                 */
3245 /*RAISEDELAY*/              for (i = 25; i < RaiseDelay; i += 25) {
3246
3247 /*
3248  * Submitted by Steve Ratcliffe
3249  */
3250 /*RAISEDELAY*/                  /* The timeout needs initialising each time on Linux */
3251 /*RAISEDELAY*/                  timeout = timeoutval;
3252
3253 /*RAISEDELAY*/                  select(0, 0, 0, 0, &timeout);
3254 /*RAISEDELAY*/                  /* Did we leave this window already? */
3255 /*RAISEDELAY*/                  scanArgs.w = ewp->window;
3256 /*RAISEDELAY*/                  scanArgs.leaves = scanArgs.enters = False;
3257 /*RAISEDELAY*/                  (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner,
3258 /*RAISEDELAY*/                                       (char *) &scanArgs);
3259 /*RAISEDELAY*/                  if (scanArgs.leaves && !scanArgs.inferior) return;
3260 /*RAISEDELAY*/
3261 /*RAISEDELAY*/                  XQueryPointer(dpy, Scr->Root, &w, &w, &x, &y,
3262 /*RAISEDELAY*/                                &d, &d, (unsigned int *)&d);
3263 /*RAISEDELAY*/
3264 /*RAISEDELAY*/                  /* Has the pointer moved?  If so reset the loop cnt.
3265                                                 * We want the pointer to be still for RaiseDelay
3266                                                 * milliseconds before terminating the loop
3267                                                 */
3268 /*RAISEDELAY*/                  if (x != px || y != py) {
3269 /*RAISEDELAY*/                      i = 0; px = x; py = y;
3270 /*RAISEDELAY*/                  }
3271 /*RAISEDELAY*/              }
3272 /*RAISEDELAY*/          }
3273 /*RAISEDELAY*/      }
3274 /*RAISEDELAY*/
3275 /*RAISEDELAY*/      /*
3276                                         * Scan for Leave and Enter Notify events to see if we can avoid some
3277                                         * unnecessary processing.
3278                                         */
3279 /*RAISEDELAY*/      scanArgs.w = ewp->window;
3280 /*RAISEDELAY*/      scanArgs.leaves = scanArgs.enters = False;
3281 /*RAISEDELAY*/      (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
3282 /*RAISEDELAY*/
3283 /*RAISEDELAY*/      /*
3284                                         * if entering root window, restore twm default colormap so that
3285                                         * titlebars are legible
3286                                         */
3287 /*RAISEDELAY*/      if (ewp->window == Scr->Root) {
3288 /*RAISEDELAY*/          if (!scanArgs.leaves && !scanArgs.enters)
3289 /*RAISEDELAY*/              InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
3290 /*RAISEDELAY*/          return;
3291 /*RAISEDELAY*/      }
3292 /*RAISEDELAY*/  }
3293 /*RAISEDELAY*/  /* End of RaiseDelay modification. */
3294
3295         /*
3296          * if we have an event for a specific one of our windows
3297          */
3298         if (Tmp_win) {
3299                 /*
3300                  * If currently in PointerRoot mode (indicated by FocusRoot), then
3301                  * focus on this window
3302                  */
3303                 if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
3304                 if (Tmp_win->list) ActiveIconManager(Tmp_win->list);
3305
3306                 if (Tmp_win->mapped) {
3307                     /*
3308                      * unhighlight old focus window
3309                      */
3310
3311 /* djhjr - 4/25/96
3312                     if (Scr->Focus && Scr->Focus != Tmp_win && Tmp_win->hilite_w)
3313                       XUnmapWindow(dpy, Scr->Focus->hilite_w);
3314 */
3315                     if (Scr->Focus && Scr->Focus != Tmp_win)
3316                                 PaintTitleHighlight(Scr->Focus, off);
3317
3318                     /*
3319                      * If entering the frame or the icon manager, then do
3320                      * "window activation things":
3321                      *
3322                      *     1.  turn on highlight window (if any)
3323                      *     2.  install frame colormap
3324                      *     3.  set frame and highlight window (if any) border
3325                      *     3a. set titlebutton highlight (if button color is frame)
3326                      *     if IconManagerFocus is set or not in icon mgr
3327                      *         4.  focus on client window to forward typing
3328                      *         4a. same as 4 but for icon mgr and/or NoTitlebar set
3329                      *     5.  send WM_TAKE_FOCUS if requested
3330                      */
3331                     if (ewp->window == Tmp_win->frame ||
3332                         (Tmp_win->list && ewp->window == Tmp_win->list->w)) {
3333
3334 /* djhjr - 4/25/96
3335                         if (Tmp_win->hilite_w)                          * 1 *
3336                           XMapWindow (dpy, Tmp_win->hilite_w);
3337 */
3338                         PaintTitleHighlight(Tmp_win, on);               /* 1 */
3339
3340                         if (!scanArgs.leaves && !scanArgs.enters)       /* 2 */
3341                             InstallWindowColormaps (EnterNotify,
3342                                                     &Scr->TwmRoot);
3343                         SetBorder (Tmp_win, True);                      /* 3, 3a */
3344
3345                         /* added this 'if()' - djhjr - 5/27/98 */
3346                         /* added hack for StrictIconManager - djhjr - 10/2/01 */
3347                         /* added test for transients - djhjr - 4/9/02 */
3348                         if (Scr->IconManagerFocus ||
3349                                         (Scr->FocusRoot &&
3350                                         Scr->StrictIconManager &&
3351                                         !Tmp_win->list) ||
3352                                         (Tmp_win->list && Tmp_win->list->w &&
3353                                         Tmp_win->list->w != ewp->window) ||
3354                                         Tmp_win->transient)
3355                         {
3356                         /* added test for transients - djhjr - 4/9/02 */
3357                         if ((((Tmp_win->title_w || Scr->NoTitlebar) &&  /* 4, 4a */
3358                                         Scr->TitleFocus) ||
3359                                         Tmp_win->transient) &&
3360                                         Tmp_win->wmhints &&
3361                                         Tmp_win->wmhints->input)
3362                                 SetFocus (Tmp_win, ewp->time);
3363                         }
3364
3365                         if (Tmp_win->protocols & DoesWmTakeFocus)       /* 5 */
3366                           SendTakeFocusMessage (Tmp_win, ewp->time);
3367                         Scr->Focus = Tmp_win;
3368                     } else if (ewp->window == Tmp_win->w) {
3369                         /*
3370                          * If we are entering the application window, install
3371                          * its colormap(s).
3372                          */
3373                         if (!scanArgs.leaves || scanArgs.inferior)
3374                             InstallWindowColormaps(EnterNotify, Tmp_win);
3375                     }
3376                 }                       /* end if Tmp_win->mapped */
3377                 if (Tmp_win->wmhints != NULL &&
3378                         ewp->window == Tmp_win->wmhints->icon_window &&
3379                         (!scanArgs.leaves || scanArgs.inferior))
3380                             InstallWindowColormaps(EnterNotify, Tmp_win);
3381                 }                               /* end if FocusRoot */
3382                 /*
3383                  * If this window is to be autoraised, mark it so
3384                  */
3385                 if (Tmp_win->auto_raise) {
3386                 enter_win = Tmp_win;
3387                 if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
3388                 } else if (enter_flag && raise_win == Tmp_win)
3389                   enter_win = Tmp_win;
3390                 /*
3391                  * set ring leader
3392                  */
3393                 if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
3394                 {
3395                         /*
3396                          * If this window is an icon manager window, make
3397                          * the ring leader the icon manager - djhjr - 11/8/01
3398                          *
3399                          * Is the icon manager in the ring? - djhjr - 10/27/02
3400                          */
3401                         if (Tmp_win->list && ewp->window == Tmp_win->list->w &&
3402                                         Tmp_win->list->iconmgr->twm_win->ring.next)
3403                         {
3404                                 Scr->RingLeader = Tmp_win->list->iconmgr->twm_win;
3405                         }
3406                         else
3407                                 Scr->RingLeader = Tmp_win;
3408                 }
3409                 XSync (dpy, 0);
3410                 return;
3411         }                               /* end if Tmp_win */
3412         }                                       /* end if !ActiveMenu */
3413
3414         /*
3415          * Find the menu that we are dealing with now; punt if unknown
3416          */
3417         if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return;
3418
3419         mr->entered = TRUE;
3420 /* djhjr - 4/23/96
3421         if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == F_NOFUNCTION) {
3422                 if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
3423                 XUnmapWindow (dpy, ActiveMenu->w);
3424                 ActiveMenu->mapped = UNMAPPED;
3425                 UninstallRootColormap ();
3426                 if (ActiveItem) {
3427                         ActiveItem->state = 0;
3428                         PaintEntry (ActiveMenu, ActiveItem,  False);
3429                 }
3430                 ActiveItem = NULL;
3431                 ActiveMenu = mr;
3432                 MenuDepth--;
3433         }
3434 */
3435     if (RootFunction == F_NOFUNCTION) {
3436                 MenuRoot *tmp;
3437                 for (tmp = ActiveMenu; tmp; tmp = tmp->prev) {
3438                 if (tmp == mr) break;
3439                 }
3440                 if (! tmp) return;
3441                 for (tmp = ActiveMenu; tmp != mr; tmp = tmp->prev) {
3442                         /* all 'tmp' were 'ActiveMenu'... DUH! - djhjr - 11/16/98 */
3443                         if (Scr->Shadow) XUnmapWindow (dpy, tmp->shadow);
3444                         XUnmapWindow (dpy, tmp->w);
3445                         tmp->mapped = UNMAPPED;
3446                 MenuDepth--;
3447                 }
3448                 UninstallRootColormap ();
3449                 if (ActiveItem) {
3450                 ActiveItem->state = 0;
3451                 PaintEntry (ActiveMenu, ActiveItem,  False);
3452                 }
3453                 ActiveItem = NULL;
3454                 ActiveMenu = mr;
3455         }
3456
3457         return;
3458 }
3459
3460 \f
3461
3462 /***********************************************************************
3463  *
3464  *  Procedure:
3465  *      HLNQueueScanner - LeaveNotify event q scanner
3466  *
3467  *      Looks at the queued events and determines if any
3468  *      EnterNotify events are behind this event to allow
3469  *      skipping of unnecessary processing.
3470  *
3471  ***********************************************************************
3472  */
3473
3474 typedef struct HLNScanArgs {
3475         Window w;               /* The window getting the LeaveNotify */
3476         Bool enters;    /* Any EnterNotify event at all */
3477         Bool matches;   /* Any matching EnterNotify events */
3478 } HLNScanArgs;
3479
3480 /* ARGSUSED*/
3481 static Bool
3482 HLNQueueScanner(dpy, ev, args)
3483         Display *dpy;
3484         XEvent *ev;
3485         char *args;
3486 {
3487         if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
3488         ((HLNScanArgs *) args)->enters = True;
3489         if (ev->xcrossing.window == ((HLNScanArgs *) args)->w)
3490                 ((HLNScanArgs *) args)->matches = True;
3491         }
3492
3493         return (False);
3494 }
3495
3496 \f
3497
3498 /***********************************************************************
3499  *
3500  *  Procedure:
3501  *      HandleLeaveNotify - LeaveNotify event handler
3502  *
3503  ***********************************************************************
3504  */
3505
3506 void
3507 HandleLeaveNotify()
3508 {
3509         HLNScanArgs scanArgs;
3510         XEvent dummy;
3511
3512         if (Tmp_win != NULL)
3513         {
3514         Bool inicon;
3515
3516         /*
3517          * We're not interested in pseudo Enter/Leave events generated
3518          * from grab initiations and terminations.
3519          */
3520         if (Event.xcrossing.mode != NotifyNormal)
3521                 return;
3522
3523         inicon = (Tmp_win->list &&
3524                   Tmp_win->list->w == Event.xcrossing.window);
3525
3526 /*
3527  * rem'ing this allows the window crossed out of onto the root window
3528  * to be remembered, so an f.warpring event occuring on the root window
3529  * will return to that window (see WarpAlongRing() in menus.c).
3530  *
3531  * no, I don't fully understand... djhjr - 5/11/98
3532  *
3533         if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
3534                 (Event.xcrossing.detail != NotifyInferior &&
3535                  Event.xcrossing.window != Tmp_win->w)) {
3536
3537 #ifdef ORIGINAL_WARPRINGCOORDINATES * djhjr - 5/11/98 *
3538                 if (!inicon) {
3539                 if (Tmp_win->mapped) {
3540                     Tmp_win->ring.cursor_valid = False;
3541                 } else {
3542                     Tmp_win->ring.cursor_valid = True;
3543                     Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
3544                                             Tmp_win->frame_x);
3545                     Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
3546                                             Tmp_win->frame_y);
3547                 }
3548                 }
3549 #endif
3550
3551                 Scr->RingLeader = (TwmWindow *) NULL;
3552         }
3553 */
3554
3555         if (Scr->FocusRoot) {
3556
3557                 if (Event.xcrossing.detail != NotifyInferior) {
3558
3559                 /*
3560                  * Scan for EnterNotify events to see if we can avoid some
3561                  * unnecessary processing.
3562                  */
3563                 scanArgs.w = Event.xcrossing.window;
3564                 scanArgs.enters = scanArgs.matches = False;
3565                 (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
3566                                      (char *) &scanArgs);
3567
3568                 if ((Event.xcrossing.window == Tmp_win->frame &&
3569                         !scanArgs.matches) || inicon) {
3570                     if (Tmp_win->list) NotActiveIconManager(Tmp_win->list);
3571
3572 /* djhjr - 4/25/96
3573                     if (Tmp_win->hilite_w)
3574                       XUnmapWindow (dpy, Tmp_win->hilite_w);
3575 */
3576                         PaintTitleHighlight(Tmp_win, off);
3577
3578                     SetBorder (Tmp_win, False);
3579                     if (Scr->TitleFocus ||
3580                         Tmp_win->protocols & DoesWmTakeFocus)
3581                       SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
3582                     Scr->Focus = NULL;
3583                 } else if (Event.xcrossing.window == Tmp_win->w &&
3584                                 !scanArgs.enters) {
3585                     InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot);
3586                 }
3587                 }
3588         }
3589         XSync (dpy, 0);
3590         return;
3591         }
3592 }
3593
3594 \f
3595
3596 /***********************************************************************
3597  *
3598  *  Procedure:
3599  *      HandleConfigureRequest - ConfigureRequest event handler
3600  *
3601  ***********************************************************************
3602  */
3603
3604 void
3605 HandleConfigureRequest()
3606 {
3607         XWindowChanges xwc;
3608         unsigned long xwcm;
3609         int x, y, width, height, bw;
3610         int gravx, gravy;
3611         XConfigureRequestEvent *cre = &Event.xconfigurerequest;
3612
3613 #ifdef DEBUG_EVENTS
3614         fprintf(stderr, "ConfigureRequest\n");
3615         if (cre->value_mask & CWX)
3616         fprintf(stderr, "  x = %d\n", cre->x);
3617         if (cre->value_mask & CWY)
3618         fprintf(stderr, "  y = %d\n", cre->y);
3619         if (cre->value_mask & CWWidth)
3620         fprintf(stderr, "  width = %d\n", cre->width);
3621         if (cre->value_mask & CWHeight)
3622         fprintf(stderr, "  height = %d\n", cre->height);
3623         if (cre->value_mask & CWSibling)
3624         fprintf(stderr, "  above = 0x%x\n", cre->above);
3625         if (cre->value_mask & CWStackMode)
3626         fprintf(stderr, "  stack = %d\n", cre->detail);
3627 #endif
3628
3629         /*
3630          * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
3631          * be wrong
3632          */
3633         Event.xany.window = cre->window;        /* mash parent field */
3634         if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) ==
3635         XCNOENT)
3636           Tmp_win = NULL;
3637
3638
3639         /*
3640          * According to the July 27, 1988 ICCCM draft, we should ignore size and
3641          * position fields in the WM_NORMAL_HINTS property when we map a window.
3642          * Instead, we'll read the current geometry.  Therefore, we should respond
3643          * to configuration requests for windows which have never been mapped.
3644          */
3645         if (!Tmp_win || Tmp_win->icon_w == cre->window) {
3646         xwcm = cre->value_mask &
3647                 (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3648         xwc.x = cre->x;
3649         xwc.y = cre->y;
3650         xwc.width = cre->width;
3651         xwc.height = cre->height;
3652         xwc.border_width = cre->border_width;
3653         XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
3654         return;
3655         }
3656
3657         if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
3658         TwmWindow *otherwin;
3659
3660         xwc.sibling = (((cre->value_mask & CWSibling) &&
3661                         (XFindContext (dpy, cre->above, TwmContext,
3662                                        (caddr_t *) &otherwin) == XCSUCCESS))
3663                        ? otherwin->frame : cre->above);
3664         xwc.stack_mode = cre->detail;
3665         XConfigureWindow (dpy, Tmp_win->frame,
3666                           cre->value_mask & (CWSibling | CWStackMode), &xwc);
3667         }
3668
3669
3670         /* Don't modify frame_XXX fields before calling SetupWindow! */
3671         x = Tmp_win->frame_x;
3672         y = Tmp_win->frame_y;
3673         width = Tmp_win->frame_width;
3674         height = Tmp_win->frame_height;
3675         bw = Tmp_win->frame_bw;
3676
3677         /*
3678          * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
3679          * configure request are for the upper-left outer corner of the window.
3680          * This means that we need to adjust for the additional title height as
3681          * well as for any border width changes that we decide to allow.  The
3682          * current window gravity is to be used in computing the adjustments, just
3683          * as when initially locating the window.  Note that if we do decide to
3684          * allow border width changes, we will need to send the synthetic
3685          * ConfigureNotify event.
3686          */
3687         GetGravityOffsets (Tmp_win, &gravx, &gravy);
3688
3689         if (cre->value_mask & CWBorderWidth) {
3690         int bwdelta = cre->border_width - Tmp_win->old_bw;  /* posit growth */
3691         if (bwdelta && Scr->ClientBorderWidth) {  /* if change allowed */
3692                 x += gravx * bwdelta;   /* change default values only */
3693                 y += gravy * bwdelta;   /* ditto */
3694                 bw = cre->border_width;
3695                 if (Tmp_win->title_height) height += bwdelta;
3696                 x += (gravx < 0) ? bwdelta : -bwdelta;
3697                 y += (gravy < 0) ? bwdelta : -bwdelta;
3698         }
3699         Tmp_win->old_bw = cre->border_width;  /* for restoring */
3700         }
3701
3702         if (cre->value_mask & CWX) {    /* override even if border change */
3703         x = cre->x - bw;
3704
3705         /* djhjr - 4/21/96 */
3706         x -= ((gravx < 0) ? 0 : Tmp_win->frame_bw3D);
3707
3708         }
3709         if (cre->value_mask & CWY) {
3710         y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
3711
3712         /* djhjr - 4/21/96 */
3713         y -= ((gravy < 0) ? 0 : Tmp_win->frame_bw3D);
3714
3715         }
3716
3717         if (cre->value_mask & CWWidth) {
3718
3719 /* djhjr - 4/21/96
3720         width = cre->width;
3721 */
3722         width = cre->width + 2 * Tmp_win->frame_bw3D;
3723
3724         }
3725         if (cre->value_mask & CWHeight) {
3726
3727 /* djhjr - 4/21/96
3728         height = cre->height + Tmp_win->title_height;
3729 */
3730         height = cre->height + Tmp_win->title_height + 2 * Tmp_win->frame_bw3D;
3731
3732         }
3733
3734         if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
3735         Tmp_win->zoomed = ZOOM_NONE;
3736
3737         /*
3738          * SetupWindow (x,y) are the location of the upper-left outer corner and
3739          * are passed directly to XMoveResizeWindow (frame).  The (width,height)
3740          * are the inner size of the frame.  The inner width is the same as the
3741          * requested client window width; the inner height is the same as the
3742          * requested client window height plus any title bar slop.
3743          */
3744 /* propogate ConfigureNotify events - submitted by Jonathan Paisley - 11/11/02
3745         SetupWindow (Tmp_win, x, y, width, height, bw);
3746 */
3747         SetupFrame(Tmp_win, x, y, width, height, bw, True);
3748
3749         /* Change the size of the desktop representation */
3750         MoveResizeDesktop (Tmp_win, TRUE);
3751
3752         /*
3753          * Raise the autopan windows in case the current window covers them.
3754          * Submitted by Steve Ratcliffe
3755          */
3756         RaiseAutoPan();
3757 }
3758
3759 \f
3760
3761 /***********************************************************************
3762  *
3763  *  Procedure:
3764  *      HandleShapeNotify - shape notification event handler
3765  *
3766  ***********************************************************************
3767  */
3768 void
3769 HandleShapeNotify ()
3770 {
3771         XShapeEvent         *sev = (XShapeEvent *) &Event;
3772
3773         if (Tmp_win == NULL)
3774         return;
3775         if (sev->kind != ShapeBounding)
3776         return;
3777         if (!Tmp_win->wShaped && sev->shaped) {
3778         XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
3779                            ShapeSet);
3780         }
3781         Tmp_win->wShaped = sev->shaped;
3782         SetFrameShape (Tmp_win);
3783 }
3784
3785 \f
3786
3787 /***********************************************************************
3788  *
3789  *  Procedure:
3790  *      HandleUnknown - unknown event handler
3791  *
3792  ***********************************************************************
3793  */
3794
3795 void
3796 HandleUnknown()
3797 {
3798 #ifdef DEBUG_EVENTS
3799         fprintf(stderr, "type = %d\n", Event.type);
3800 #endif
3801 }
3802
3803 \f
3804
3805 /***********************************************************************
3806  *
3807  *  Procedure:
3808  *      Transient - checks to see if the window is a transient
3809  *
3810  *  Returned Value:
3811  *      TRUE    - window is a transient
3812  *      FALSE   - window is not a transient
3813  *
3814  *  Inputs:
3815  *      w       - the window to check
3816  *
3817  ***********************************************************************
3818  */
3819
3820 int
3821 Transient(w, propw)
3822         Window w, *propw;
3823 {
3824         return (XGetTransientForHint(dpy, w, propw));
3825 }
3826
3827 \f
3828
3829 /***********************************************************************
3830  *
3831  *  Procedure:
3832  *      FindScreenInfo - get ScreenInfo struct associated with a given window
3833  *
3834  *  Returned Value:
3835  *      ScreenInfo struct
3836  *
3837  *  Inputs:
3838  *      w       - the window
3839  *
3840  ***********************************************************************
3841  */
3842
3843 ScreenInfo *
3844 FindScreenInfo(w)
3845         Window w;
3846 {
3847         XWindowAttributes attr;
3848         int scrnum;
3849
3850         attr.screen = NULL;
3851         if (XGetWindowAttributes(dpy, w, &attr)) {
3852         for (scrnum = 0; scrnum < NumScreens; scrnum++) {
3853                 if (ScreenList[scrnum] != NULL &&
3854                 (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
3855                  attr.screen))
3856                   return ScreenList[scrnum];
3857         }
3858         }
3859
3860         return NULL;
3861 }
3862
3863 \f
3864
3865 static void flush_expose (w)
3866         Window w;
3867 {
3868         XEvent dummy;
3869
3870                                 /* SUPPRESS 530 */
3871         while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
3872 }
3873
3874 \f
3875
3876 /***********************************************************************
3877  *
3878  *  Procedure:
3879  *      InstallWindowColormaps - install the colormaps for one twm window
3880  *
3881  *  Inputs:
3882  *      type    - type of event that caused the installation
3883  *      tmp     - for a subset of event types, the address of the
3884  *                window structure, whose colormaps are to be installed.
3885  *
3886  ***********************************************************************
3887  */
3888
3889 void InstallWindowColormaps (type, tmp)
3890         int type;
3891         TwmWindow *tmp;
3892 {
3893         int i, j, n, number_cwins, state;
3894         ColormapWindow **cwins, *cwin, **maxcwin = NULL;
3895         TwmColormap *cmap;
3896         char *row, *scoreboard;
3897
3898         switch (type) {
3899         case EnterNotify:
3900         case LeaveNotify:
3901         case DestroyNotify:
3902         default:
3903         /* Save the colormap to be loaded for when force loading of
3904          * root colormap(s) ends.
3905          */
3906         Scr->cmapInfo.pushed_window = tmp;
3907         /* Don't load any new colormap if root colormap(s) has been
3908          * force loaded.
3909          */
3910         if (Scr->cmapInfo.root_pushes)
3911                 return;
3912         /* Don't reload the currend window colormap list.
3913          */
3914         if (Scr->cmapInfo.cmaps == &tmp->cmaps)
3915                 return;
3916         if (Scr->cmapInfo.cmaps)
3917                 for (i = Scr->cmapInfo.cmaps->number_cwins,
3918                  cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++)
3919                 (*cwins)->colormap->state &= ~CM_INSTALLABLE;
3920         Scr->cmapInfo.cmaps = &tmp->cmaps;
3921         break;
3922
3923         case PropertyNotify:
3924         case VisibilityNotify:
3925         case ColormapNotify:
3926         break;
3927         }
3928
3929         number_cwins = Scr->cmapInfo.cmaps->number_cwins;
3930         cwins = Scr->cmapInfo.cmaps->cwins;
3931         scoreboard = Scr->cmapInfo.cmaps->scoreboard;
3932
3933         ColortableThrashing = FALSE; /* in case installation aborted */
3934
3935         state = CM_INSTALLED;
3936
3937 /*
3938  * Submitted by Caveh Frank Jalali
3939  *
3940           for (i = n = 0; i < number_cwins
3941                 && n < Scr->cmapInfo.maxCmaps
3942 */
3943           for (i = 0; i < number_cwins
3944
3945                 /* comp.windows.x
3946                 ** Article <21sn92INNbiv@sirius.isi.com> Mon 18:06
3947                 ** Path: ..!news.isi.com!not-for-mail (Mark Kent @
3948                 ** Integrated Systems, Inc.)
3949                 */
3950           ; i++) {
3951         cwin = cwins[i];
3952         cmap = cwin->colormap;
3953         cmap->state |= CM_INSTALLABLE;
3954         cmap->state &= ~CM_INSTALL;
3955         cmap->w = cwin->w;
3956           }
3957           for (i = n = 0; i < number_cwins; i++) {
3958         cwin = cwins[i];
3959         cmap = cwin->colormap;
3960         if (cwin->visibility != VisibilityFullyObscured
3961                 /* && n < Scr->cmapInfo.maxCmaps
3962                 ** <21sn92INNbiv@sirius.isi.com>
3963                 */
3964         ) {
3965                 row = scoreboard + (i*(i-1)/2);
3966                 for (j = 0; j < i; j++)
3967                 if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
3968                     break;
3969                 if (j != i)
3970                 continue;
3971                 n++;
3972                 maxcwin = &cwins[i];
3973                 state &= (cmap->state & CM_INSTALLED);
3974                 cmap->state |= CM_INSTALL;
3975         }
3976         }
3977
3978         Scr->cmapInfo.first_req = NextRequest(dpy);
3979
3980 /*
3981  * Submitted by Caveh Frank Jalali
3982  *
3983         for ( ; n > 0; maxcwin--) {
3984 */
3985         for ( ; n > 0; n--, maxcwin--) {
3986
3987                 cmap = (*maxcwin)->colormap;
3988                 if (cmap->state & CM_INSTALL) {
3989                         cmap->state &= ~CM_INSTALL;
3990                         if (!(state & CM_INSTALLED)) {
3991                                 cmap->install_req = NextRequest(dpy);
3992                                 XInstallColormap(dpy, cmap->c);
3993                         }
3994                         cmap->state |= CM_INSTALLED;
3995 /* see above 'for (...)'
3996                         n--;
3997 */
3998                 }
3999         }
4000 }
4001
4002 \f
4003
4004 /***********************************************************************
4005  *
4006  *  Procedures:
4007  *      <Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
4008  *
4009  *         These matching routines provide a mechanism to insure that
4010  *         the root colormap(s) is installed during operations like
4011  *         rubber banding or menu display that require colors from
4012  *         that colormap.  Calls may be nested arbitrarily deeply,
4013  *         as long as there is one UninstallRootColormap call per
4014  *         InstallRootColormap call.
4015  *
4016  *         The final UninstallRootColormap will cause the colormap list
4017  *         which would otherwise have be loaded to be loaded, unless
4018  *         Enter or Leave Notify events are queued, indicating some
4019  *         other colormap list would potentially be loaded anyway.
4020  ***********************************************************************
4021  */
4022
4023 void InstallRootColormap()
4024 {
4025         TwmWindow *tmp;
4026         if (Scr->cmapInfo.root_pushes == 0) {
4027         /*
4028          * The saving and restoring of cmapInfo.pushed_window here
4029          * is a slimy way to remember the actual pushed list and
4030          * not that of the root window.
4031          */
4032         tmp = Scr->cmapInfo.pushed_window;
4033         InstallWindowColormaps(0, &Scr->TwmRoot);
4034         Scr->cmapInfo.pushed_window = tmp;
4035         }
4036         Scr->cmapInfo.root_pushes++;
4037 }
4038
4039 \f
4040
4041 /* ARGSUSED*/
4042 static Bool
4043 UninstallRootColormapQScanner(dpy, ev, args)
4044         Display *dpy;
4045         XEvent *ev;
4046         char *args;
4047 {
4048         if (!*args)
4049         {
4050         if (ev->type == EnterNotify) {
4051                 if (ev->xcrossing.mode != NotifyGrab)
4052                 *args = 1;
4053         } else if (ev->type == LeaveNotify) {
4054                 if (ev->xcrossing.mode == NotifyNormal)
4055                 *args = 1;
4056         }
4057         }
4058
4059         return (False);
4060 }
4061
4062 \f
4063
4064 void UninstallRootColormap()
4065 {
4066         char args;
4067         XEvent dummy;
4068
4069         if (Scr->cmapInfo.root_pushes)
4070         Scr->cmapInfo.root_pushes--;
4071
4072         if (!Scr->cmapInfo.root_pushes) {
4073         /*
4074          * If we have subsequent Enter or Leave Notify events,
4075          * we can skip the reload of pushed colormaps.
4076          */
4077         XSync (dpy, 0);
4078         args = 0;
4079         (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
4080
4081         if (!args)
4082                 InstallWindowColormaps(0, Scr->cmapInfo.pushed_window);
4083         }
4084 }
4085
4086 void SendConfigureNotify(tmp_win, x, y)
4087 TwmWindow *tmp_win;
4088 int x, y;
4089 {
4090         XEvent client_event;
4091
4092     client_event.type = ConfigureNotify;
4093     client_event.xconfigure.display = dpy;
4094     client_event.xconfigure.event = tmp_win->w;
4095     client_event.xconfigure.window = tmp_win->w;
4096
4097 /* djhjr - 4/24/96
4098     client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw);
4099     client_event.xconfigure.y = (y + tmp_win->frame_bw +
4100                              tmp_win->title_height - tmp_win->old_bw);
4101     client_event.xconfigure.width = tmp_win->frame_width;
4102     client_event.xconfigure.height = tmp_win->frame_height -
4103             tmp_win->title_height;
4104 */
4105     client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw
4106                         + tmp_win->frame_bw3D);
4107     client_event.xconfigure.y = (y + tmp_win->frame_bw +
4108                      tmp_win->title_height - tmp_win->old_bw
4109                         + tmp_win->frame_bw3D);
4110     client_event.xconfigure.width = tmp_win->attr.width;
4111     client_event.xconfigure.height = tmp_win->attr.height;
4112
4113     client_event.xconfigure.border_width = tmp_win->old_bw;
4114     /* Real ConfigureNotify events say we're above title window, so ... */
4115     /* what if we don't have a title ????? */
4116     client_event.xconfigure.above = tmp_win->frame;
4117     client_event.xconfigure.override_redirect = False;
4118
4119     XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
4120 }
4121
4122 #ifdef TRACE
4123 dumpevent (e)
4124         XEvent *e;
4125 {
4126         char *name = NULL;
4127
4128         switch (e->type) {
4129           case KeyPress:  name = "KeyPress"; break;
4130           case KeyRelease:  name = "KeyRelease"; break;
4131           case ButtonPress:  name = "ButtonPress"; break;
4132           case ButtonRelease:  name = "ButtonRelease"; break;
4133           case MotionNotify:  name = "MotionNotify"; break;
4134           case EnterNotify:  name = "EnterNotify"; break;
4135           case LeaveNotify:  name = "LeaveNotify"; break;
4136           case FocusIn:  name = "FocusIn"; break;
4137           case FocusOut:  name = "FocusOut"; break;
4138           case KeymapNotify:  name = "KeymapNotify"; break;
4139           case Expose:  name = "Expose"; break;
4140           case GraphicsExpose:  name = "GraphicsExpose"; break;
4141           case NoExpose:  name = "NoExpose"; break;
4142           case VisibilityNotify:  name = "VisibilityNotify"; break;
4143           case CreateNotify:  name = "CreateNotify"; break;
4144           case DestroyNotify:  name = "DestroyNotify"; break;
4145           case UnmapNotify:  name = "UnmapNotify"; break;
4146           case MapNotify:  name = "MapNotify"; break;
4147           case MapRequest:  name = "MapRequest"; break;
4148           case ReparentNotify:  name = "ReparentNotify"; break;
4149           case ConfigureNotify:  name = "ConfigureNotify"; break;
4150           case ConfigureRequest:  name = "ConfigureRequest"; break;
4151           case GravityNotify:  name = "GravityNotify"; break;
4152           case ResizeRequest:  name = "ResizeRequest"; break;
4153           case CirculateNotify:  name = "CirculateNotify"; break;
4154           case CirculateRequest:  name = "CirculateRequest"; break;
4155           case PropertyNotify:  name = "PropertyNotify"; break;
4156           case SelectionClear:  name = "SelectionClear"; break;
4157           case SelectionRequest:  name = "SelectionRequest"; break;
4158           case SelectionNotify:  name = "SelectionNotify"; break;
4159           case ColormapNotify:  name = "ColormapNotify"; break;
4160           case ClientMessage:  name = "ClientMessage"; break;
4161           case MappingNotify:  name = "MappingNotify"; break;
4162         }
4163
4164         if (name) {
4165         printf ("event:  %s, %d remaining\n", name, QLength(dpy));
4166         } else {
4167         printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy));
4168         }
4169 }
4170 #endif /* TRACE */
4171