chiark / gitweb /
Import vtwm_5.4.7.orig.tar.gz
[vtwm.git] / menus.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  * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
31  *
32  * twm menu code
33  *
34  * 17-Nov-87 Thomas E. LaStrange                File created
35  *
36  ***********************************************************************/
37
38 #include <X11/Xmu/CharSet.h>
39 #include <X11/Xos.h>
40 /* djhjr - 10/27/02 */
41 #ifndef NO_REGEX_SUPPORT
42 #include <sys/types.h>
43 #include <regex.h>
44 #endif
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <signal.h>
49 #include <unistd.h>
50 #ifdef NEED_PROCESS_H
51 #include <process.h>
52 #endif
53 #include <ctype.h> /* DSE */
54 #include "twm.h"
55 #include "gc.h"
56 #include "menus.h"
57 #include "resize.h"
58 #include "events.h"
59 #include "util.h"
60 #include "parse.h"
61 #include "gram.h"
62 #include "screen.h"
63 #include "doors.h"
64 #include "desktop.h"
65 #include "add_window.h"
66 /* djhjr - 6/22/01 */
67 #ifndef NO_SOUND_SUPPORT
68 #include "sound.h"
69 #endif
70 #include "version.h"
71
72 #define strdup Strdup /* avoid conflict with system header files */
73 extern char *strdup(char *);
74
75 extern void IconUp(), IconDown(), CreateIconWindow();
76
77 /* djhjr - 4/26/99 */
78 extern void AppletDown();
79
80 /* djhjr - 12/2/01 */
81 extern void delete_pidfile();
82
83 /* djhjr - 10/27/02 */
84 extern int MatchName();
85
86 extern void ResizeTwmWindowContents();
87 extern void SetRaiseWindow();
88
89 extern char *Action;
90 extern int Context;
91 extern int ConstrainedMoveTime;
92 extern TwmWindow *ButtonWindow, *Tmp_win;
93 extern XEvent Event, ButtonEvent;
94 extern char *InitFile;
95
96 int RootFunction = F_NOFUNCTION;
97 MenuRoot *ActiveMenu = NULL;            /* the active menu */
98 MenuItem *ActiveItem = NULL;            /* the active menu item */
99 int MoveFunction = F_NOFUNCTION;        /* or F_MOVE or F_FORCEMOVE */
100 int WindowMoved = FALSE;
101 int menuFromFrameOrWindowOrTitlebar = FALSE;
102 /* djhjr - 6/22/01 */
103 #ifndef NO_SOUND_SUPPORT
104 int createSoundFromFunction = FALSE;
105 int destroySoundFromFunction = FALSE;
106 #endif
107
108 void BumpWindowColormap();
109 void DestroyMenu();
110 void HideIconManager();
111 void MakeMenu();
112 void SendDeleteWindowMessage();
113 void SendSaveYourselfMessage();
114 void WarpClass();
115 void WarpToScreen();
116 void WarpScreenToWindow();
117 Cursor NeedToDefer(); /* was an 'int' - Submitted by Michel Eyckmans */
118
119 int ConstMove = FALSE;          /* constrained move variables */
120
121 /* for comparison against MoveDelta - djhjr - 9/5/98 */
122 static int MenuOrigX, MenuOrigY;
123
124 /* Globals used to keep track of whether the mouse has moved during
125    a resize function. */
126 int ResizeOrigX;
127 int ResizeOrigY;
128
129 extern int origx, origy, origWidth, origHeight;
130
131 int MenuDepth = 0;              /* number of menus up */
132 static struct {
133         int x;
134         int y;
135 } MenuOrigins[MAXMENUDEPTH];
136 static Cursor LastCursor;
137
138 static char *actionHack = ""; /* Submitted by Michel Eyckmans */
139
140 /*
141  * context bitmaps for TwmWindows menu, f.showdesktop and f.showiconmgr
142  * djhjr - 9/10/99
143  */
144 static int have_twmwindows = -1;
145 static int have_showdesktop = -1;
146 static int have_showlist = -1;
147
148 void WarpAlongRing();
149
150 /* djhjr - 4/18/96 */
151 void Paint3DEntry();
152
153 static void Identify();
154 void PaintNormalEntry();
155
156 /* djhjr - 5/13/98 */
157 static TwmWindow *next_by_class();
158 static int warp_if_warpunmapped();
159
160 /* djhjr - 7/31/98 */
161 static void setup_restart();
162 void RestartVtwm();
163
164 /* djhjr - 9/21/99 */
165 int FindMenuOrFuncInBindings();
166 int FindMenuOrFuncInWindows();
167 int FindMenuInMenus();
168 int FindFuncInMenus();
169
170 /* djhjr - 9/21/99 */
171 void HideIconMgr();
172 void ShowIconMgr();
173
174 /* djhjr - 9/17/02 */
175 static int do_squeezetitle();
176
177 /* djhjr */
178 #undef MAX
179 /* DSE */
180 #define MAX(x,y) ((x)>(y)?(x):(y))
181
182 #define SHADOWWIDTH 5                   /* in pixels */
183
184 #define EDGE_OFFSET 5 /* DSE */
185
186 /* djhjr - 5/5/98
187 #define PULLDOWNMENU_OFFSET ((Scr->RightHandSidePulldownMenus)?\
188         (ActiveMenu->width - EDGE_OFFSET * 2 - Scr->pullW):\
189         (ActiveMenu->width >> 1)) * DSE *
190 */
191 #define PULLDOWNMENU_OFFSET ((Scr->RightHandSidePulldownMenus)?\
192         (JunkWidth - EDGE_OFFSET * 2 - Scr->pullW):\
193         (JunkWidth >> 1))
194
195 \f
196
197 /***********************************************************************
198  *
199  *  Procedure:
200  *      InitMenus - initialize menu roots
201  *
202  ***********************************************************************
203  */
204
205 void
206 InitMenus()
207 {
208     int i, j, k;
209     FuncKey *key, *tmp;
210
211     for (i = 0; i < MAX_BUTTONS+1; i++)
212         for (j = 0; j < NUM_CONTEXTS; j++)
213             for (k = 0; k < MOD_SIZE; k++)
214             {
215                 Scr->Mouse[i][j][k].func = F_NOFUNCTION;
216                 Scr->Mouse[i][j][k].item = NULL;
217             }
218
219     Scr->DefaultFunction.func = F_NOFUNCTION;
220     Scr->WindowFunction.func = F_NOFUNCTION;
221
222     if (FirstScreen)
223     {
224         for (key = Scr->FuncKeyRoot.next; key != NULL;)
225         {
226             free(key->name);
227             tmp = key;
228             key = key->next;
229             free((char *) tmp);
230         }
231         Scr->FuncKeyRoot.next = NULL;
232     }
233 }
234
235 \f
236
237 /***********************************************************************
238  *
239  *  Procedure:
240  *      AddFuncKey - add a function key to the list
241  *
242  *  Inputs:
243  *      name    - the name of the key
244  *      cont    - the context to look for the key press in
245  *      mods    - modifier keys that need to be pressed
246  *      func    - the function to perform
247  *      win_name- the window name (if any)
248  *      action  - the action string associated with the function (if any)
249  *
250  ***********************************************************************
251  */
252
253 Bool AddFuncKey (name, cont, mods, func, win_name, action)
254     char *name;
255     int cont, mods, func;
256     char *win_name;
257     char *action;
258 {
259     FuncKey *tmp;
260     KeySym keysym;
261     KeyCode keycode;
262
263     /*
264      * Don't let a 0 keycode go through, since that means AnyKey to the
265      * XGrabKey call in GrabKeys().
266      */
267     if ((keysym = XStringToKeysym(name)) == NoSymbol ||
268         (keycode = XKeysymToKeycode(dpy, keysym)) == 0)
269     {
270         return False;
271     }
272
273     /* see if there already is a key defined for this context */
274     for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
275     {
276         if (tmp->keysym == keysym &&
277             tmp->cont == cont &&
278             tmp->mods == mods)
279             break;
280     }
281
282     if (tmp == NULL)
283     {
284         tmp = (FuncKey *) malloc(sizeof(FuncKey));
285         tmp->next = Scr->FuncKeyRoot.next;
286         Scr->FuncKeyRoot.next = tmp;
287     }
288
289     tmp->name = name;
290     tmp->keysym = keysym;
291     tmp->keycode = keycode;
292     tmp->cont = cont;
293     tmp->mods = mods;
294     tmp->func = func;
295     tmp->win_name = win_name;
296     tmp->action = action;
297
298     return True;
299 }
300
301 \f
302
303 int CreateTitleButton (name, func, action, menuroot, rightside, append)
304     char *name;
305     int func;
306     char *action;
307     MenuRoot *menuroot;
308     Bool rightside;
309     Bool append;
310 {
311     TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
312
313     if (!tb) {
314         fprintf (stderr,
315                  "%s:  unable to allocate %d bytes for title button\n",
316                  ProgramName, sizeof(TitleButton));
317         return 0;
318     }
319
320     tb->next = NULL;
321     tb->name = name;                    /* note that we are not copying */
322
323 /* djhjr - 10/30/02
324     * djhjr - 4/19/96 *
325     tb->image = NULL;
326 */
327
328 /*    tb->bitmap = None;*/                      /* WARNING, values not set yet */
329     tb->width = 0;                      /* see InitTitlebarButtons */
330     tb->height = 0;                     /* ditto */
331     tb->func = func;
332     tb->action = action;
333     tb->menuroot = menuroot;
334     tb->rightside = rightside;
335     if (rightside) {
336         Scr->TBInfo.nright++;
337     } else {
338         Scr->TBInfo.nleft++;
339     }
340
341     /*
342      * Cases for list:
343      *
344      *     1.  empty list, prepend left       put at head of list
345      *     2.  append left, prepend right     put in between left and right
346      *     3.  append right                   put at tail of list
347      *
348      * Do not refer to widths and heights yet since buttons not created
349      * (since fonts not loaded and heights not known).
350      */
351     if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) {   /* 1 */
352                 tb->next = Scr->TBInfo.head;
353                 Scr->TBInfo.head = tb;
354     } else if (append && rightside) {   /* 3 */
355                 register TitleButton *t;
356
357                 for (t = Scr->TBInfo.head; t->next; t = t->next)
358                         ; /* SUPPRESS 530 */
359                 t->next = tb;
360                 tb->next = NULL;
361         } else {                                /* 2 */
362                 register TitleButton *t, *prev = NULL;
363
364                 for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next)
365                 prev = t;
366                 if (prev) {
367                 tb->next = prev->next;
368                 prev->next = tb;
369                 } else {
370                     tb->next = Scr->TBInfo.head;
371                     Scr->TBInfo.head = tb;
372                 }
373         }
374
375     return 1;
376 }
377
378 \f
379
380 /*
381  * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
382  * button.  If we can't find the button, then put in a question; if we can't
383  * find the question mark, something is wrong and we are probably going to be
384  * in trouble later on.
385  */
386 /* was of type 'void', now returns button height - djhjr - 12/10/98 */
387 int InitTitlebarButtons ()
388 {
389     Image *image;
390     TitleButton *tb;
391     int h, height;
392
393     /*
394      * initialize dimensions
395      */
396     Scr->TBInfo.width = (Scr->TitleHeight -
397                          2 * (Scr->FramePadding + Scr->ButtonIndent));
398
399 /* djhjr - 10/18/02
400         * djhjr - 4/19/96 *
401         * was 'Scr->use3Dtitles' - djhjr - 8/11/98 *
402     if (Scr->TitleBevelWidth > 0) 
403         Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
404                        ? ((Scr->TitlePadding + 1) / 2) : 0);
405     else
406
407     Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
408                        ? ((Scr->TitlePadding + 1) / 2) : 1);
409 */
410     Scr->TBInfo.pad = Scr->TitlePadding;
411
412     h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
413     /* djhjr - 10/30/02 */
414     if (!(h & 1)) h--;
415     height = h;
416
417     /*
418      * add in some useful buttons and bindings so that novices can still
419      * use the system. -- modified by DSE 
420      */
421
422     if (!Scr->NoDefaultTitleButtons) /* DSE */
423         {
424                 /* insert extra buttons */
425
426         /* djhjr - 4/19/96 */
427         /* was 'Scr->use3Dtitles' - djhjr - 8/11/98 */
428         if (Scr->TitleBevelWidth > 0) {
429             if (!CreateTitleButton (TBPM_3DDOT, F_ICONIFY, "", (MenuRoot *) NULL,
430                                 False, False))
431                 fprintf (stderr, "%s:  unable to add iconify button\n", ProgramName);
432             if (!CreateTitleButton (TBPM_3DRESIZE, F_RESIZE, "", (MenuRoot *) NULL,
433                                 True, True))
434                 fprintf (stderr, "%s:  unable to add resize button\n", ProgramName);
435         }
436         else {
437
438                 if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
439                                 False, False))
440                         fprintf(stderr,"%s:  unable to add iconify button\n",ProgramName);
441                 if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
442                                 True, True))
443                         fprintf(stderr,"%s:  unable to add resize button\n",ProgramName);
444         }
445         }
446         if (!Scr->NoDefaultMouseOrKeyboardBindings) /* DSE */
447                 {
448                 AddDefaultBindings ();
449                 }
450
451     ComputeCommonTitleOffsets ();
452
453 /* djhjr - 6/15/98 - moved it back to here... */
454 /* djhjr - 9/14/96 - moved to CreateWindowTitlebarButtons()... */
455         /*
456          * load in images and do appropriate centering
457          */
458     for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
459
460 /* djhjr - 4/19/96
461         tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height);
462         if (!tb->bitmap) {
463             tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height);
464             if (!tb->bitmap) {          * cannot happen (see util.c) *
465                 fprintf (stderr,
466                          "%s:  unable to add titlebar button \"%s\"\n",
467                          ProgramName, tb->name);
468             }
469         }
470 */
471 /* djhjr - 9/21/96
472         tb->image = GetImage (tb->name, Scr->TitleC);
473         if (!tb->image) {
474             tb->image = GetImage (TBPM_QUESTION, Scr->TitleC);
475             if (!tb->image) {           * cannot happen (see util.c) *
476                 fprintf (stderr, "%s:  unable to add titlebar button \"%s\"\n",
477                          ProgramName, tb->name);
478             }
479         }
480 */
481         /* added width and height - 10/30/02 */
482         image = GetImage (tb->name, h, h, Scr->ButtonBevelWidth * 2,
483                 (Scr->ButtonColorIsFrame) ? Scr->BorderColorC : Scr->TitleC);
484
485         tb->width  = image->width;
486
487         /* added 'height = ' - djhjr - 12/10/98 */
488         height = tb->height = image->height;
489
490         tb->dstx = (h - tb->width + 1) / 2;
491         if (tb->dstx < 0) {             /* clip to minimize copying */
492                 tb->srcx = -(tb->dstx);
493                 tb->width = h;
494                 tb->dstx = 0;
495         } else {
496                 tb->srcx = 0;
497         }
498         tb->dsty = (h - tb->height + 1) / 2;
499         if (tb->dsty < 0) {
500                 tb->srcy = -(tb->dsty);
501                 tb->height = h;
502                 tb->dsty = 0;
503         } else {
504                 tb->srcy = 0;
505         }
506
507     } /* for(...) */
508
509     /* djhjr - 12/10/98 */
510     return (height > h) ? height : h;
511 /* ...end of moved */
512 }
513
514 \f
515
516 /* djhjr - 10/30/02 */
517 void SetMenuIconPixmap(filename)
518     char *filename;
519 {
520         Scr->menuIconName = filename;
521 }
522
523 void PaintEntry(mr, mi, exposure)
524 MenuRoot *mr;
525 MenuItem *mi;
526 int exposure;
527 {
528         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
529     if (Scr->MenuBevelWidth > 0)
530         Paint3DEntry (mr, mi, exposure);
531
532         /* djhjr - 4/22/96 */
533         else
534
535     PaintNormalEntry (mr, mi, exposure);
536 }
537
538 void Paint3DEntry(mr, mi, exposure)
539 MenuRoot *mr;
540 MenuItem *mi;
541 int exposure;
542 {
543     int y_offset;
544     int text_y;
545     GC gc;
546
547 /* djhjr - 4/29/98
548     y_offset = mi->item_num * Scr->EntryHeight + 2;
549 */
550 /* djhjr - 5/22/00
551     y_offset = mi->item_num * Scr->EntryHeight + Scr->MenuBevelWidth;
552 */
553     y_offset = (mi->item_num - mr->top) * Scr->EntryHeight + Scr->MenuBevelWidth;
554
555 /* djhjr - 9/25/96
556     text_y = y_offset + Scr->MenuFont.y + 2;
557 */
558         text_y = y_offset + (((Scr->EntryHeight - Scr->MenuFont.height) / 2) + Scr->MenuFont.y);
559
560     if (mi->func != F_TITLE)
561         {
562                 int x, y;
563
564                 if (mi->state)
565                 {
566
567 /* djhjr - 9/25/96
568                         Draw3DBorder (mr->w, 2, y_offset, mr->width - 4, Scr->EntryHeight, 1, 
569                                 mi->highlight, off, True, False);
570 */
571 /* djhjr - 4/29/98
572                         Draw3DBorder (mr->w, 2, y_offset + 1, mr->width - 4, Scr->EntryHeight - 1, 1,
573                                 mi->highlight, off, True, False);
574 */
575                         Draw3DBorder (mr->w, Scr->MenuBevelWidth, y_offset + 1, mr->width - 2 * Scr->MenuBevelWidth, Scr->EntryHeight - 1, 1,
576                                 mi->highlight, off, True, False);
577
578                         /* font was font.font->fid - djhjr - 9/14/03 */
579                         FBF(mi->highlight.fore, mi->highlight.back, Scr->MenuFont);
580
581 /* djhjr - 4/29/98
582                         XDrawImageString(dpy, mr->w, Scr->NormalGC, mi->x + 2, text_y, mi->item, mi->strlen);
583 */
584 /* djhjr - 9/14/03 */
585 #ifndef NO_I18N_SUPPORT
586                         MyFont_DrawImageString(dpy, mr->w, &Scr->MenuFont,
587 #else
588                         XDrawImageString(dpy, mr->w,
589 #endif
590                                         Scr->NormalGC, mi->x + Scr->MenuBevelWidth, text_y, mi->item, mi->strlen);
591
592                         gc = Scr->NormalGC;
593                 }
594                 else
595                 {
596                         if (mi->user_colors || !exposure)
597                         {
598                                 XSetForeground (dpy, Scr->NormalGC, mi->normal.back);
599
600 /* djhjr - 9/25/96
601                                 XFillRectangle (dpy, mr->w, Scr->NormalGC, 2, y_offset,
602                                         mr->width - 4, Scr->EntryHeight);
603 */
604 /* djhjr - 4/29/98
605                                 XFillRectangle (dpy, mr->w, Scr->NormalGC, 2, y_offset + 1,
606                                         mr->width - 4, Scr->EntryHeight - 1);
607 */
608                                 XFillRectangle (dpy, mr->w, Scr->NormalGC, Scr->MenuBevelWidth, y_offset + 1,
609                                         mr->width - 2 * Scr->MenuBevelWidth, Scr->EntryHeight - 1);
610
611                                 /* font was font.font->fid - djhjr - 9/14/03 */
612                                 FBF (mi->normal.fore, mi->normal.back, Scr->MenuFont);
613
614                                 gc = Scr->NormalGC;
615                     }
616                         else
617                         {
618                                 gc = Scr->MenuGC;
619                         }
620
621 /* djhjr - 4/29/98
622                         XDrawImageString (dpy, mr->w, gc, mi->x + 2, text_y, mi->item, mi->strlen);
623 */
624 /* djhjr - 9/14/03 */
625 #ifndef NO_I18N_SUPPORT
626                         MyFont_DrawImageString (dpy, mr->w, &Scr->MenuFont,
627 #else
628                         XDrawImageString (dpy, mr->w,
629 #endif
630                                         gc, mi->x + Scr->MenuBevelWidth, text_y, mi->item, mi->strlen);
631
632                         if (mi->separated)
633                         {
634                                 /* this 'if (...)' - djhjr - 1/19/98 */
635                                 if (!Scr->BeNiceToColormap)
636                                 {
637                                         FB (Scr->MenuC.shadd, Scr->MenuC.shadc);
638
639 /* djhjr - 9/25/96
640                                         XDrawLine (dpy, mr->w, Scr->NormalGC, 1, y_offset + Scr->MenuFont.y + 5,
641                                                 mr->width - 2, y_offset + Scr->MenuFont.y + 5);
642 */
643 /* djhjr - 4/29/98
644                                         XDrawLine (dpy, mr->w, Scr->NormalGC, 1, y_offset + Scr->EntryHeight - 1,
645                                                 mr->width - 2, y_offset + Scr->EntryHeight - 1);
646 */
647                                         XDrawLine (dpy, mr->w, Scr->NormalGC, Scr->MenuBevelWidth + 1, y_offset + Scr->EntryHeight - 1,
648                                                 mr->width - Scr->MenuBevelWidth - 3, y_offset + Scr->EntryHeight - 1);
649                                 }
650
651                                 FB (Scr->MenuC.shadc, Scr->MenuC.shadd);
652
653 /* djhjr - 9/25/96
654                                 XDrawLine (dpy, mr->w, Scr->NormalGC, 2, y_offset + Scr->MenuFont.y + 6,
655                                         mr->width - 3, y_offset + Scr->MenuFont.y + 6);
656 */
657 /* djhjr - 4/29/98
658                                 XDrawLine (dpy, mr->w, Scr->NormalGC, 2, y_offset + Scr->EntryHeight,
659                                         mr->width - 3, y_offset + Scr->EntryHeight);
660 */
661                                 XDrawLine (dpy, mr->w, Scr->NormalGC, Scr->MenuBevelWidth + 2, y_offset + Scr->EntryHeight,
662                                         mr->width - Scr->MenuBevelWidth - 2, y_offset + Scr->EntryHeight);
663                         }
664                 }
665
666                 if (mi->func == F_MENU)
667                 {
668 /* djhjr - 10/30/02
669                         * create the pull right pixmap if needed *
670                         if (Scr->pullPm == None)
671                         {
672                                 Scr->pullPm = Create3DMenuIcon (Scr->MenuFont.height, &Scr->pullW,
673                                         &Scr->pullH, Scr->MenuC);
674 */
675                                 Image *image;
676                                 Pixel back;
677
678                                 back = Scr->MenuC.back;
679                                 if (mi->state)
680                                         Scr->MenuC.back = mi->highlight.back;
681                                 else
682                                         Scr->MenuC.back = mi->normal.back;
683
684                                 Scr->pullW = Scr->pullH = Scr->MenuFont.height;
685                                 image = GetImage(Scr->menuIconName,
686                                                  Scr->pullW, Scr->pullH,
687                                                  0, Scr->MenuC);
688
689                                 Scr->MenuC.back = back;
690 /* djhjr - 10/30/02
691                         }
692 */
693
694 /* djhjr - 4/29/98
695                         x = mr->width - Scr->pullW - 5;
696 */
697                         x = mr->width - Scr->pullW - Scr->MenuBevelWidth - EDGE_OFFSET;
698
699 /* djhjr - 9/25/96
700                         y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2) + 2;
701 */
702                         y = y_offset + ((Scr->EntryHeight - Scr->pullH) / 2) + 1;
703
704                         XCopyArea (dpy, image->pixmap, mr->w, gc, 0, 0, Scr->pullW, Scr->pullH, x, y);
705                 }
706         }
707         else
708         {
709
710 /* djhjr - 4/29/96
711                 Draw3DBorder (mr->w, 2, y_offset, mr->width - 4, Scr->EntryHeight, 1, 
712                         mi->normal, off, True, False);
713 */
714 /* djhjr - 4/29/98
715                 Draw3DBorder (mr->w, 2, y_offset, mr->width - 4, Scr->EntryHeight + 1, 1, 
716                         mi->normal, off, True, False);
717 */
718                 Draw3DBorder (mr->w, Scr->MenuBevelWidth, y_offset, mr->width - 2 * Scr->MenuBevelWidth, Scr->EntryHeight + 1, 1, 
719                         mi->normal, off, True, False);
720
721 /* djhjr - 4/29/96
722                 FBF (mi->normal.fore, mi->normal.back, Scr->MenuFont.font->fid);
723 */
724                 /* font was font.font->fid - djhjr - 9/14/03 */
725                 FBF (mi->normal.fore, mi->normal.back, Scr->MenuTitleFont);
726
727 /* djhjr - 9/25/96
728                 XDrawImageString (dpy, mr->w, Scr->NormalGC, mi->x + 2, text_y, mi->item, mi->strlen);
729 */
730 /* djhjr - 9/14/03 */
731 #ifndef NO_I18N_SUPPORT
732                 MyFont_DrawImageString (dpy, mr->w, &Scr->MenuTitleFont,
733 #else
734                 XDrawImageString (dpy, mr->w,
735 #endif
736                                 Scr->NormalGC, mi->x, text_y, mi->item, mi->strlen);
737         }
738 }
739     
740 \f
741
742 void PaintNormalEntry(mr, mi, exposure)
743 MenuRoot *mr;
744 MenuItem *mi;
745 int exposure;
746 {
747     int y_offset;
748     int text_y;
749     GC gc;
750
751 /* djhjr - 5/22/00
752     y_offset = mi->item_num * Scr->EntryHeight;
753 */
754     y_offset = (mi->item_num - mr->top) * Scr->EntryHeight;
755
756 /* djhjr - 9/26/96
757     text_y = y_offset + Scr->MenuFont.y;
758 */
759         text_y = y_offset + (((Scr->EntryHeight - Scr->MenuFont.height) / 2) + Scr->MenuFont.y);
760
761         if (mi->func != F_TITLE)
762         {
763                 int x, y;
764
765                 if (mi->state)
766                 {
767                         XSetForeground(dpy, Scr->NormalGC, mi->highlight.back);
768
769                         XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
770                                 mr->width, Scr->EntryHeight);
771
772                         /* font was font.font->fid - djhjr - 9/14/03 */
773                         FBF(mi->highlight.fore, mi->highlight.back, Scr->MenuFont);
774
775 /* djhjr - 9/14/03 */
776 #ifndef NO_I18N_SUPPORT
777                         MyFont_DrawString(dpy, mr->w, &Scr->MenuFont,
778 #else
779                         XDrawString(dpy, mr->w,
780 #endif
781                                 Scr->NormalGC, mi->x,
782                                 text_y, mi->item, mi->strlen);
783
784                         gc = Scr->NormalGC;
785                 }
786                 else
787                 {
788                         if (mi->user_colors || !exposure)
789                         {
790                                 XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
791
792                                 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
793                                         mr->width, Scr->EntryHeight);
794
795                                 /* font was font.font->fid - djhjr - 9/14/03 */
796                                 FBF(mi->normal.fore, mi->normal.back, Scr->MenuFont);
797
798                                 gc = Scr->NormalGC;
799                         }
800                         else
801                         {
802                                 gc = Scr->MenuGC;
803                         }
804
805 /* djhjr - 9/14/03 */
806 #ifndef NO_I18N_SUPPORT
807                         MyFont_DrawString(dpy, mr->w, &Scr->MenuFont,
808 #else
809                         XDrawString(dpy, mr->w,
810 #endif
811                                         gc, mi->x, text_y, mi->item, mi->strlen);
812
813                         if (mi->separated)
814
815 /* djhjr - 9/26/96
816                                 XDrawLine (dpy, mr->w, gc, 0, y_offset + Scr->MenuFont.y + 5,
817                                         mr->width, y_offset + Scr->MenuFont.y + 5);
818 */
819                                 XDrawLine (dpy, mr->w, gc, 0, y_offset + Scr->EntryHeight - 1,
820                                         mr->width, y_offset + Scr->EntryHeight - 1);
821                 }
822
823                 if (mi->func == F_MENU)
824                 {
825 /* djhjr - 10/30/02
826                         * create the pull right pixmap if needed *
827                         if (Scr->pullPm == None)
828                         {
829                                 Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
830                                         &Scr->pullW, &Scr->pullH);
831 */
832                                 Image *image;
833                                 ColorPair cp;
834
835                                 cp.back = Scr->MenuC.back;
836                                 if (strncmp(Scr->menuIconName, ":xpm:", 5) != 0)
837                                 {
838                                         cp.fore = Scr->MenuC.fore;
839                                         Scr->MenuC.fore = (mi->state) ? mi->highlight.fore : mi->normal.fore;
840                                         Scr->MenuC.back = (mi->state) ? mi->highlight.back : mi->normal.back;
841                                 }
842                                 else
843                                         Scr->MenuC.back = (mi->state) ? mi->highlight.back : mi->normal.back;
844
845                                 Scr->pullW = Scr->pullH = Scr->MenuFont.height;
846                                 image = GetImage(Scr->menuIconName,
847                                                  Scr->pullW, Scr->pullH,
848                                                  0, Scr->MenuC);
849
850                                 Scr->MenuC.back = cp.back;
851                                 if (strncmp(Scr->menuIconName, ":xpm:", 5) != 0)
852                                         Scr->MenuC.fore = cp.fore;
853 /* djhjr - 10/30/02
854                         }
855 */
856
857                         x = mr->width - Scr->pullW - EDGE_OFFSET;
858
859 /* djhjr - 9/26/96
860                         y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
861 */
862                         y = y_offset + ((Scr->EntryHeight - Scr->pullH) / 2);
863
864 /* djhjr - 10/30/02
865                         XCopyPlane(dpy, Scr->pullPm->pixmap, mr->w, gc, 0, 0,
866                                 Scr->pullW, Scr->pullH, x, y, 1);
867 */
868                         XCopyArea (dpy, image->pixmap, mr->w, gc, 0, 0,
869                                 Scr->pullW, Scr->pullH, x, y);
870                 }
871         }
872         else
873         {
874                 int y;
875
876                 XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
877
878                 /* fill the rectangle with the title background color */
879                 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
880                         mr->width, Scr->EntryHeight);
881
882                 XSetForeground(dpy, Scr->NormalGC, mi->normal.fore);
883
884                 /* now draw the dividing lines */
885                 if (y_offset)
886                         XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
887                                 mr->width, y_offset);
888
889                 y = ((mi->item_num+1) * Scr->EntryHeight)-1;
890                 XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
891
892 /* djhjr - 4/29/96
893                 FBF(mi->normal.fore, mi->normal.back, Scr->MenuFont.font->fid);
894 */
895                 /* font was font.font->fid - djhjr - 9/14/03 */
896                 FBF (mi->normal.fore, mi->normal.back, Scr->MenuTitleFont);
897
898                 /* finally render the title */
899 /* djhjr - 9/14/03 */
900 #ifndef NO_I18N_SUPPORT
901                 MyFont_DrawString(dpy, mr->w, &Scr->MenuTitleFont,
902 #else
903                 XDrawString(dpy, mr->w,
904 #endif
905                         Scr->NormalGC, mi->x, text_y, mi->item, mi->strlen);
906         }
907 }
908
909 void PaintMenu(mr, e)
910 MenuRoot *mr;
911 XEvent *e;
912 {
913     MenuItem *mi;
914         /* djhjr - 5/22/00 */
915         int y_offset;
916
917         /* djhjr - 4/22/96 */
918         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
919     if (Scr->MenuBevelWidth > 0) {
920 /* djhjr - 4/29/98
921         Draw3DBorder (mr->w, 0, 0, mr->width, mr->height, 2, Scr->MenuC, off, False, False);
922 */
923         Draw3DBorder (mr->w, 0, 0, mr->width, mr->height, Scr->MenuBevelWidth, Scr->MenuC, off, False, False);
924     }
925
926     for (mi = mr->first; mi != NULL; mi = mi->next)
927     {
928         /* djhjr - 5/22/00 */
929         if (mi->item_num < mr->top) continue;
930
931 /* djhjr - 5/22/00
932         int y_offset = mi->item_num * Scr->EntryHeight;
933 */
934         y_offset = (mi->item_num - mr->top) * Scr->EntryHeight;
935
936         /* djhjr - 5/22/00 */
937         if (y_offset + Scr->EntryHeight > mr->height) break;
938
939         /* some servers want the previous entry redrawn - djhjr - 10/24/00 */
940         if (Scr->MenuBevelWidth > 0) y_offset += Scr->EntryHeight;
941
942         /*
943          * Be smart about handling the expose, redraw only the entries
944          * that we need to.
945          */
946         /* those servers want the next entry redrawn, too - djhjr - 10/24/00 */
947         if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
948             (e->xexpose.y + e->xexpose.height) > y_offset - ((mr->shadow) ? Scr->EntryHeight : 0))
949         {
950             PaintEntry(mr, mi, True);
951         }
952     }
953     XSync(dpy, 0);
954 }
955
956 \f
957
958 static Bool fromMenu;
959
960 extern int GlobalFirstTime; /* for StayUpMenus -- PF */
961
962 void UpdateMenu()
963 {
964         MenuItem *mi;
965     int i, x, y, x_root, y_root, entry;
966         int done;
967         MenuItem *badItem = NULL;
968         static int firstTime = True;
969
970         fromMenu = TRUE;
971
972         while (TRUE)
973         {       /* block until there is an event */
974 #ifdef NEVER /* see the '#else' - Steve Ratcliffe */
975 #if 0
976                 if (!menuFromFrameOrWindowOrTitlebar && ! Scr->StayUpMenus) {
977                         XMaskEvent(dpy,
978                                 ButtonPressMask | ButtonReleaseMask |
979                                 EnterWindowMask | ExposureMask |
980                                 VisibilityChangeMask | LeaveWindowMask |
981                                 ButtonMotionMask, &Event);
982                 }
983                 if (Event.type == MotionNotify) {
984                         /* discard any extra motion events before a release */
985                         while(XCheckMaskEvent(dpy,
986                                         ButtonMotionMask | ButtonReleaseMask, &Event))
987                                 if (Event.type == ButtonRelease)
988                                         break;
989                 }
990 #else
991                 while (XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
992                                 EnterWindowMask | ExposureMask, &Event))
993                 {       /* taken from tvtwm */
994 #endif /* 0 */
995 #else
996                 /* Submitted by Steve Ratcliffe */
997                 XNextEvent(dpy, &Event);
998 #endif /* NEVER */
999
1000                 if (!DispatchEvent ()) continue;
1001
1002                 if (Event.type == ButtonRelease )
1003                 {       if (Scr->StayUpMenus)
1004                         {
1005                                 if (firstTime == True)
1006                                 {       /* it was the first release of the button */
1007                                         firstTime = False;
1008                                 }
1009                                 else
1010                                 {       /* thats the second we need to return now */
1011                                         firstTime = True;
1012                                         menuFromFrameOrWindowOrTitlebar = FALSE;
1013                                         fromMenu = FALSE;
1014                                         return;
1015                                 }
1016                         }
1017                         else
1018                         {       /* not stay-up */
1019                                 menuFromFrameOrWindowOrTitlebar = FALSE;
1020                                 fromMenu = FALSE;
1021                                 return;
1022                         }
1023                 }
1024
1025                 if (Cancel) return;
1026
1027 #ifdef NEVER /* see the above - Steve Ratcliffe */
1028                 }
1029 #endif
1030
1031                 /* re-instated - Steve Ratcliffe */
1032                 if (Event.type != MotionNotify)
1033                         continue;
1034
1035                 /* if we haven't received the enter notify yet, wait */
1036                 if (!ActiveMenu || !ActiveMenu->entered)
1037                         continue;
1038
1039                 done = FALSE;
1040                 XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
1041                                 &x_root, &y_root, &x, &y, &JunkMask);
1042
1043                 /* djhjr - 9/5/98 */
1044                 if (!ActiveItem)
1045                         if (abs(x_root - MenuOrigX) < Scr->MoveDelta &&
1046                                         abs(y_root - MenuOrigY) < Scr->MoveDelta)
1047                                 continue;
1048
1049 #if 0
1050                 /* if we haven't recieved the enter notify yet, wait */
1051                 if (ActiveMenu && !ActiveMenu->entered)
1052                         continue;
1053 #endif
1054
1055                 XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
1056
1057                 JunkWidth = ActiveMenu->width;
1058                 JunkHeight = ActiveMenu->height;
1059                 /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1060                 if (Scr->MenuBevelWidth > 0)
1061                 {
1062                         x -= Scr->MenuBevelWidth;
1063                         y -= Scr->MenuBevelWidth;
1064
1065                         JunkWidth -= 2 * Scr->MenuBevelWidth;
1066                         JunkHeight -= Scr->MenuBevelWidth;
1067                 }
1068
1069 /* djhjr - 5/22/00
1070                 if (x < 0 || y < 0 || x >= JunkWidth || y >= JunkHeight)
1071 */
1072                 if ((x < 0 || y < 0 || x >= JunkWidth || y >= JunkHeight) ||
1073                                 (ActiveMenu->too_tall && (y < Scr->MenuScrollBorderWidth ||
1074                                                 y > JunkHeight - Scr->MenuScrollBorderWidth)))
1075                 {
1076                         if (ActiveItem && ActiveItem->func != F_TITLE)
1077                         {
1078                                 ActiveItem->state = 0;
1079                                 PaintEntry(ActiveMenu, ActiveItem, False);
1080                         }
1081                         ActiveItem = NULL;
1082
1083                         /* menu scrolling - djhjr - 5/22/00 */
1084                         if (ActiveMenu->too_tall && x >= 0 && x < JunkWidth)
1085                         {
1086                                 short j = ActiveMenu->top;
1087
1088                                 if (y < Scr->MenuScrollBorderWidth)
1089                                 {
1090                                         if (ActiveMenu->top - Scr->MenuScrollJump < 0)
1091                                                 continue;
1092                                         else
1093                                                 j -= Scr->MenuScrollJump;
1094                                 }
1095                                 else if (y > JunkHeight - Scr->MenuScrollBorderWidth)
1096                                 {
1097                                         int k = JunkHeight / Scr->EntryHeight;
1098
1099                                         if (ActiveMenu->top + k >= ActiveMenu->items)
1100                                                 continue;
1101                                         else
1102                                                 j += Scr->MenuScrollJump;
1103                                 }
1104
1105                                 if (ActiveMenu->top != j)
1106                                 {
1107                                         ActiveMenu->top = j;
1108                                         XClearArea(dpy, ActiveMenu->w, 0, 0, 0, 0, True);
1109                                 }
1110                         }
1111
1112                         continue;
1113                 }
1114
1115                 /* look for the entry that the mouse is in */
1116 /* djhjr - 5/22/00
1117                 entry = y / Scr->EntryHeight;
1118 */
1119                 entry = (y / Scr->EntryHeight) + ActiveMenu->top;
1120                 for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
1121                 {
1122                         if (i == entry)
1123                                 break;
1124                 }
1125
1126                 /* if there is an active item, we might have to turn it off */
1127                 if (ActiveItem)
1128                 {
1129                         /* is the active item the one we are on ? */
1130                         if (ActiveItem->item_num == entry && ActiveItem->state)
1131                                 done = TRUE;
1132
1133                         /* if we weren't on the active entry, let's turn the old
1134                          * active one off
1135                          */
1136                         if (!done && ActiveItem->func != F_TITLE)
1137                         {
1138                                 ActiveItem->state = 0;
1139                                 PaintEntry(ActiveMenu, ActiveItem, False);
1140                         }
1141                 }
1142
1143                 /* djhjr - 5/22/00 */
1144                 if (ActiveMenu->too_tall && y + Scr->EntryHeight > JunkHeight)
1145                         continue;
1146
1147                 /* if we weren't on the active item, change the active item and turn
1148                  * it on
1149                  */
1150                 if (!done)
1151                 {
1152                         ActiveItem = mi;
1153
1154 /* djhjr - 5/20/98
1155                         if (ActiveItem->func != F_TITLE && !ActiveItem->state)
1156 */
1157                         if (ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state)
1158                         {
1159                                 ActiveItem->state = 1;
1160                                 PaintEntry(ActiveMenu, ActiveItem, False);
1161
1162                                 if (Scr->StayUpOptionalMenus)            /* PF */
1163                                         GlobalFirstTime = firstTime = False; /* PF */
1164                 
1165                         }
1166                 }
1167
1168                 /* now check to see if we were over the arrow of a pull right entry */
1169
1170 /* djhjr - 5/20/98
1171                 if (ActiveItem->func == F_MENU &&
1172 */
1173                 if (ActiveItem && ActiveItem->func == F_MENU && 
1174
1175 /*                      ((ActiveMenu->width - x) < (ActiveMenu->width >> 1))) */
1176                         ( x > PULLDOWNMENU_OFFSET )) /* DSE */
1177                 {
1178                         MenuRoot *save = ActiveMenu;
1179                         int savex = MenuOrigins[MenuDepth - 1].x;
1180                         int savey = MenuOrigins[MenuDepth - 1].y;
1181
1182                         if (MenuDepth < MAXMENUDEPTH) {
1183                                 PopUpMenu (ActiveItem->sub,
1184                                    (savex + PULLDOWNMENU_OFFSET), /* DSE */
1185                                    (savey + ActiveItem->item_num * Scr->EntryHeight)
1186                                    /*(savey + ActiveItem->item_num * Scr->EntryHeight +
1187                                         (Scr->EntryHeight >> 1))*/, False);
1188                         } else if (!badItem) {
1189                                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
1190                                 badItem = ActiveItem;
1191                         }
1192
1193                         /* if the menu did get popped up, unhighlight the active item */
1194                         if (save != ActiveMenu && ActiveItem->state)
1195                         {
1196                                 ActiveItem->state = 0;
1197                                 PaintEntry(save, ActiveItem, False);
1198                                 ActiveItem = NULL;
1199                         }
1200                 }
1201
1202                 if (badItem != ActiveItem) badItem = NULL;
1203                 XFlush(dpy);
1204         }
1205 }
1206
1207 \f
1208
1209 /***********************************************************************
1210  *
1211  *      Procedure:
1212  *      NewMenuRoot - create a new menu root
1213  *
1214  *      Returned Value:
1215  *      (MenuRoot *)
1216  *
1217  *      Inputs:
1218  *      name    - the name of the menu root
1219  *
1220  ***********************************************************************
1221  */
1222
1223 MenuRoot *
1224 NewMenuRoot(name)
1225         char *name;
1226 {
1227         MenuRoot *tmp;
1228
1229 #define UNUSED_PIXEL ((unsigned long) (~0))     /* more than 24 bits */
1230
1231         tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
1232
1233 /* djhjr - 5/22/96
1234         tmp->hi_fore = UNUSED_PIXEL;
1235         tmp->hi_back = UNUSED_PIXEL;
1236 */
1237         tmp->highlight.fore = UNUSED_PIXEL;
1238         tmp->highlight.back = UNUSED_PIXEL;
1239
1240         tmp->name = name;
1241         tmp->prev = NULL;
1242         tmp->first = NULL;
1243         tmp->last = NULL;
1244         tmp->items = 0;
1245         tmp->width = 0;
1246         tmp->mapped = NEVER_MAPPED;
1247         tmp->pull = FALSE;
1248         tmp->w = None;
1249         tmp->shadow = None;
1250         tmp->real_menu = FALSE;
1251
1252         /* djhjr - 5/22/00 */
1253         tmp->too_tall = 0;
1254         tmp->top = 0;
1255
1256         if (Scr->MenuList == NULL)
1257         {
1258         Scr->MenuList = tmp;
1259         Scr->MenuList->next = NULL;
1260         }
1261
1262         if (Scr->LastMenu == NULL)
1263         {
1264         Scr->LastMenu = tmp;
1265         Scr->LastMenu->next = NULL;
1266         }
1267         else
1268         {
1269         Scr->LastMenu->next = tmp;
1270         Scr->LastMenu = tmp;
1271         Scr->LastMenu->next = NULL;
1272         }
1273
1274 /* djhjr - 5/4/98
1275         if (strcmp(name, TWM_WINDOWS) == 0)
1276 */
1277         if (strcmp(name, TWM_WINDOWS) == 0 || strcmp(name, VTWM_WINDOWS) == 0)
1278         Scr->Windows = tmp;
1279
1280         return (tmp);
1281 }
1282
1283 \f
1284
1285 /***********************************************************************
1286  *
1287  *      Procedure:
1288  *      AddToMenu - add an item to a root menu
1289  *
1290  *      Returned Value:
1291  *      (MenuItem *)
1292  *
1293  *      Inputs:
1294  *      menu    - pointer to the root menu to add the item
1295  *      item    - the text to appear in the menu
1296  *      action  - the string to possibly execute
1297  *      sub     - the menu root if it is a pull-right entry
1298  *      func    - the numeric function
1299  *      fore    - foreground color string
1300  *      back    - background color string
1301  *
1302  ***********************************************************************
1303  */
1304
1305 MenuItem *
1306 AddToMenu(menu, item, action, sub, func, fore, back)
1307         MenuRoot *menu;
1308         char *item, *action;
1309         MenuRoot *sub;
1310         int func;
1311         char *fore, *back;
1312 {
1313         MenuItem *tmp;
1314         int width;
1315         MyFont *font; /* DSE */
1316
1317 #ifdef DEBUG_MENUS
1318         fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
1319         item, action, sub, func);
1320 #endif
1321
1322         tmp = (MenuItem *) malloc(sizeof(MenuItem));
1323         tmp->root = menu;
1324
1325         if (menu->first == NULL)
1326         {
1327         menu->first = tmp;
1328         tmp->prev = NULL;
1329         }
1330         else
1331         {
1332         menu->last->next = tmp;
1333         tmp->prev = menu->last;
1334         }
1335         menu->last = tmp;
1336
1337         tmp->item = item;
1338         tmp->strlen = strlen(item);
1339         tmp->action = action;
1340         tmp->next = NULL;
1341         tmp->sub = NULL;
1342         tmp->state = 0;
1343         tmp->func = func;
1344
1345         /* djhjr - 4/22/96 */
1346         tmp->separated = 0;
1347
1348     if ( func == F_TITLE && (Scr->MenuTitleFont.name != NULL) ) /* DSE */
1349                 font= &(Scr->MenuTitleFont);
1350     else
1351                 font= &(Scr->MenuFont);
1352
1353         if (!Scr->HaveFonts) CreateFonts();
1354 /* djhjr - 9/14/03 */
1355 #ifndef NO_I18N_SUPPORT
1356         width = MyFont_TextWidth(font,
1357 #else
1358         width = XTextWidth(font->font,
1359 #endif
1360                         item, tmp->strlen);
1361         if (width <= 0)
1362         width = 1;
1363         if (width > menu->width)
1364         menu->width = width;
1365
1366         tmp->user_colors = FALSE;
1367         if (Scr->Monochrome == COLOR && fore != NULL)
1368         {
1369         int save;
1370
1371         save = Scr->FirstTime;
1372         Scr->FirstTime = TRUE;
1373
1374 /* djhjr - 4/22/96
1375         GetColor(COLOR, &tmp->fore, fore);
1376         GetColor(COLOR, &tmp->back, back);
1377 */
1378         GetColor(COLOR, &tmp->normal.fore, fore);
1379         GetColor(COLOR, &tmp->normal.back, back);
1380
1381         /* djhjr - 4/22/96 */
1382         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1383         /* rem'd 'Scr->MenuBevelWidth' djhjr - 10/30/02 */
1384         if (/*Scr->MenuBevelWidth > 0 && */!Scr->BeNiceToColormap) GetShadeColors (&tmp->normal);
1385
1386         Scr->FirstTime = save;
1387         tmp->user_colors = TRUE;
1388         }
1389         if (sub != NULL)
1390         {
1391         tmp->sub = sub;
1392         menu->pull = TRUE;
1393         }
1394         tmp->item_num = menu->items++;
1395
1396         return (tmp);
1397 }
1398
1399 \f
1400
1401 void MakeMenus()
1402 {
1403         MenuRoot *mr;
1404
1405         for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
1406         {
1407         if (mr->real_menu == FALSE)
1408                 continue;
1409
1410         MakeMenu(mr);
1411         }
1412 }
1413
1414 \f
1415
1416 void MakeMenu(mr)
1417 MenuRoot *mr;
1418 {
1419         MenuItem *start, *end, *cur, *tmp;
1420         XColor f1, f2, f3;
1421         XColor b1, b2, b3;
1422         XColor save_fore, save_back;
1423         int num, i;
1424         int fred, fgreen, fblue;
1425         int bred, bgreen, bblue;
1426         int width;
1427
1428         /* djhjr - 4/22/96 */
1429         int borderwidth;
1430
1431         unsigned long valuemask;
1432         XSetWindowAttributes attributes;
1433         Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
1434         MyFont *titleFont;
1435         
1436         if ( Scr->MenuTitleFont.name != NULL ) /* DSE */
1437                 {
1438                 Scr->EntryHeight = MAX(Scr->MenuFont.height,
1439                                        Scr->MenuTitleFont.height) + 4;
1440                 titleFont = &(Scr->MenuTitleFont);
1441                 }
1442         else
1443                 {
1444                 Scr->EntryHeight = Scr->MenuFont.height + 4;
1445                 titleFont= &(Scr->MenuFont);
1446                 }
1447
1448
1449         /* lets first size the window accordingly */
1450         if (mr->mapped == NEVER_MAPPED)
1451         {
1452         if (mr->pull == TRUE)
1453         {
1454                 mr->width += 16 + 2 * EDGE_OFFSET; /* DSE */
1455         }
1456
1457 /* djhjr - 4/29/98
1458         * djhjr - 9/18/96 *
1459         if (Scr->use3Dmenus) mr->width += 4;
1460 */
1461         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1462         if (Scr->MenuBevelWidth > 0) mr->width += 2 * Scr->MenuBevelWidth;
1463
1464         width = mr->width + 2 * EDGE_OFFSET; /* DSE */
1465
1466         for (cur = mr->first; cur != NULL; cur = cur->next)
1467         {
1468                 if (cur->func != F_TITLE)
1469                 cur->x = EDGE_OFFSET; /* DSE */
1470                 else
1471                 {
1472                 cur->x = width -
1473 /* djhjr - 9/14/03 */
1474 #ifndef NO_I18N_SUPPORT
1475                         MyFont_TextWidth(titleFont,
1476 #else
1477                         XTextWidth(titleFont->font,
1478 #endif
1479                                 cur->item, cur->strlen);
1480                 cur->x /= 2;
1481                 }
1482         }
1483         mr->height = mr->items * Scr->EntryHeight;
1484
1485 /* djhjr - 4/29/98
1486         * djhjr - 4/22/96 *
1487         if (Scr->use3Dmenus) mr->height += 4;
1488 */
1489         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1490         if (Scr->MenuBevelWidth > 0) mr->height += 2 * Scr->MenuBevelWidth;
1491
1492         /* djhjr - 4/22/96 */
1493         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1494         borderwidth = (Scr->MenuBevelWidth > 0) ? 0 : 1;
1495
1496         /* djhjr - 5/22/00 */
1497         if (mr->height > Scr->MyDisplayHeight)
1498         {
1499                 mr->too_tall = 1;
1500                 mr->height = Scr->MyDisplayHeight - borderwidth * 2;
1501         }
1502
1503         /* added this 'if () ... else' - djhjr - 4/29/98 */
1504         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1505         if (Scr->MenuBevelWidth > 0)
1506                 mr->width += 2 * Scr->MenuBevelWidth + 6;
1507         else
1508                 mr->width += 10;
1509
1510         if (Scr->Shadow)
1511         {
1512                 /*
1513                  * Make sure that you don't draw into the shadow window or else
1514                  * the background bits there will get saved
1515                  */
1516                 valuemask = (CWBackPixel | CWBorderPixel);
1517                 attributes.background_pixel = Scr->MenuShadowColor;
1518                 attributes.border_pixel = Scr->MenuShadowColor;
1519                 if (Scr->SaveUnder) {
1520                 valuemask |= CWSaveUnder;
1521                 attributes.save_under = True;
1522                 }
1523                 mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
1524                                         (unsigned int) mr->width,
1525                                         (unsigned int) mr->height,
1526                                         (unsigned int)0,
1527                                         CopyFromParent,
1528                                         (unsigned int) CopyFromParent,
1529                                         (Visual *) CopyFromParent,
1530                                         valuemask, &attributes);
1531         }
1532
1533         valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
1534         attributes.background_pixel = Scr->MenuC.back;
1535         attributes.border_pixel = Scr->MenuC.fore;
1536         attributes.event_mask = (ExposureMask | EnterWindowMask);
1537         if (Scr->SaveUnder) {
1538                 valuemask |= CWSaveUnder;
1539                 attributes.save_under = True;
1540         }
1541         if (Scr->BackingStore) {
1542                 valuemask |= CWBackingStore;
1543                 attributes.backing_store = Always;
1544         }
1545
1546         mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
1547
1548 /* djhjr - 4/22/96
1549                                    (unsigned int) mr->height, (unsigned int) 1,
1550 */
1551                                    (unsigned int) mr->height, (unsigned int) borderwidth,
1552
1553                                    CopyFromParent, (unsigned int) CopyFromParent,
1554                                    (Visual *) CopyFromParent,
1555                                    valuemask, &attributes);
1556
1557
1558         XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
1559         XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
1560
1561         mr->mapped = UNMAPPED;
1562         }
1563
1564         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1565     if (Scr->MenuBevelWidth > 0 && (Scr->Monochrome == COLOR) &&  (mr->highlight.back == UNUSED_PIXEL)) {
1566         XColor xcol;
1567         char colname [32];
1568         short save;
1569
1570         xcol.pixel = Scr->MenuC.back;
1571         XQueryColor (dpy, cmap, &xcol);
1572         sprintf (colname, "#%04x%04x%04x", 
1573                 5 * (xcol.red / 6), 5 * (xcol.green / 6), 5 * (xcol.blue / 6));
1574         save = Scr->FirstTime;
1575         Scr->FirstTime = True;
1576         GetColor (Scr->Monochrome, &mr->highlight.back, colname);
1577         Scr->FirstTime = save;
1578     }
1579
1580         /* djhjr - 4/22/96 */
1581         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1582     if (Scr->MenuBevelWidth > 0 && (Scr->Monochrome == COLOR) && (mr->highlight.fore == UNUSED_PIXEL)) {
1583         XColor xcol;
1584         char colname [32];
1585         short save;
1586         xcol.pixel = Scr->MenuC.fore;
1587         XQueryColor (dpy, cmap, &xcol);
1588         sprintf (colname, "#%04x%04x%04x",
1589                 5 * (xcol.red / 6), 5 * (xcol.green / 6), 5 * (xcol.blue / 6));
1590         save = Scr->FirstTime;
1591         Scr->FirstTime = True;
1592         GetColor (Scr->Monochrome, &mr->highlight.fore, colname);
1593         Scr->FirstTime = save;
1594     }
1595         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1596     if (Scr->MenuBevelWidth > 0 && !Scr->BeNiceToColormap) GetShadeColors (&mr->highlight);
1597
1598         /* get the default colors into the menus */
1599         for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
1600         {
1601 /* djhjr - 4/22/96
1602         if (!tmp->user_colors) {
1603                 if (tmp->func != F_TITLE) {
1604                 tmp->fore = Scr->MenuC.fore;
1605                 tmp->back = Scr->MenuC.back;
1606                 } else {
1607                 tmp->fore = Scr->MenuTitleC.fore;
1608                 tmp->back = Scr->MenuTitleC.back;
1609                 }
1610         }
1611
1612         if (mr->hi_fore != UNUSED_PIXEL)
1613         {
1614                 tmp->hi_fore = mr->hi_fore;
1615                 tmp->hi_back = mr->hi_back;
1616         }
1617         else
1618         {
1619                 tmp->hi_fore = tmp->back;
1620                 tmp->hi_back = tmp->fore;
1621         }
1622 */
1623         if (!tmp->user_colors) {
1624             if (tmp->func != F_TITLE) {
1625                 tmp->normal.fore = Scr->MenuC.fore;
1626                 tmp->normal.back = Scr->MenuC.back;
1627             } else {
1628                 tmp->normal.fore = Scr->MenuTitleC.fore;
1629                 tmp->normal.back = Scr->MenuTitleC.back;
1630             }
1631         }
1632
1633         if (mr->highlight.fore != UNUSED_PIXEL)
1634         {
1635             tmp->highlight.fore = mr->highlight.fore;
1636             tmp->highlight.back = mr->highlight.back;
1637         }
1638         else
1639         {
1640             tmp->highlight.fore = tmp->normal.back;
1641             tmp->highlight.back = tmp->normal.fore;
1642         }
1643         /* was 'Scr->use3Dmenus' - djhjr - 8/11/98 */
1644         if (Scr->MenuBevelWidth > 0 && !Scr->BeNiceToColormap) {
1645             if (tmp->func != F_TITLE)
1646                 GetShadeColors (&tmp->highlight);
1647             else
1648                 GetShadeColors (&tmp->normal);
1649         }
1650
1651
1652         } /* end for(...) */
1653
1654         if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
1655         return;
1656
1657         start = mr->first;
1658         while (TRUE)
1659         {
1660         for (; start != NULL; start = start->next)
1661         {
1662                 if (start->user_colors)
1663                 break;
1664         }
1665         if (start == NULL)
1666                 break;
1667
1668         for (end = start->next; end != NULL; end = end->next)
1669         {
1670                 if (end->user_colors)
1671                 break;
1672         }
1673         if (end == NULL)
1674                 break;
1675
1676         /* we have a start and end to interpolate between */
1677         num = end->item_num - start->item_num;
1678
1679 /* djhjr - 4/22/96
1680         f1.pixel = start->fore;
1681         XQueryColor(dpy, cmap, &f1);
1682         f2.pixel = end->fore;
1683         XQueryColor(dpy, cmap, &f2);
1684
1685         b1.pixel = start->back;
1686         XQueryColor(dpy, cmap, &b1);
1687         b2.pixel = end->back;
1688         XQueryColor(dpy, cmap, &b2);
1689 */
1690         f1.pixel = start->normal.fore;
1691         XQueryColor(dpy, cmap, &f1);
1692         f2.pixel = end->normal.fore;
1693         XQueryColor(dpy, cmap, &f2);
1694         b1.pixel = start->normal.back;
1695         XQueryColor(dpy, cmap, &b1);
1696         b2.pixel = end->normal.back;
1697         XQueryColor(dpy, cmap, &b2);
1698
1699         fred = ((int)f2.red - (int)f1.red) / num;
1700         fgreen = ((int)f2.green - (int)f1.green) / num;
1701         fblue = ((int)f2.blue - (int)f1.blue) / num;
1702
1703         bred = ((int)b2.red - (int)b1.red) / num;
1704         bgreen = ((int)b2.green - (int)b1.green) / num;
1705         bblue = ((int)b2.blue - (int)b1.blue) / num;
1706
1707         f3 = f1;
1708         f3.flags = DoRed | DoGreen | DoBlue;
1709
1710         b3 = b1;
1711         b3.flags = DoRed | DoGreen | DoBlue;
1712
1713         /* djhjr - 4/23/96 */
1714         start->highlight.back = start->normal.fore;
1715         start->highlight.fore = start->normal.back;
1716
1717         num -= 1;
1718         for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
1719         {
1720                 f3.red += fred;
1721                 f3.green += fgreen;
1722                 f3.blue += fblue;
1723                 save_fore = f3;
1724
1725                 b3.red += bred;
1726                 b3.green += bgreen;
1727                 b3.blue += bblue;
1728                 save_back = b3;
1729                 
1730                 if (Scr->DontInterpolateTitles && (cur->func == F_TITLE))
1731                         continue; /* DSE -- from tvtwm */
1732                 
1733                 XAllocColor(dpy, cmap, &f3);
1734                 XAllocColor(dpy, cmap, &b3);
1735
1736 /* djhjr - 4/22/96
1737                 cur->hi_back = cur->fore = f3.pixel;
1738                 cur->hi_fore = cur->back = b3.pixel;
1739 */
1740                 cur->highlight.back = cur->normal.fore = f3.pixel;
1741                 cur->highlight.fore = cur->normal.back = b3.pixel;
1742                 cur->user_colors = True;
1743
1744                 f3 = save_fore;
1745                 b3 = save_back;
1746         }
1747         start = end;
1748
1749         /* djhjr - 4/22/96
1750         start->highlight.back = start->normal.fore;
1751         start->highlight.fore = start->normal.back;
1752         */
1753         }
1754 }
1755
1756 \f
1757
1758 /***********************************************************************
1759  *
1760  *      Procedure:
1761  *      PopUpMenu - pop up a pull down menu
1762  *
1763  *      Inputs:
1764  *      menu    - the root pointer of the menu to pop up
1765  *      x, y    - location of upper left of menu
1766  *              center  - whether or not to center horizontally over position
1767  *
1768  ***********************************************************************
1769  */
1770
1771 Bool PopUpMenu (menu, x, y, center)
1772         MenuRoot *menu;
1773         int x, y;
1774         Bool center;
1775 {
1776         int WindowNameOffset, WindowNameCount;
1777         TwmWindow **WindowNames;
1778         TwmWindow *tmp_win2,*tmp_win3;
1779         int mask;
1780         int i;
1781         int (*compar)() =
1782           (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
1783
1784         /* djhjr - 9/5/98 */
1785         int x_root, y_root;
1786
1787         if (!menu) return False;
1788
1789 /* djhjr - 6/22/01 */
1790 #ifndef NO_SOUND_SUPPORT
1791         if (!PlaySound(F_MENU)) PlaySound(S_MMAP);
1792 #endif
1793
1794         /* djhjr - 5/22/00 */
1795         menu->top = 0;
1796         if (menu->w) XClearArea(dpy, menu->w, 0, 0, 0, 0, True);
1797
1798         InstallRootColormap();
1799
1800         if (menu == Scr->Windows)
1801         {
1802         TwmWindow *tmp_win;
1803
1804         /* this is the twm windows menu,  let's go ahead and build it */
1805
1806         DestroyMenu (menu);
1807
1808         menu->first = NULL;
1809         menu->last = NULL;
1810         menu->items = 0;
1811         menu->width = 0;
1812         menu->mapped = NEVER_MAPPED;
1813
1814 /* djhjr - 5/4/98
1815         AddToMenu(menu, "TWM Windows", NULLSTR, (MenuRoot *)NULL, F_TITLE,NULLSTR,NULLSTR);
1816 */
1817         AddToMenu(menu, "VTWM Windows", NULLSTR, (MenuRoot *)NULL, F_TITLE,NULLSTR,NULLSTR);
1818
1819                 WindowNameOffset=(char *)Scr->TwmRoot.next->name -
1820                                                            (char *)Scr->TwmRoot.next;
1821                 for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
1822                         tmp_win != NULL;
1823                         tmp_win = tmp_win->next)
1824                   WindowNameCount++;
1825                   
1826             if (WindowNameCount != 0)   /* Submitted by Jennifer Elaan */
1827             {
1828                 WindowNames =
1829                   (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
1830                 WindowNames[0] = Scr->TwmRoot.next;
1831                 for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
1832                         tmp_win != NULL;
1833                         tmp_win = tmp_win->next,WindowNameCount++)
1834                 {
1835                         /* Submitted by Erik Agsjo <erik.agsjo@aktiedirekt.com> */
1836                         if (LookInList(Scr->DontShowInTWMWindows, tmp_win->full_name, &tmp_win->class))
1837                         {
1838                                 WindowNameCount--;
1839                                 continue;
1840                         }
1841
1842                         tmp_win2 = tmp_win;
1843                         for (i=0;i<WindowNameCount;i++)
1844                         {
1845                                 if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
1846                                 {
1847                                         tmp_win3 = tmp_win2;
1848                                         tmp_win2 = WindowNames[i];
1849                                         WindowNames[i] = tmp_win3;
1850                                 }
1851                         }
1852                         WindowNames[WindowNameCount] = tmp_win2;
1853                 }
1854                 for (i=0; i<WindowNameCount; i++)
1855                 {
1856                         AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
1857                                           (MenuRoot *)NULL, F_POPUP,NULLSTR,NULLSTR);
1858                         if (!Scr->OldFashionedTwmWindowsMenu
1859                         && Scr->Monochrome == COLOR)/*RFBCOLOR*/
1860                         {/*RFBCOLOR*/
1861                                 menu->last->user_colors = TRUE;/*RFBCOLOR*/
1862
1863 /* djhjr - 4/22/96
1864                                 menu->last->fore =
1865                                         WindowNames[i]->virtual.fore;*RFBCOLOR*
1866 */
1867 /* djhjr - 5/4/98
1868                                 menu->last->normal.fore =
1869                                         WindowNames[i]->virtual.fore;*RFBCOLOR*
1870 */
1871                                 menu->last->normal.fore = Scr->MenuC.fore;
1872
1873 /* djhjr - 4/22/96
1874                                 menu->last->back =
1875                                         WindowNames[i]->virtual.back;*RFBCOLOR*
1876 */
1877                                 menu->last->normal.back =
1878                                         WindowNames[i]->virtual.back;
1879
1880 /**********************************************************/
1881 /*                                                                                                                */
1882 /*      Okay, okay, it's a bit of a kludge.                                       */
1883 /*                                                                                                                */
1884 /*      On the other hand, it's nice to have the VTWM Windows */
1885 /*      menu come up with "the right colors". And the colors  */
1886 /*      from the panner are not a bad choice...                           */
1887 /*                                                                                                                */
1888 /**********************************************************/
1889                         }/*RFBCOLOR*/
1890                 }
1891                 free(WindowNames);
1892             }
1893         MakeMenu(menu);
1894         }
1895
1896         if (menu->w == None || menu->items == 0) return False;
1897
1898         /* Prevent recursively bringing up menus. */
1899         if (menu->mapped == MAPPED) return False;
1900
1901         /*
1902          * Dynamically set the parent;  this allows pull-ups to also be main
1903          * menus, or to be brought up from more than one place.
1904          */
1905         menu->prev = ActiveMenu;
1906
1907         /*
1908          * Submitted by Steve Ratcliffe
1909          */
1910         mask = ButtonPressMask | ButtonReleaseMask |
1911         ButtonMotionMask | PointerMotionHintMask;
1912         if (Scr->StayUpMenus)
1913                 mask |= PointerMotionMask;
1914
1915         XGrabPointer(dpy, Scr->Root, True, mask,
1916                 GrabModeAsync, GrabModeAsync,
1917                 Scr->Root, Scr->MenuCursor, CurrentTime);
1918
1919         ActiveMenu = menu;
1920         menu->mapped = MAPPED;
1921         menu->entered = FALSE;
1922
1923         if (center) {
1924                 x -= (menu->width / 2);
1925                 y -= (Scr->EntryHeight / 2);    /* sticky menus would be nice here */
1926         }
1927
1928         /*
1929          * clip to screen
1930          */
1931         /* next line and " - i" to "x = " and "y = " - djhjr - 5/22/00 */
1932         i = (Scr->MenuBevelWidth > 0) ? 0 : 2;
1933         if (x + menu->width > Scr->MyDisplayWidth) {
1934                 x = Scr->MyDisplayWidth - menu->width - i;
1935         }
1936         if (x < 0) x = 0;
1937         if (y + menu->height > Scr->MyDisplayHeight) {
1938                 y = Scr->MyDisplayHeight - menu->height - i;
1939         }
1940         if (y < 0) y = 0;
1941
1942         MenuOrigins[MenuDepth].x = x;
1943         MenuOrigins[MenuDepth].y = y;
1944         MenuDepth++;
1945
1946         XMoveWindow(dpy, menu->w, x, y);
1947         if (Scr->Shadow) {
1948         XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
1949         }
1950         if (Scr->Shadow) {
1951         XRaiseWindow (dpy, menu->shadow);
1952         }
1953         XMapRaised(dpy, menu->w);
1954         if (Scr->Shadow) {
1955         XMapWindow (dpy, menu->shadow);
1956         }
1957         XSync(dpy, 0);
1958
1959         /* djhjr - 9/5/98 */
1960         XQueryPointer(dpy, menu->w, &JunkRoot, &JunkChild,
1961                         &x_root, &y_root, &JunkX, &JunkY, &JunkMask);
1962         MenuOrigX = x_root;
1963         MenuOrigY = y_root;
1964
1965         return True;
1966 }
1967
1968 \f
1969
1970 /***********************************************************************
1971  *
1972  *      Procedure:
1973  *      PopDownMenu - unhighlight the current menu selection and
1974  *              take down the menus
1975  *
1976  ***********************************************************************
1977  */
1978
1979 void PopDownMenu()
1980 {
1981         MenuRoot *tmp;
1982
1983         if (ActiveMenu == NULL)
1984         return;
1985
1986 /* djhjr - 6/22/01 */
1987 #ifndef NO_SOUND_SUPPORT
1988         PlaySound(S_MUNMAP);
1989 #endif
1990
1991         if (ActiveItem)
1992         {
1993         ActiveItem->state = 0;
1994         PaintEntry(ActiveMenu, ActiveItem, False);
1995         }
1996
1997         for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
1998         {
1999         if (Scr->Shadow) {
2000                 XUnmapWindow (dpy, tmp->shadow);
2001         }
2002         XUnmapWindow(dpy, tmp->w);
2003         tmp->mapped = UNMAPPED;
2004         UninstallRootColormap();
2005         }
2006
2007         XFlush(dpy);
2008         ActiveMenu = NULL;
2009         ActiveItem = NULL;
2010         MenuDepth = 0;
2011         if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
2012         {  menuFromFrameOrWindowOrTitlebar = TRUE;
2013         }
2014 }
2015
2016 \f
2017
2018 /***********************************************************************
2019  *
2020  *      Procedure:
2021  *      FindMenuRoot - look for a menu root
2022  *
2023  *      Returned Value:
2024  *      (MenuRoot *)  - a pointer to the menu root structure
2025  *
2026  *      Inputs:
2027  *      name    - the name of the menu root
2028  *
2029  ***********************************************************************
2030  */
2031
2032 MenuRoot *
2033 FindMenuRoot(name)
2034         char *name;
2035 {
2036         MenuRoot *tmp;
2037
2038         for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
2039         {
2040         if (strcmp(name, tmp->name) == 0)
2041                 return (tmp);
2042         }
2043         return NULL;
2044 }
2045
2046 \f
2047
2048 static Bool belongs_to_twm_window (t, w)
2049         register TwmWindow *t;
2050         register Window w;
2051 {
2052         if (!t) return False;
2053
2054 #if 0
2055 StayUpMenus
2056         if (w == t->frame || w == t->title_w || w == t->hilite_w ||
2057         w == t->icon_w || w == t->icon_bm_w) return True;
2058 #endif
2059
2060         if (t && t->titlebuttons) {
2061         register TBWindow *tbw;
2062         register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
2063         for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
2064                 if (tbw->window == w) return True;
2065         }
2066         }
2067         return False;
2068 }
2069
2070 \f
2071
2072 /*
2073  * Hack^H^H^H^HWrapper to moves for non-menu contexts.
2074  *
2075  * djhjr - 10/11/01 10/4/02
2076  */
2077 static void moveFromCenterWrapper(tmp_win)
2078 TwmWindow *tmp_win;
2079 {
2080         if (!tmp_win->opaque_move) XUngrabServer(dpy);
2081
2082         WarpScreenToWindow(tmp_win);
2083
2084         /* now here's a nice little kludge... */
2085         {
2086                 int hilite = tmp_win->highlight;
2087
2088                 tmp_win->highlight = True;
2089                 SetBorder(tmp_win, (hilite) ? True : False);
2090                 tmp_win->highlight = hilite;
2091
2092                 Scr->Focus = tmp_win;
2093         }
2094
2095         if (!tmp_win->opaque_move) XGrabServer(dpy);
2096 }
2097
2098 /*
2099  * Jason P. Venner jason@tfs.com
2100  * This function is used by F_WARPTO to match the action name
2101  * against window names.
2102  * Re-written to use list.c:MatchName(), allowing VTWM-style wilcards.
2103  * djhjr - 10/27/02
2104  */
2105 int MatchWinName(action, t)
2106 char            *action;
2107 TwmWindow       *t;
2108 {
2109         int matched = 0;
2110 #ifndef NO_REGEX_SUPPORT
2111         regex_t re;
2112 #else
2113         char re;
2114 #endif
2115
2116         if (MatchName(t->full_name, action, &re, LTYPE_ANY_STRING))
2117                 if (MatchName(t->class.res_name, action, &re, LTYPE_ANY_STRING))
2118                         if (MatchName(t->class.res_class, action, &re, LTYPE_ANY_STRING))
2119                                 matched = 1;
2120
2121         return (matched);
2122 }
2123
2124 \f
2125
2126 /***********************************************************************
2127  *
2128  *      Procedure:
2129  *      ExecuteFunction - execute a twm root function
2130  *
2131  *      Inputs:
2132  *      func    - the function to execute
2133  *      action  - the menu action to execute
2134  *      w       - the window to execute this function on
2135  *      tmp_win - the twm window structure
2136  *      event   - the event that caused the function
2137  *      context - the context in which the button was pressed
2138  *      pulldown- flag indicating execution from pull down menu
2139  *
2140  *      Returns:
2141  *      TRUE if should continue with remaining actions else FALSE to abort
2142  *
2143  ***********************************************************************
2144  */
2145
2146 extern int MovedFromKeyPress;
2147
2148 int
2149 ExecuteFunction(func, action, w, tmp_win, eventp, context, pulldown)
2150         int func;
2151         char *action;
2152         Window w;
2153         TwmWindow *tmp_win;
2154         XEvent *eventp;
2155         int context;
2156         int pulldown;
2157 {
2158         char tmp[200];
2159         char *ptr;
2160         char buff[MAX_FILE_SIZE];
2161         int count, fd;
2162         int do_next_action = TRUE;
2163
2164         actionHack = action; /* Submitted by Michel Eyckmans */
2165         RootFunction = F_NOFUNCTION;
2166         if (Cancel)
2167         return TRUE;                    /* XXX should this be FALSE? */
2168
2169         switch (func)
2170         {
2171         case F_UPICONMGR:
2172         case F_LEFTICONMGR:
2173         case F_RIGHTICONMGR:
2174         case F_DOWNICONMGR:
2175         case F_FORWICONMGR:
2176         case F_BACKICONMGR:
2177         case F_NEXTICONMGR:
2178         case F_PREVICONMGR:
2179         case F_NOP:
2180         case F_TITLE:
2181         case F_DELTASTOP:
2182         case F_RAISELOWER:
2183         case F_WARP:          /* PF */
2184         case F_WARPCLASSNEXT: /* PF */
2185         case F_WARPCLASSPREV: /* PF */
2186         case F_WARPTOSCREEN:
2187         case F_WARPTO:
2188         case F_WARPRING:
2189         case F_WARPTOICONMGR:
2190         case F_COLORMAP:
2191
2192         /* djhjr - 4/30/96 */
2193         case F_SEPARATOR:
2194
2195         /* djhjr - 12/14/98 */
2196         case F_STATICICONPOSITIONS:
2197
2198         /* djhjr - 5/30/00 */
2199         case F_WARPSNUG:
2200         case F_WARPVISIBLE:
2201
2202 /* djhjr - 6/22/01 */
2203 #ifndef NO_SOUND_SUPPORT
2204         case F_SOUNDS:
2205 #endif
2206
2207         /* djhjr - 10/2/01 */
2208         case F_STRICTICONMGR:
2209
2210         /* djhjr - 9/9/02 */
2211         case F_BINDBUTTONS:
2212         case F_BINDKEYS:
2213         case F_UNBINDBUTTONS:
2214         case F_UNBINDKEYS:
2215
2216         break;
2217         default:
2218                 XGrabPointer(dpy, Scr->Root, True,
2219                         ButtonPressMask | ButtonReleaseMask,
2220                         GrabModeAsync, GrabModeAsync,
2221                         Scr->Root, Scr->WaitCursor, CurrentTime);
2222         break;
2223         }
2224
2225 /* djhjr - 6/22/01 */
2226 #ifndef NO_SOUND_SUPPORT
2227         switch (func)
2228         {
2229                 case F_BEEP:
2230                 case F_SQUEEZECENTER:
2231                 case F_SQUEEZELEFT:
2232                 case F_SQUEEZERIGHT:
2233
2234                 /* djhjr - 11/4/03 */
2235                 case F_MOVESCREEN:
2236
2237                 case F_FORCEMOVE:
2238                 case F_MOVE:
2239                 case F_RESIZE:
2240                 case F_EXEC:
2241                 case F_DELETE:
2242                 case F_DELETEDOOR:
2243                 case F_DESTROY:
2244                 case F_DEICONIFY:
2245                 case F_ICONIFY:
2246                 case F_IDENTIFY:
2247                 case F_VERSION:
2248                 case F_QUIT:
2249                 case F_WARP:
2250                 case F_WARPCLASSNEXT:
2251                 case F_WARPCLASSPREV:
2252                 case F_WARPRING:
2253                 case F_WARPTO:
2254                 case F_WARPTOICONMGR:
2255                 case F_WARPTONEWEST:
2256                 case F_WARPTOSCREEN:
2257                         /* handle uniquely */
2258                         break;
2259                 case F_POPUP:
2260                         /* ignore */
2261                         break;
2262                 case F_LOWER:
2263                 case F_RAISE:
2264                 case F_RAISELOWER:
2265                 case F_NAIL:
2266                 case F_NAMEDOOR:
2267                 case F_BOTTOMZOOM:
2268                 case F_FULLZOOM:
2269                 case F_HORIZOOM:
2270                 case F_LEFTZOOM:
2271                 case F_RIGHTZOOM:
2272                 case F_TOPZOOM:
2273                 case F_ZOOM:
2274                 case F_BACKICONMGR:
2275                 case F_DOWNICONMGR:
2276                 case F_FORWICONMGR:
2277                 case F_LEFTICONMGR:
2278                 case F_RIGHTICONMGR:
2279                 case F_UPICONMGR:
2280                 case F_FOCUS:
2281                 case F_SAVEYOURSELF:
2282                 case F_STICKYABOVE:
2283                 case F_RING:
2284                 case F_WINREFRESH:
2285
2286                 /* djhjr - 9/9/02 */
2287                 case F_BINDBUTTONS:
2288                 case F_BINDKEYS:
2289                 case F_UNBINDBUTTONS:
2290                 case F_UNBINDKEYS:
2291
2292                         /* ignore if from a root menu */
2293                         if (Context != C_ROOT && Context != C_NO_CONTEXT)
2294                                 PlaySound(func);
2295                         break;
2296                 default:
2297                         /* unconditional */
2298                         PlaySound(func);
2299                         break;
2300         }
2301 #endif
2302
2303         switch (func)
2304         {
2305         case F_NOP:
2306         case F_TITLE:
2307         break;
2308
2309         case F_DELTASTOP:
2310         if (WindowMoved) do_next_action = FALSE;
2311         break;
2312
2313         case F_RESTART:
2314
2315         /* added this 'case' and 'if () ... else ' - djhjr - 7/15/98 */
2316         case F_STARTWM:
2317         if (func == F_STARTWM)
2318         {
2319                 /* dynamic allocation of (char **)my_argv - djhjr - 9/26/02 */
2320
2321                 char *p, *delims = " \t";
2322                 char *new_argv = NULL, **my_argv = NULL;
2323                 int i = 0, j = 0;
2324
2325                 p = strtok(action, delims);
2326                 while (p)
2327                 {
2328                         if (j >= i)
2329                         {
2330                                 i += 5;
2331                                 new_argv = (char *)realloc((char *)my_argv,
2332                                                            i * sizeof(char *));
2333                                 if (new_argv == NULL)
2334                                 {
2335                                         fprintf(stderr,
2336                                                 "%s: unable to allocate %d bytes for execvp()\n",
2337                                                 ProgramName, i * sizeof(char *));
2338                                         break;
2339                                 }
2340                                 else
2341                                         my_argv = (char **)new_argv;
2342                         }
2343
2344                         my_argv[j++] = strdup(p);
2345                         p = strtok(NULL, delims);
2346                 }
2347
2348                 if (new_argv != NULL)
2349                 {
2350                         my_argv[j] = NULL;
2351
2352                         /* djhjr - 7/31/98 */
2353                         setup_restart(eventp->xbutton.time);
2354
2355                         execvp(*my_argv, my_argv);
2356                         fprintf(stderr, "%s:  unable to start \"%s\"\n",
2357                                 ProgramName, *my_argv);
2358                         new_argv = NULL;
2359                 }
2360
2361                 if (new_argv == NULL)
2362                 {
2363                         i = 0;
2364                         while (i < j)
2365                                 free(my_argv[i++]);
2366                         if (j)
2367                                 free((char *)my_argv);
2368                 }
2369         }
2370         else
2371                 /* djhjr - 7/31/98 */
2372                 RestartVtwm(eventp->xbutton.time);
2373
2374         break;
2375
2376         case F_UPICONMGR:
2377         case F_DOWNICONMGR:
2378         case F_LEFTICONMGR:
2379         case F_RIGHTICONMGR:
2380     case F_FORWICONMGR:
2381     case F_BACKICONMGR:
2382         MoveIconManager(func);
2383         break;
2384
2385     case F_NEXTICONMGR:
2386     case F_PREVICONMGR:
2387         JumpIconManager(func);
2388         break;
2389
2390     case F_SHOWLIST:
2391
2392         /* added this 'if (...) else ...' - djhjr - 9/21/99 */
2393         if (context == C_ROOT)
2394         {
2395                 name_list *list;
2396
2397                 ShowIconMgr(&Scr->iconmgr);
2398
2399                 /*
2400                  * New code in list.c necessitates 'next_entry()' and
2401                  * 'contents_of_entry()' - djhjr - 10/20/01
2402                  */
2403                 for (list = Scr->IconMgrs; list != NULL; list = next_entry(list))
2404                         ShowIconMgr((IconMgr *)contents_of_entry(list));
2405         }
2406         else
2407         {
2408                 IconMgr *ip;
2409
2410                 if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name,
2411                                 &tmp_win->class)) == NULL)
2412                         ip = &Scr->iconmgr;
2413
2414                 ShowIconMgr(ip);
2415         }
2416
2417         RaiseStickyAbove(); /* DSE */
2418         RaiseAutoPan();
2419         
2420         break;
2421
2422     case F_HIDELIST:
2423
2424         if (Scr->NoIconManagers)
2425             break;
2426
2427         /* added argument - djhjr - 9/21/99 */
2428         HideIconManager((context == C_ROOT) ? NULL : tmp_win);
2429
2430         break;
2431
2432     case F_SORTICONMGR:
2433
2434         /* djhjr - 6/10/98 */
2435         if (Scr->NoIconManagers || Scr->iconmgr.count == 0)
2436             break;
2437
2438         if (DeferExecution(context, func, Scr->SelectCursor))
2439             return TRUE;
2440
2441         {
2442             int save_sort;
2443
2444             save_sort = Scr->SortIconMgr;
2445             Scr->SortIconMgr = TRUE;
2446
2447             if (context == C_ICONMGR)
2448                 SortIconManager((IconMgr *) NULL);
2449             else if (tmp_win->iconmgr)
2450                 SortIconManager(tmp_win->iconmgrp);
2451             else
2452                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2453
2454             Scr->SortIconMgr = save_sort;
2455         }
2456         break;
2457
2458     case F_IDENTIFY:
2459         if (DeferExecution(context, func, Scr->SelectCursor))
2460         {
2461             return TRUE;
2462         }
2463
2464         Identify(tmp_win);
2465         break;
2466
2467     case F_VERSION:
2468         Identify ((TwmWindow *) NULL);
2469         break;
2470
2471         case F_ZOOMZOOM: /* RFB silly */
2472                 /* added args to iconmgrs - djhjr - 10/11/01 */
2473                 Zoom( None, NULL, None, NULL );
2474                 break;
2475
2476         case F_AUTOPAN:/*RFB F_AUTOPAN*/
2477         { /* toggle autopan *//*RFB F_AUTOPAN*/
2478                 static int saved;/*RFB F_AUTOPAN*/
2479
2480                 if ( Scr->AutoPanX )
2481                 {       saved = Scr->AutoPanX;/*RFB F_AUTOPAN*/
2482                         Scr->AutoPanX = 0;/*RFB F_AUTOPAN*/
2483                 } else { /*RFB F_AUTOPAN*/
2484                         Scr->AutoPanX = saved;/*RFB F_AUTOPAN*/
2485                         /* if restart with no autopan, we'll set the
2486                         ** variable but we won't pan
2487                         */
2488                         RaiseAutoPan(); /* DSE */
2489                 }/*RFB F_AUTOPAN*/
2490                 break;/*RFB F_AUTOPAN*/
2491         }/*RFB F_AUTOPAN*/
2492         
2493         case F_STICKYABOVE: /* DSE */
2494                 if (Scr->StickyAbove) {
2495                         LowerSticky(); Scr->StickyAbove = FALSE;
2496                         /* don't change the order of execution! */
2497                 } else {
2498                         Scr->StickyAbove = TRUE; RaiseStickyAbove(); RaiseAutoPan();
2499                         /* don't change the order of execution! */
2500                 }
2501                 return TRUE;
2502                 /* break; *//* NOT REACHABLE */
2503
2504     case F_AUTORAISE:
2505         if (DeferExecution(context, func, Scr->SelectCursor))
2506             return TRUE;
2507
2508         tmp_win->auto_raise = !tmp_win->auto_raise;
2509         if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
2510         else --(Scr->NumAutoRaises);
2511         break;
2512
2513     case F_BEEP:
2514
2515 /* djhjr - 6/22/01 */
2516 #ifndef NO_SOUND_SUPPORT
2517         /* sound has priority over bell */
2518         if (PlaySound(func)) break;
2519 #endif
2520
2521         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2522         break;
2523
2524     case F_POPUP:
2525         tmp_win = (TwmWindow *)action;
2526         if (Scr->WindowFunction.func != F_NOFUNCTION)
2527         {
2528            ExecuteFunction(Scr->WindowFunction.func,
2529                            Scr->WindowFunction.item->action,
2530                            w, tmp_win, eventp, C_FRAME, FALSE);
2531         }
2532         else
2533         {
2534             DeIconify(tmp_win);
2535             XRaiseWindow (dpy, tmp_win->frame);
2536             XRaiseWindow (dpy, tmp_win->VirtualDesktopDisplayWindow);
2537             
2538             RaiseStickyAbove();
2539             RaiseAutoPan();
2540         }
2541         break;
2542
2543     case F_RESIZE:
2544         {
2545             TwmWindow *focused = NULL;          /* djhjr - 5/27/03 */
2546             Bool fromtitlebar = False;
2547             long releaseEvent;
2548             long movementMask;
2549             int resizefromcenter = 0;           /* djhjr - 10/2/02 */
2550 /* djhjr - 10/6/02 */
2551 #ifndef NO_SOUND_SUPPORT
2552             int did_playsound = FALSE;
2553 #endif
2554
2555             if (DeferExecution(context, func, Scr->ResizeCursor))
2556                 return TRUE;
2557
2558             PopDownMenu();
2559
2560             if (pulldown)
2561                 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
2562                              eventp->xbutton.x_root,
2563                              eventp->xbutton.y_root);
2564
2565             EventHandler[EnterNotify] = HandleUnknown;
2566             EventHandler[LeaveNotify] = HandleUnknown;
2567
2568 /* allow the resizing of doors - djhjr - 2/22/99
2569             if ((w != tmp_win->icon_w) && (context != C_DOOR))
2570 */
2571             if (context == C_ICON) /* can't resize icons */
2572             {
2573                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2574                 break;
2575             }
2576
2577             /*
2578              * Resizing from a titlebar menu was handled uniquely long
2579              * before I got here, and I added virtual windows and icon
2580              * managers on 9/15/99 and 10/11/01, leveraging that code.
2581              * It's all been integrated here.
2582              * djhjr - 10/3/02
2583              */
2584             if (Context & (C_FRAME_BIT | C_WINDOW_BIT | C_TITLE_BIT)
2585                         && menuFromFrameOrWindowOrTitlebar)
2586             {
2587                 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
2588                              (unsigned int *)&DragWidth,
2589                              (unsigned int *)&DragHeight,
2590                              &JunkBW, &JunkDepth);
2591
2592                 resizefromcenter = 2;
2593             }
2594             else if (Context == C_VIRTUAL_WIN)
2595             {
2596                 TwmWindow *twin;
2597
2598                 if ((XFindContext(dpy, eventp->xbutton.subwindow,
2599                                   VirtualContext, (caddr_t *) &twin) == XCNOENT))
2600                 {
2601                     DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2602                     break;
2603                 }
2604
2605                 context = C_WINDOW;
2606                 tmp_win = twin;
2607                 resizefromcenter = 1;
2608             }
2609             else if (Context == C_ICONMGR && tmp_win->list)
2610             {
2611                 /* added the second argument - djhjr - 5/28/00 */
2612                 if (!warp_if_warpunmapped(tmp_win, F_NOFUNCTION))
2613                 {
2614                     DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2615                     break;
2616                 }
2617
2618                 resizefromcenter = 1;
2619             }
2620
2621             if (resizefromcenter)
2622             {
2623                 WarpScreenToWindow(tmp_win);
2624
2625                 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
2626                              tmp_win->frame_x + tmp_win->frame_width / 2,
2627                              tmp_win->frame_y + tmp_win->frame_height / 2);
2628
2629                 /* grr - djhjr - 5/27/03 */
2630                 focused = Scr->Focus;
2631                 Scr->Focus = tmp_win;
2632                 SetBorder(Scr->Focus, True);
2633
2634                 /* save positions so we can tell if it was moved or not */
2635                 ResizeOrigX = tmp_win->frame_x + tmp_win->frame_width / 2;
2636                 ResizeOrigY = tmp_win->frame_y + tmp_win->frame_height / 2;
2637             }
2638             else
2639             {
2640                 /* save position so we can tell if it was moved or not */
2641                 ResizeOrigX = eventp->xbutton.x_root;
2642                 ResizeOrigY = eventp->xbutton.y_root;
2643             }
2644
2645             /* see if this is being done from the titlebar */
2646             fromtitlebar = belongs_to_twm_window(tmp_win,
2647                                                  eventp->xbutton.window);
2648
2649             if (resizefromcenter == 2)
2650             {
2651                 MenuStartResize(tmp_win, origDragX, origDragY,
2652                                 DragWidth, DragHeight, Context);
2653
2654                 releaseEvent = ButtonPress;
2655                 movementMask = PointerMotionMask;
2656             }
2657             else
2658             {
2659                 StartResize(eventp, tmp_win, fromtitlebar, context);
2660
2661                 fromtitlebar = False;
2662                 releaseEvent = ButtonRelease;
2663                 movementMask = ButtonMotionMask;
2664             }
2665
2666             /* substantially re-worked - djhjr - 5/27/03 */
2667             while (TRUE)
2668             {
2669                 /* added exposure event masks - djhjr - 10/11/01 */
2670                 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
2671                            EnterWindowMask | LeaveWindowMask |
2672                            ExposureMask | VisibilityChangeMask |
2673                            movementMask, &Event);
2674
2675 /*
2676  * See down below, after this loop - djhjr - 5/27/03
2677  */
2678 #if 0
2679                 /* discard crossing events before a release - djhjr - 10/11/01 */
2680                 if (Event.xany.type == EnterNotify ||
2681                                 Event.xany.type == LeaveNotify)
2682                 {
2683                     /* this can't be the proper place - djhjr - 10/2/02 */
2684                     SetBorder(tmp_win, True);
2685
2686                     continue;
2687                 }
2688 #endif
2689
2690                 /*
2691                  * Don't discard exposure events before release
2692                  * or window borders and/or their titles in the
2693                  * virtual desktop won't get redrawn - djhjr
2694                  */
2695
2696                 /* discard any extra motion events before a release */
2697                 if (Event.type == MotionNotify)
2698                 {
2699                     /* was 'ButtonMotionMask' - djhjr - 10/11/01 */
2700                     while (XCheckMaskEvent(dpy, releaseEvent | movementMask,
2701                                            &Event))
2702                     {
2703                         if (Event.type == releaseEvent)
2704                             break;
2705                     }
2706                 }
2707
2708 /*
2709  * See above, before this loop - djhjr - 5/27/03
2710  */
2711 #if 0
2712                 if (fromtitlebar && Event.type == ButtonPress) {
2713                     fromtitlebar = False;
2714                     continue;
2715                 }
2716 #endif
2717
2718                 if (Event.type == releaseEvent)
2719                 {
2720                     if (Cancel)
2721                     {
2722                         if (tmp_win->opaque_resize)
2723                         {
2724                             ConstrainSize(tmp_win, &origWidth, &origHeight);
2725                             SetupWindow(tmp_win, origx, origy,
2726                                         origWidth, origHeight, -1);
2727                             ResizeTwmWindowContents(tmp_win,
2728                                                     origWidth, origHeight);
2729                         }
2730                         else
2731                             MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
2732
2733                         ResizeWindow = None;
2734                         resizing_window = 0;
2735                         do_next_action = FALSE;
2736                     }
2737                     else
2738                     {
2739                         if (resizefromcenter == 2)
2740                         {
2741                             /* added passing of 'Context' - djhjr - 9/30/02 */
2742                             MenuEndResize(tmp_win, Context);
2743                         }
2744                         else
2745                             EndResize();
2746
2747                         /* DispatchEvent2() is depreciated - djhjr - 10/6/02 */
2748                         DispatchEvent();
2749
2750                         /* djhjr - 5/27/03 11/2/03 */
2751                         if (!Scr->NoRaiseResize && !Scr->RaiseOnStart &&
2752                                 WindowMoved)
2753                         {
2754                             XRaiseWindow(dpy, tmp_win->frame);
2755                             SetRaiseWindow(tmp_win);
2756                         }
2757                     }
2758
2759                     break;
2760                 }
2761
2762                 /* DispatchEvent2() is depreciated - djhjr - 10/6/02 */
2763                 if (!DispatchEvent()) continue;
2764
2765                 if (Event.type != MotionNotify) continue;
2766
2767                 XQueryPointer(dpy, Scr->Root,
2768                               &JunkRoot, &JunkChild, &JunkX, &JunkY,
2769                               &AddingX, &AddingY, &JunkMask);
2770
2771                 if (!resizing_window &&
2772                                 (abs(AddingX - ResizeOrigX) < Scr->MoveDelta &&
2773                                  abs(AddingY - ResizeOrigY) < Scr->MoveDelta))
2774                 {
2775                     continue;
2776                 }
2777
2778                 resizing_window = 1;
2779                 WindowMoved = TRUE;
2780
2781                 /* djhjr - 5/27/03 11/3/03 */
2782                 if ((!Scr->NoRaiseResize && Scr->RaiseOnStart)
2783                         /* trap a Shape extention bug - djhjr - 5/27/03 */
2784                         || (tmp_win->opaque_resize &&
2785                         (HasShape &&
2786                         (tmp_win->wShaped || tmp_win->squeeze_info)))
2787                    )
2788                 {
2789                     XRaiseWindow(dpy, tmp_win->frame);
2790                     SetRaiseWindow(tmp_win);
2791                     if (Scr->Virtual && tmp_win->VirtualDesktopDisplayWindow)
2792                         XRaiseWindow(dpy, tmp_win->VirtualDesktopDisplayWindow);
2793                 }
2794
2795 /* djhjr - 6/22/01 */
2796 #ifndef NO_SOUND_SUPPORT
2797                 if (did_playsound == FALSE)
2798                 {
2799                     PlaySound(func);
2800                     did_playsound = TRUE;
2801                 }
2802 #endif
2803
2804                 /* MenuDoResize() is depreciated - djhjr - 10/6/02 */
2805                 DoResize(AddingX, AddingY, tmp_win);
2806             }
2807
2808 /* djhjr - 6/4/98
2809             return TRUE;
2810 */
2811
2812 /* djhjr - 7/17/98
2813             * djhjr - 4/7/98 *
2814             if (!Scr->NoGrabServer) XUngrabServer(dpy);
2815 */
2816             if (!tmp_win->opaque_resize) XUngrabServer(dpy);
2817
2818             /*
2819              * All this stuff from resize.c:EndResize() - djhjr - 10/6/02
2820              */
2821
2822             if (!tmp_win->opaque_resize)
2823                 UninstallRootColormap();
2824
2825             /* discard queued enter and leave events - djhjr - 5/27/03 */
2826             while (XCheckMaskEvent(dpy, EnterWindowMask | LeaveWindowMask,
2827                                    &Event))
2828                 ;
2829
2830             if (!Scr->NoRaiseResize)
2831             {
2832                 RaiseStickyAbove (); /* DSE */
2833                 RaiseAutoPan();
2834             }
2835
2836             /* update virtual coords */
2837             tmp_win->virtual_frame_x = Scr->VirtualDesktopX + tmp_win->frame_x;
2838             tmp_win->virtual_frame_y = Scr->VirtualDesktopY + tmp_win->frame_y;
2839
2840             /* UpdateDesktop(tmp_win); Stig */
2841 /* djhjr - 5/27/03
2842             MoveResizeDesktop(tmp_win,  Scr->NoRaiseResize); * Stig *
2843 */
2844             MoveResizeDesktop(tmp_win,  Cancel | Scr->NoRaiseResize); /* Stig */
2845
2846             /* djhjr - 9/30/02 10/6/02 */
2847             if (Context == C_VIRTUAL_WIN)
2848             {
2849                 /*
2850                  * Mask a bug that calls MoveOutline(zeros) after the
2851                  * border has been repainted, leaving artifacts. I think
2852                  * I know what the bug is, but I can't seem to fix it.
2853                  */
2854                 if (Scr->BorderBevelWidth > 0) PaintBorders(tmp_win, False);
2855
2856                 JunkX = tmp_win->virtual_frame_x + tmp_win->frame_width / 2;
2857                 JunkY = tmp_win->virtual_frame_y + tmp_win->frame_height / 2;
2858                 XWarpPointer(dpy, None, Scr->VirtualDesktopDisplayOuter,
2859                              0, 0, 0, 0, SCALE_D(JunkX), SCALE_D(JunkY));
2860
2861                 /* grr - djhjr - 5/27/03 */
2862                 SetBorder(Scr->Focus, False);
2863                 Scr->Focus = focused;
2864             }
2865
2866             /* djhjr - 6/4/98 */
2867             /* don't re-map if the window is the virtual desktop - djhjr - 2/28/99 */
2868             if (Scr->VirtualReceivesMotionEvents &&
2869                         /* !tmp_win->opaque_resize && */
2870                         tmp_win->w != Scr->VirtualDesktopDisplayOuter)
2871             {
2872                 XUnmapWindow(dpy, Scr->VirtualDesktopDisplay);
2873                 XMapWindow(dpy, Scr->VirtualDesktopDisplay);
2874             }
2875
2876             break;
2877         }
2878
2879     case F_ZOOM:
2880     case F_HORIZOOM:
2881     case F_FULLZOOM:
2882     case F_LEFTZOOM:
2883     case F_RIGHTZOOM:
2884     case F_TOPZOOM:
2885     case F_BOTTOMZOOM:
2886         if (DeferExecution(context, func, Scr->SelectCursor))
2887             return TRUE;
2888
2889         /* djhjr - 4/1/00 */
2890         PopDownMenu();
2891
2892         fullzoom(tmp_win, func);
2893         /* UpdateDesktop(tmp_win); Stig */
2894         MoveResizeDesktop(tmp_win, Scr->NoRaiseMove); /* Stig */
2895         break;
2896
2897     case F_MOVE:
2898     case F_FORCEMOVE:
2899         {
2900             static Time last_time = 0;
2901             Window rootw;
2902             Bool fromtitlebar = False;
2903             int moving_icon = FALSE;
2904             int constMoveDir, constMoveX, constMoveY;
2905             int constMoveXL, constMoveXR, constMoveYT, constMoveYB;
2906             int origX, origY;
2907             long releaseEvent;
2908             long movementMask;
2909             int xl, yt, xr, yb;
2910             int movefromcenter = 0;     /* djhjr - 10/4/02 */
2911 /* djhjr - 6/22/01 */
2912 #ifndef NO_SOUND_SUPPORT
2913             int did_playsound = FALSE;
2914 #endif
2915
2916             if (DeferExecution(context, func, Scr->MoveCursor))
2917                 return TRUE;
2918
2919             PopDownMenu();
2920             rootw = eventp->xbutton.root;
2921
2922             if (pulldown)
2923                 XWarpPointer(dpy, None, Scr->Root,
2924                              0, 0, 0, 0, eventp->xbutton.x_root,
2925                              eventp->xbutton.y_root);
2926
2927             EventHandler[EnterNotify] = HandleUnknown;
2928             EventHandler[LeaveNotify] = HandleUnknown;
2929
2930 /* djhjr - 4/7/98
2931             if (!Scr->NoGrabServer || !Scr->OpaqueMove) XGrabServer(dpy);
2932 */
2933 /* djhjr - 7/17/98
2934             if (!Scr->NoGrabServer) XGrabServer(dpy);
2935 */
2936             if (!tmp_win->opaque_move) XGrabServer(dpy);
2937
2938 /* use initialized size... djhjr - 5/9/96
2939             * djhjr - 4/27/96 *
2940             Scr->SizeStringOffset = SIZE_HINDENT;
2941             XResizeWindow(dpy, Scr->SizeWindow,
2942                           Scr->SizeStringWidth + SIZE_HINDENT * 2, 
2943                           Scr->SizeFont.height + SIZE_VINDENT * 2);
2944 */
2945
2946             XGrabPointer(dpy, eventp->xbutton.root, True,
2947                          ButtonPressMask | ButtonReleaseMask |
2948                          ButtonMotionMask | PointerMotionMask,
2949                          /* PointerMotionHintMask */
2950                          GrabModeAsync, GrabModeAsync,
2951                          Scr->Root, Scr->MoveCursor, CurrentTime);
2952
2953             /* added this 'if (...) else' - djhjr - 10/11/01 */
2954             if (context == C_VIRTUAL_WIN)
2955             {
2956                 TwmWindow *twin;
2957
2958                 if ((XFindContext(dpy, eventp->xbutton.subwindow,
2959                                 VirtualContext, (caddr_t *) &twin) == XCNOENT))
2960                 {
2961                     DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2962                     break;
2963                 }
2964
2965                 tmp_win = twin;
2966                 moveFromCenterWrapper(tmp_win);
2967                 /* these two - djhjr - 10/4/02 */
2968                 w = tmp_win->frame;
2969                 movefromcenter = 1;
2970             }
2971             else
2972
2973             /* added this 'if (...) else' - djhjr - 9/15/99 */
2974             if (context == C_ICONMGR && tmp_win->list)
2975             {
2976                 /* added the second argument - djhjr - 5/28/00 */
2977                 if (!warp_if_warpunmapped(tmp_win, F_NOFUNCTION))
2978                 {
2979                     DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
2980                     break;
2981                 }
2982
2983                 moveFromCenterWrapper(tmp_win); /* djhjr - 10/11/01 */
2984                 /* these two - djhjr - 10/4/02 */
2985                 w = tmp_win->frame;
2986                 movefromcenter = 1;
2987             }
2988             else
2989
2990             if (context == C_ICON && tmp_win->icon_w)
2991             {
2992                 DragX = eventp->xbutton.x;
2993                 DragY = eventp->xbutton.y;
2994
2995                 w = tmp_win->icon_w;
2996                 moving_icon = TRUE;
2997             }
2998             else if (w != tmp_win->icon_w)
2999             {
3000                 XTranslateCoordinates(dpy, w, tmp_win->frame,
3001                                       eventp->xbutton.x,
3002                                       eventp->xbutton.y,
3003                                       &DragX, &DragY, &JunkChild);
3004
3005                 w = tmp_win->frame;
3006             }
3007
3008             XMapRaised (dpy, Scr->SizeWindow);
3009
3010             DragWindow = None;
3011
3012             MoveFunction = func;        /* set for DispatchEvent() */
3013
3014             XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
3015                          (unsigned int *)&DragWidth,
3016                          (unsigned int *)&DragHeight,
3017                          &JunkBW, &JunkDepth);
3018
3019             /* added this 'if (...) else' - djhjr - 10/4/02 */
3020             if (menuFromFrameOrWindowOrTitlebar ||
3021                         movefromcenter || (moving_icon && fromMenu))
3022             {
3023                 origX = DragX = origDragX + DragWidth / 2;
3024                 origY = DragY = origDragY + DragHeight / 2;
3025             }
3026             else
3027             {
3028                 origX = eventp->xbutton.x_root;
3029                 origY = eventp->xbutton.y_root;
3030             }
3031
3032             CurrentDragX = origDragX;
3033             CurrentDragY = origDragY;
3034
3035             /*
3036              * Only do the constrained move if timer is set -
3037              * need to check it in case of stupid or wicked fast servers.
3038              */
3039             if ( ConstrainedMoveTime &&
3040                         eventp->xbutton.time - last_time < ConstrainedMoveTime)
3041             {
3042                 int width, height;
3043
3044                 ConstMove = TRUE;
3045                 constMoveDir = MOVE_NONE;
3046                 constMoveX = eventp->xbutton.x_root - DragX - JunkBW;
3047                 constMoveY = eventp->xbutton.y_root - DragY - JunkBW;
3048                 width = DragWidth + 2 * JunkBW;
3049                 height = DragHeight + 2 * JunkBW;
3050                 constMoveXL = constMoveX + width/3;
3051                 constMoveXR = constMoveX + 2*(width/3);
3052                 constMoveYT = constMoveY + height/3;
3053                 constMoveYB = constMoveY + 2*(height/3);
3054
3055                 XWarpPointer(dpy, None, w,
3056                              0, 0, 0, 0, DragWidth/2, DragHeight/2);
3057
3058                 XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
3059                               &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
3060             }
3061             last_time = eventp->xbutton.time;
3062
3063 /* djhjr - 4/7/98
3064             if (!Scr->OpaqueMove)
3065 */
3066             if (!tmp_win->opaque_move)
3067             {
3068                 InstallRootColormap();
3069                 /*if (!Scr->MoveDelta)*/        /* djhjr - 10/2/02 */
3070                 {
3071                     /*
3072                      * Draw initial outline.  This was previously done the
3073                      * first time though the outer loop by dropping out of
3074                      * the XCheckMaskEvent inner loop down to one of the
3075                      * MoveOutline's below.
3076                      */
3077                     MoveOutline(rootw,
3078                                 origDragX - JunkBW, origDragY - JunkBW,
3079                                 DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
3080                                 tmp_win->frame_bw,
3081 /* djhjr - 4/22/96
3082                                 moving_icon ? 0 : tmp_win->title_height);
3083 */
3084                                 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
3085
3086                     /*
3087                      * This next line causes HandleButtonRelease to call
3088                      * XRaiseWindow().  This is solely to preserve the
3089                      * previous behaviour that raises a window being moved
3090                      * on button release even if you never actually moved
3091                      * any distance (unless you move less than MoveDelta or
3092                      * NoRaiseMove is set or OpaqueMove is set).
3093                      *
3094                      * It's set way down below; no need to force it here.
3095                      * djhjr - 10/4/02
3096                      *
3097                      * The code referred to above is 'if 0'd out now anyway.
3098                      * djhjr - 10/6/02
3099                      */
3100                     /*DragWindow = w;*/
3101                 }
3102             }
3103
3104             /*
3105              * see if this is being done from the titlebar
3106              */
3107             fromtitlebar = belongs_to_twm_window(tmp_win,
3108                                                  eventp->xbutton.window);
3109
3110             /* added 'movefromcenter' and 'moving_icon' - djhjr - 10/4/02 */
3111             if ((menuFromFrameOrWindowOrTitlebar && !fromtitlebar) ||
3112                         movefromcenter || (moving_icon && fromMenu))
3113             {
3114                 /* warp the pointer to the middle of the window */
3115                 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
3116                              origDragX + DragWidth / 2,
3117                              origDragY + DragHeight / 2);
3118
3119                 SetBorder(tmp_win, True);       /* grr */
3120
3121                 XFlush(dpy);
3122             }
3123
3124             /* djhjr - 4/27/96 */
3125             DisplayPosition(CurrentDragX, CurrentDragY);
3126
3127             if (menuFromFrameOrWindowOrTitlebar)
3128             {
3129                 releaseEvent = ButtonPress;
3130                 movementMask = PointerMotionMask;
3131             }
3132             else
3133             {
3134                 releaseEvent = ButtonRelease;
3135                 movementMask = ButtonMotionMask;
3136             }
3137
3138             while (TRUE)
3139             {
3140                 /* block until there is an interesting event */
3141                 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
3142                            EnterWindowMask | LeaveWindowMask |
3143                            ExposureMask | VisibilityChangeMask |
3144                            movementMask, &Event);
3145
3146 /*
3147  * See down below, after this loop - djhjr - 5/23/03
3148  */
3149 #if 0
3150                 /* throw away enter and leave events until release */
3151                 if (Event.xany.type == EnterNotify ||
3152                                 Event.xany.type == LeaveNotify)
3153                 {
3154                     continue;
3155                 }
3156 #endif
3157
3158                 /*
3159                  * Don't discard exposure events before release
3160                  * or window borders and/or their titles in the
3161                  * virtual desktop won't get redrawn - djhjr
3162                  */
3163
3164                 /* discard any extra motion events before a release */
3165                 if (Event.type == MotionNotify)
3166                 {
3167                     while (XCheckMaskEvent(dpy, movementMask | releaseEvent,
3168                                            &Event))
3169                     {
3170                         if (Event.type == releaseEvent)
3171                             break;
3172                     }
3173                 }
3174
3175                 /*
3176                  * There used to be a couple of routines that handled the
3177                  * cancel functionality here, each doing a portion of the
3178                  * job, then returning immediately. They became redundant
3179                  * to just letting program execution fall through. So now,
3180                  * the 'if (Event.type == releaseEvent) if (Cancel)' below
3181                  * does just that, clearing a few flags first.
3182                  * djhjr - 10/6/02
3183                  */
3184
3185                 if (fromtitlebar && Event.type == ButtonPress)
3186                 {
3187                     fromtitlebar = False;
3188                     CurrentDragX = origX = Event.xbutton.x_root;
3189                     CurrentDragY = origY = Event.xbutton.y_root;
3190                     XTranslateCoordinates(dpy, rootw, tmp_win->frame,
3191                                           origX, origY,
3192                                           &DragX, &DragY, &JunkChild);
3193
3194                     continue;
3195                 }
3196
3197                 /* DispatchEvent2() is depreciated - djhjr - 10/6/02 */
3198                 if (!DispatchEvent()) continue;
3199
3200                 /* re-wrote this stuff - djhjr - 10/4/02 5/24/03 11/2/03 */
3201                 if (Event.type == releaseEvent)
3202                 {
3203                     MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
3204
3205                     if (Cancel)
3206                     {
3207                         DragWindow = None;
3208                         ConstMove = WindowMoved = do_next_action = FALSE;
3209                     }
3210                     else if (WindowMoved)
3211                     {
3212                         if (moving_icon)
3213                         {
3214                             tmp_win->icon_moved = TRUE;
3215                             XMoveWindow(dpy, tmp_win->icon_w,
3216                                         CurrentDragX, CurrentDragY);
3217
3218                             if (!Scr->NoRaiseMove && !Scr->RaiseOnStart)
3219                             {
3220                                 XRaiseWindow(dpy, tmp_win->icon_w);
3221                                 SetRaiseWindow(tmp_win->icon_w);
3222                             }
3223                         }
3224                         else
3225                         {
3226                             if (movefromcenter)
3227                             {
3228                                 tmp_win->frame_x = Event.xbutton.x_root -
3229                                                    DragWidth / 2;
3230                                 tmp_win->frame_y = Event.xbutton.y_root -
3231                                                    DragHeight / 2;
3232                             }
3233                             else
3234                             {
3235                                 tmp_win->frame_x = CurrentDragX;
3236                                 tmp_win->frame_y = CurrentDragY;
3237                             }
3238
3239                             XMoveWindow(dpy, tmp_win->frame,
3240                                         tmp_win->frame_x, tmp_win->frame_y);
3241                             SendConfigureNotify(tmp_win, tmp_win->frame_x,
3242                                                 tmp_win->frame_y);
3243
3244                             if (!Scr->NoRaiseMove && !Scr->RaiseOnStart)
3245                             {
3246                                 XRaiseWindow(dpy, tmp_win->frame);
3247                                 SetRaiseWindow(tmp_win);
3248                             }
3249                         }
3250                     }
3251
3252                     break;
3253                 }
3254
3255                 /* something left to do only if the pointer moved */
3256                 if (Event.type != MotionNotify) continue;
3257
3258                 XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
3259                               &(eventp->xmotion.x_root),
3260                               &(eventp->xmotion.y_root),
3261                               &JunkX, &JunkY, &JunkMask);
3262
3263                 if (DragWindow == None &&
3264                         abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
3265                         abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
3266                 {
3267                     continue;
3268                 }
3269
3270                 WindowMoved = TRUE;
3271                 DragWindow = w;
3272
3273 /* djhjr - 4/7/98
3274                 if (!Scr->NoRaiseMove && Scr->OpaqueMove)
3275 */
3276 /* djhjr - 10/6/02
3277                 if (!Scr->NoRaiseMove && tmp_win->opaque_move)
3278                     XRaiseWindow(dpy, DragWindow);
3279 */
3280                 /* djhjr - 5/24/03 11/3/03 */
3281                 if (!Scr->NoRaiseMove && Scr->RaiseOnStart)
3282                 {
3283                     if (moving_icon)
3284                     {
3285                         XRaiseWindow(dpy, tmp_win->icon_w);
3286                         SetRaiseWindow(tmp_win->icon_w);
3287                     }
3288                     else
3289                     {
3290                         XRaiseWindow(dpy, tmp_win->frame);
3291                         SetRaiseWindow(tmp_win);
3292                         if (Scr->Virtual &&
3293                                 tmp_win->VirtualDesktopDisplayWindow)
3294                             XRaiseWindow(dpy,
3295                                          tmp_win->VirtualDesktopDisplayWindow);
3296                     }
3297                 }
3298
3299                 if (ConstMove)
3300                 {
3301                     switch (constMoveDir)
3302                     {
3303                         case MOVE_NONE:
3304                             if (eventp->xmotion.x_root < constMoveXL ||
3305                                         eventp->xmotion.x_root > constMoveXR)
3306                             {
3307                                 constMoveDir = MOVE_HORIZ;
3308                             }
3309                             if (eventp->xmotion.y_root < constMoveYT ||
3310                                         eventp->xmotion.y_root > constMoveYB)
3311                             {
3312                                 constMoveDir = MOVE_VERT;
3313                             }
3314                             XQueryPointer(dpy, DragWindow, &JunkRoot,
3315                                           &JunkChild, &JunkX, &JunkY,
3316                                           &DragX, &DragY, &JunkMask);
3317                             break;
3318                         case MOVE_VERT:
3319                             constMoveY = eventp->xmotion.y_root - DragY -
3320                                          JunkBW;
3321                             break;
3322                         case MOVE_HORIZ:
3323                             constMoveX = eventp->xmotion.x_root - DragX -
3324                                          JunkBW;
3325                             break;
3326                     }
3327
3328                     xl = constMoveX;
3329                     yt = constMoveY;
3330                 }
3331                 else if (DragWindow != None)
3332                 {
3333                     /* added 'movefromcenter' and 'moving_icon' - djhjr - 10/4/02 */
3334                     if (!menuFromFrameOrWindowOrTitlebar &&
3335                                 !movefromcenter && !(moving_icon && fromMenu))
3336                     {
3337                         xl = eventp->xmotion.x_root - DragX - JunkBW;
3338                         yt = eventp->xmotion.y_root - DragY - JunkBW;
3339                     }
3340                     else
3341                     {
3342                         xl = eventp->xmotion.x_root - (DragWidth / 2);
3343                         yt = eventp->xmotion.y_root - (DragHeight / 2);
3344                     }
3345                 }
3346
3347                 if ((ConstMove && constMoveDir != MOVE_NONE) ||
3348                         DragWindow != None)
3349                 {
3350                     int width = DragWidth + 2 * JunkBW;
3351                     int height = DragHeight + 2 * JunkBW;
3352
3353                     if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
3354                     {
3355                         xr = xl + width;
3356                         yb = yt + height;
3357
3358                         if (xl < 0) xl = 0;
3359                         if (xr > Scr->MyDisplayWidth)
3360                             xl = Scr->MyDisplayWidth - width;
3361
3362                         if (yt < 0) yt = 0;
3363                         if (yb > Scr->MyDisplayHeight)
3364                             yt = Scr->MyDisplayHeight - height;
3365                     }
3366
3367                     CurrentDragX = xl;
3368                     CurrentDragY = yt;
3369
3370 /* djhjr - 6/22/01 10/6/02 */
3371 #ifndef NO_SOUND_SUPPORT
3372                     if ((!ConstMove || constMoveDir != MOVE_NONE) &&
3373                                 did_playsound == FALSE)
3374                     {
3375                         PlaySound(func);
3376                         did_playsound = TRUE;
3377                     }
3378 #endif
3379
3380 /* djhjr - 4/7/98
3381                     if (Scr->OpaqueMove)
3382 */
3383                     if (tmp_win->opaque_move)
3384                         XMoveWindow(dpy, DragWindow, xl, yt);
3385                     else
3386                         MoveOutline(eventp->xmotion.root, xl, yt,
3387                                     width, height, tmp_win->frame_bw,
3388 /* djhjr - 4/22/96
3389                                     moving_icon ? 0 : tmp_win->title_height);
3390 */
3391                                     moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
3392
3393 /* djhjr - 4/17/98
3394                     * move the small representation window
3395                     * this knows a bit much about the internals i guess
3396                     * XMoveWindow(dpy, tmp_win->VirtualDesktopDisplayWindow, SCALE_D(xl), SCALE_D(yt));
3397 */
3398                     if (Scr->VirtualReceivesMotionEvents)
3399                     {
3400                         tmp_win->virtual_frame_x = R_TO_V_X(xl);
3401                         tmp_win->virtual_frame_y = R_TO_V_Y(yt);
3402 /* djhjr - 5/24/03
3403                         MoveResizeDesktop(tmp_win, Scr->NoRaiseMove);
3404 */
3405                         MoveResizeDesktop(tmp_win, TRUE);
3406                     }
3407
3408                     /* djhjr - 4/27/96 */
3409                     DisplayPosition (xl, yt);
3410                 }
3411             }
3412
3413 /* djhjr - 7/17/98
3414             * djhjr - 4/7/98 *
3415             if (!Scr->NoGrabServer) XUngrabServer(dpy);
3416 */
3417             if (!tmp_win->opaque_move) XUngrabServer(dpy);
3418
3419             /* djhjr - 4/27/96 */
3420             XUnmapWindow (dpy, Scr->SizeWindow);
3421
3422             MovedFromKeyPress = False;
3423
3424             if (!tmp_win->opaque_move)
3425                 UninstallRootColormap();
3426
3427             /* discard queued enter and leave events - djhjr - 5/23/03 */
3428             while (XCheckMaskEvent(dpy, EnterWindowMask | LeaveWindowMask,
3429                                    &Event))
3430                 ;
3431
3432             /* from events.c:HandleButtonRelease() - djhjr - 10/6/02 */
3433             if (!Scr->NoRaiseMove)
3434             {
3435                 RaiseStickyAbove(); /* DSE */
3436                 RaiseAutoPan();
3437             }
3438
3439             /* update virtual coords */
3440             tmp_win->virtual_frame_x = Scr->VirtualDesktopX + tmp_win->frame_x;
3441             tmp_win->virtual_frame_y = Scr->VirtualDesktopY + tmp_win->frame_y;
3442
3443             /* UpdateDesktop() hoses the stacking order - djhjr - 10/6/02 */
3444 /* djhjr - 5/24/03
3445             MoveResizeDesktop(tmp_win, Scr->NoRaiseMove);
3446 */
3447             MoveResizeDesktop(tmp_win, Cancel | Scr->NoRaiseMove);
3448
3449             /* djhjr - 10/4/02 10/6/02 */
3450             if (Context == C_VIRTUAL_WIN)
3451             {
3452                 /*
3453                  * Mask a bug that calls MoveOutline(zeros) after the
3454                  * border has been repainted, leaving artifacts. I think
3455                  * I know what the bug is, but I can't seem to fix it.
3456                  */
3457                 if (Scr->BorderBevelWidth > 0) PaintBorders(tmp_win, False);
3458
3459                 JunkX = tmp_win->virtual_frame_x + tmp_win->frame_width / 2;
3460                 JunkY = tmp_win->virtual_frame_y + tmp_win->frame_height / 2;
3461                 XWarpPointer(dpy, None, Scr->VirtualDesktopDisplayOuter,
3462                              0, 0, 0, 0, SCALE_D(JunkX), SCALE_D(JunkY));
3463             }
3464
3465             /* djhjr - 6/4/98 */
3466             /* don't re-map if the window is the virtual desktop - djhjr - 2/28/99 */
3467             if (Scr->VirtualReceivesMotionEvents &&
3468                         /* !tmp_win->opaque_move && */
3469                         tmp_win->w != Scr->VirtualDesktopDisplayOuter)
3470             {
3471                 XUnmapWindow(dpy, Scr->VirtualDesktopDisplay);
3472                 XMapWindow(dpy, Scr->VirtualDesktopDisplay);
3473             }
3474
3475             MoveFunction = F_NOFUNCTION;        /* clear for DispatchEvent() */
3476
3477             /* sanity check (also in events.c:HandleButtonRelease()) - djhjr - 10/6/02 */
3478             DragWindow = None;
3479             ConstMove = FALSE;
3480
3481             break;
3482         }
3483     case F_FUNCTION:
3484         {
3485             MenuRoot *mroot;
3486             MenuItem *mitem;
3487                 Cursor cursor;
3488
3489             if ((mroot = FindMenuRoot(action)) == NULL)
3490             {
3491                 fprintf (stderr, "%s: couldn't find function \"%s\"\n",
3492                          ProgramName, action);
3493                 return TRUE;
3494             }
3495
3496 /*
3497  * Changed this 'if ()' for deferred keyboard events (see also events.c)
3498  * Submitted by Michel Eyckmans
3499  *
3500                 if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
3501  */
3502                 if ((cursor = NeedToDefer(mroot)) != None && DeferExecution(context, func, cursor))
3503                         return TRUE;
3504                 else
3505                 {
3506                         for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
3507                         {
3508                                 if (!ExecuteFunction (mitem->func, mitem->action, w,
3509                                                 tmp_win, eventp, context, pulldown))
3510                                 break;
3511                         }
3512                 }
3513         }
3514         break;
3515
3516     case F_DEICONIFY:
3517     case F_ICONIFY:
3518         if (DeferExecution(context, func, Scr->SelectCursor))
3519             return TRUE;
3520
3521         /* added '|| (...)' - djhjr - 6/3/03 */
3522         if (tmp_win->icon ||
3523                 (func == F_DEICONIFY && tmp_win == tmp_win->list->twm))
3524         {
3525 /* djhjr - 6/3/03 */
3526 #ifndef NO_SOUND_SUPPORT
3527             PlaySound(func);
3528 #endif
3529
3530             DeIconify(tmp_win);
3531
3532                 /*
3533                  * now HERE's a fine bit of kludge! it's to mask a hole in the
3534                  * code I can't find that messes up when trying to warp to the
3535                  * de-iconified window not in the real screen when WarpWindows
3536                  * isn't used. see also the change in DeIconify().
3537                  * djhjr - 1/24/98
3538                  */
3539                 if (!Scr->WarpWindows && (Scr->WarpCursor ||
3540                                 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)))
3541                 {
3542                         RaiseStickyAbove();                                 /* DSE */
3543                         RaiseAutoPan();                                     
3544
3545                         WarpToWindow(tmp_win);                              /* PF */
3546                 }
3547         }
3548         else if (func == F_ICONIFY)
3549         {
3550                 /* djhjr - 9/10/99 */
3551                 TwmDoor *d;
3552                 TwmWindow *tmgr = NULL, *twin = NULL;
3553                 MenuRoot *mr;
3554
3555                 /* sanity check for what's next - djhjr - 9/10/99 */
3556                 if (XFindContext(dpy, tmp_win->w, DoorContext,
3557                                 (caddr_t *)&d) != XCNOENT)
3558                 {
3559                         twin = tmp_win;
3560                         tmp_win = d->twin;
3561                 }
3562
3563                 /*
3564                  * don't iconify if there's no way to get it back - not fool-proof
3565                  * djhjr - 9/10/99
3566                  */
3567                 if (tmp_win->iconify_by_unmapping)
3568                 {
3569                         /* iconified by unmapping */
3570
3571                         if (tmp_win->list) tmgr = tmp_win->list->iconmgr->twm_win;
3572
3573                         if ((tmgr && !tmgr->mapped && tmgr->iconify_by_unmapping) ||
3574                                         ((Scr->IconManagerDontShow ||
3575                                         LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class)) &&
3576                                         LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class) == (char *)NULL))
3577                         {
3578                                 /* icon manager not mapped or not shown in one */
3579
3580                                 if (have_twmwindows == -1)
3581                                 {
3582                                         have_twmwindows = 0;
3583
3584                                         /* better than two calls to FindMenuRoot() */
3585                                         for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
3586                                                 if (strcmp(mr->name, TWM_WINDOWS) == 0 ||
3587                                                                 strcmp(mr->name, VTWM_WINDOWS) == 0)
3588                                                 {
3589                                                         /* djhjr - 9/21/99 */
3590                                                         have_twmwindows = FindMenuOrFuncInBindings(C_ALL_BITS, mr, F_NOFUNCTION);
3591                                                         break;
3592                                                 }
3593                                 }
3594                                 /* djhjr - 9/21/99 */
3595                                 if (have_showdesktop == -1)
3596                                         have_showdesktop = FindMenuOrFuncInBindings(C_ALL_BITS, NULL, F_SHOWDESKTOP);
3597                                 if (have_showlist == -1)
3598                                         have_showlist = FindMenuOrFuncInBindings(C_ALL_BITS, NULL, F_SHOWLIST);
3599
3600                                 /* djhjr - 9/21/99 */
3601                                 if (!FindMenuOrFuncInWindows(tmp_win, have_twmwindows, mr, F_NOFUNCTION) ||
3602                                                 LookInList(Scr->DontShowInTWMWindows, tmp_win->full_name, &tmp_win->class))
3603                                 {
3604                                         /* no TwmWindows menu or not shown in it */
3605
3606                                         if (tmp_win->w == Scr->VirtualDesktopDisplayOuter &&
3607                                                         FindMenuOrFuncInWindows(tmp_win, have_showdesktop, NULL, F_SHOWDESKTOP))
3608                                                 ;
3609                                         else if (tmp_win->iconmgr &&
3610                                                         FindMenuOrFuncInWindows(tmp_win, have_showlist, NULL, F_SHOWLIST))
3611                                                 ;
3612                                         else if (tmgr &&
3613                                                         FindMenuOrFuncInWindows(tmgr, have_showlist, NULL, F_SHOWLIST))
3614                                                 ;
3615                                         else
3616                                         {
3617                                                 /* no f.showdesktop or f.showiconmgr */
3618
3619                                                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3620
3621                                                 if (twin) tmp_win = twin;
3622                                                 break;
3623                                         }
3624                                 }
3625                         }
3626                 }
3627
3628                 if (twin) tmp_win = twin;
3629
3630                 if (tmp_win->list || !Scr->NoIconifyIconManagers) /* PF */
3631                 {
3632 /* djhjr - 6/3/03 */
3633 #ifndef NO_SOUND_SUPPORT
3634                         PlaySound(func);
3635 #endif
3636
3637                         Iconify (tmp_win, eventp->xbutton.x_root - EDGE_OFFSET, /* DSE */
3638                                         eventp->xbutton.y_root - EDGE_OFFSET); /* DSE */
3639                 }
3640         }
3641         break;
3642
3643     case F_RAISELOWER:
3644         if (DeferExecution(context, func, Scr->SelectCursor))
3645             return TRUE;
3646
3647         if (!WindowMoved) {
3648             XWindowChanges xwc;
3649
3650             xwc.stack_mode = Opposite;
3651             if (w != tmp_win->icon_w)
3652               w = tmp_win->frame;
3653             XConfigureWindow (dpy, w, CWStackMode, &xwc);
3654             XConfigureWindow (dpy, tmp_win->VirtualDesktopDisplayWindow, CWStackMode, &xwc);
3655             /* ug */
3656             XLowerWindow(dpy, Scr->VirtualDesktopDScreen);
3657         }
3658         break;
3659
3660     case F_RAISE:
3661         if (DeferExecution(context, func, Scr->SelectCursor))
3662             return TRUE;
3663
3664         /* check to make sure raise is not from the WindowFunction */
3665         if (w == tmp_win->icon_w && Context != C_ROOT)
3666             XRaiseWindow(dpy, tmp_win->icon_w);
3667         else
3668         {
3669             XRaiseWindow(dpy, tmp_win->frame);
3670             XRaiseWindow(dpy, tmp_win->VirtualDesktopDisplayWindow);
3671         }
3672
3673         RaiseStickyAbove(); /* DSE */
3674         RaiseAutoPan();
3675
3676         break;
3677
3678     case F_LOWER:
3679         if (DeferExecution(context, func, Scr->SelectCursor))
3680             return TRUE;
3681
3682         if (!(Scr->StickyAbove && tmp_win->nailed)) { /* DSE */
3683                 if (w == tmp_win->icon_w)
3684                     XLowerWindow(dpy, tmp_win->icon_w);
3685                 else
3686                 {    XLowerWindow(dpy, tmp_win->frame);
3687                         XLowerWindow(dpy, tmp_win->VirtualDesktopDisplayWindow);
3688                         XLowerWindow(dpy, Scr->VirtualDesktopDScreen);
3689                 }
3690         } /* DSE */
3691
3692         break;
3693
3694     case F_FOCUS:
3695         if (DeferExecution(context, func, Scr->SelectCursor))
3696             return TRUE;
3697
3698         if (tmp_win->icon == FALSE)
3699         {
3700             if (!Scr->FocusRoot && Scr->Focus == tmp_win)
3701             {
3702                 FocusOnRoot();
3703             }
3704             else
3705             {
3706                 if (Scr->Focus != NULL) {
3707                     SetBorder (Scr->Focus, False);
3708
3709 /* djhjr - 4/25/96
3710                     if (Scr->Focus->hilite_w)
3711                       XUnmapWindow (dpy, Scr->Focus->hilite_w);
3712 */
3713                         PaintTitleHighlight(Scr->Focus, off);
3714
3715                 }
3716
3717                 InstallWindowColormaps (0, tmp_win);
3718
3719 /* djhjr - 4/25/96
3720                 if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
3721 */
3722                 PaintTitleHighlight(tmp_win, on);
3723
3724                 SetBorder (tmp_win, True);
3725                 SetFocus (tmp_win, eventp->xbutton.time);
3726                 Scr->FocusRoot = FALSE;
3727                 Scr->Focus = tmp_win;
3728             }
3729         }
3730         break;
3731
3732     case F_DESTROY:
3733         if (DeferExecution(context, func, Scr->DestroyCursor))
3734             return TRUE;
3735
3736 /* djhjr - 6/22/01 */
3737 #ifndef NO_SOUND_SUPPORT
3738         /* flag for the handler */
3739         if (PlaySound(func)) destroySoundFromFunction = TRUE;
3740 #endif
3741
3742         /* djhjr - 9/10/96 */
3743         if (tmp_win == Scr->VirtualDesktopDisplayTwin)
3744         {
3745                 /* added this 'if (...) ...' and 'if (...) else' - djhjr - 9/21/99 */
3746                 if (have_showdesktop == -1)
3747                         have_showdesktop = FindMenuOrFuncInBindings(C_ALL_BITS, NULL, F_SHOWDESKTOP);
3748                 if (FindMenuOrFuncInWindows(tmp_win, have_showdesktop, NULL, F_SHOWDESKTOP))
3749                         XUnmapWindow(dpy, Scr->VirtualDesktopDisplayTwin->frame);
3750                 else
3751
3752                         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3753                 break;
3754         }
3755
3756         {
3757                 TwmDoor *d;
3758
3759                 if (XFindContext(dpy, tmp_win->w, DoorContext,
3760                                 (caddr_t *) &d) != XCNOENT)
3761                 {
3762 /* djhjr - 9/10/99
3763                         XBell(dpy, 0);
3764 */
3765                         /* for some reason, we don't get the button up event - djhjr - 9/10/99 */
3766                         ButtonPressed = -1;
3767                         door_delete(tmp_win->w, d);
3768
3769                         break;
3770                 }
3771         }
3772
3773         if (tmp_win->iconmgr)           /* don't send ourself a message */
3774         {
3775                 /* added this 'if (...) ...' and 'if (...) else ...' - djhjr - 9/21/99 */
3776                 if (have_showlist == -1)
3777                         have_showlist = FindMenuOrFuncInBindings(C_ALL_BITS, NULL, F_SHOWLIST);
3778                 if (FindMenuOrFuncInWindows(tmp_win, have_showlist, NULL, F_SHOWLIST))
3779
3780                         /* added argument - djhjr - 9/21/99 */
3781                         HideIconManager(tmp_win);
3782
3783                 else
3784                         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3785         }
3786         else
3787         {
3788                 /* djhjr - 4/26/99 */
3789                 AppletDown(tmp_win);
3790
3791             XKillClient(dpy, tmp_win->w);
3792         }
3793         break;
3794
3795     case F_DELETE:
3796         if (DeferExecution(context, func, Scr->DestroyCursor))
3797             return TRUE;
3798
3799 /* djhjr - 6/22/01 */
3800 #ifndef NO_SOUND_SUPPORT
3801         /* flag for the handler */
3802         if (PlaySound(func)) destroySoundFromFunction = TRUE;
3803 #endif
3804
3805         /* djhjr - 9/21/99 */
3806         if (tmp_win == Scr->VirtualDesktopDisplayTwin)
3807         {
3808                 if (have_showdesktop == -1)
3809                         have_showdesktop = FindMenuOrFuncInBindings(C_ALL_BITS, NULL, F_SHOWDESKTOP);
3810                 if (FindMenuOrFuncInWindows(tmp_win, have_showdesktop, NULL, F_SHOWDESKTOP))
3811                         XUnmapWindow(dpy, Scr->VirtualDesktopDisplayTwin->frame);
3812                 else
3813                         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3814
3815                 break;
3816         }
3817
3818         /* djhjr - 9/10/99 */
3819         {
3820                 TwmDoor *d;
3821
3822                 if (XFindContext(dpy, tmp_win->w, DoorContext,
3823                                 (caddr_t *) &d) != XCNOENT)
3824                 {
3825                         /* for some reason, we don't get the button up event - djhjr - 9/10/99 */
3826                         ButtonPressed = -1;
3827                         door_delete(tmp_win->w, d);
3828
3829                         break;
3830                 }
3831         }
3832
3833         if (tmp_win->iconmgr)           /* don't send ourself a message */
3834         {
3835                 /* added this 'if (...) ...' and 'if (...) else ...' - djhjr - 9/21/99 */
3836                 if (have_showlist == -1)
3837                         have_showlist = FindMenuOrFuncInBindings(C_ALL_BITS, NULL, F_SHOWLIST);
3838                 if (FindMenuOrFuncInWindows(tmp_win, have_showlist, NULL, F_SHOWLIST))
3839
3840                         /* added argument - djhjr - 9/21/99 */
3841                         HideIconManager(tmp_win);
3842
3843                 else
3844                         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3845         }
3846         else if (tmp_win->protocols & DoesWmDeleteWindow)
3847         {
3848                 /* djhjr - 4/26/99 */
3849                 AppletDown(tmp_win);
3850
3851           SendDeleteWindowMessage (tmp_win, LastTimestamp());
3852         }
3853         else
3854           DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3855         break;
3856
3857     case F_SAVEYOURSELF:
3858         if (DeferExecution (context, func, Scr->SelectCursor))
3859           return TRUE;
3860
3861         if (tmp_win->protocols & DoesWmSaveYourself)
3862           SendSaveYourselfMessage (tmp_win, LastTimestamp());
3863         else
3864           DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3865         break;
3866
3867     case F_CIRCLEUP:
3868         XCirculateSubwindowsUp(dpy, Scr->Root);
3869         break;
3870
3871     case F_CIRCLEDOWN:
3872         XCirculateSubwindowsDown(dpy, Scr->Root);
3873         break;
3874
3875     case F_EXEC:
3876         PopDownMenu();
3877         if (!Scr->NoGrabServer) {
3878             XUngrabServer (dpy);
3879             XSync (dpy, 0);
3880         }
3881
3882 /* djhjr - 6/22/01 */
3883 #ifndef NO_SOUND_SUPPORT
3884         /* flag for the handler */
3885         if (PlaySound(func)) createSoundFromFunction = TRUE;
3886 #endif
3887
3888         Execute(action);
3889         break;
3890
3891     case F_UNFOCUS:
3892         FocusOnRoot();
3893         break;
3894
3895     case F_CUT:
3896         strcpy(tmp, action);
3897         strcat(tmp, "\n");
3898         XStoreBytes(dpy, tmp, strlen(tmp));
3899         break;
3900
3901     case F_CUTFILE:
3902         ptr = XFetchBytes(dpy, &count);
3903         if (ptr) {
3904             if (sscanf (ptr, "%s", tmp) == 1) {
3905                 XFree (ptr);
3906                 ptr = ExpandFilename(tmp);
3907                 if (ptr) {
3908                     fd = open (ptr, 0);
3909                     if (fd >= 0) {
3910                         count = read (fd, buff, MAX_FILE_SIZE - 1);
3911                         if (count > 0) XStoreBytes (dpy, buff, count);
3912                         close(fd);
3913                     } else {
3914                         fprintf (stderr,
3915                                  "%s:  unable to open cut file \"%s\"\n",
3916                                  ProgramName, tmp);
3917                     }
3918                     if (ptr != tmp) free (ptr);
3919                 }
3920             } else {
3921                 XFree(ptr);
3922             }
3923         } else {
3924             fprintf(stderr, "%s:  cut buffer is empty\n", ProgramName);
3925         }
3926         break;
3927
3928     case F_WARPTOSCREEN:
3929         {
3930             if (strcmp (action, WARPSCREEN_NEXT) == 0) {
3931                 WarpToScreen (Scr->screen + 1, 1);
3932             } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
3933                 WarpToScreen (Scr->screen - 1, -1);
3934             } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
3935                 WarpToScreen (PreviousScreen, 0);
3936             } else {
3937                 WarpToScreen (atoi (action), 0);
3938             }
3939         }
3940         break;
3941
3942     case F_COLORMAP:
3943         {
3944             if (strcmp (action, COLORMAP_NEXT) == 0) {
3945                 BumpWindowColormap (tmp_win, 1);
3946             } else if (strcmp (action, COLORMAP_PREV) == 0) {
3947                 BumpWindowColormap (tmp_win, -1);
3948             } else {
3949                 BumpWindowColormap (tmp_win, 0);
3950             }
3951         }
3952         break;
3953
3954     case F_WARPCLASSNEXT: /* PF */
3955     case F_WARPCLASSPREV: /* PF */
3956                 WarpClass(func == F_WARPCLASSNEXT, tmp_win, action);
3957                 break;
3958
3959     case F_WARPTONEWEST: /* PF */
3960                 /* added '&& warp_if_warpunmapped()' - djhjr - 5/13/98 */
3961                 /* added the second argument - djhjr - 5/28/00 */
3962                 if (Scr->Newest && warp_if_warpunmapped(Scr->Newest, F_NOFUNCTION))
3963                 {
3964                         RaiseStickyAbove();
3965                         RaiseAutoPan();
3966
3967 /* djhjr - 6/3/03 */
3968 #ifndef NO_SOUND_SUPPORT
3969                         PlaySound(func);
3970 #endif
3971
3972                     WarpToWindow(Scr->Newest);
3973                 }
3974                 else
3975                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
3976                 break;
3977         
3978     case F_WARPTO:                                              
3979         {
3980             register TwmWindow *t;                                  
3981             /* djhjr - 6/3/03 */
3982             int did_warpto = FALSE;
3983
3984             for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3985             {
3986                 /*
3987                  * This used to fall through into F_WARP, but the
3988                  * warp_if_warpunmapped() meant this loop couldn't
3989                  * continue to look for a match in the window list.
3990                  * djhjr - 10/27/02
3991                  */
3992
3993                 /* jason@tfs.com */
3994                 if (MatchWinName(action, t) == 0 &&
3995                                 warp_if_warpunmapped(t, func))
3996                 {
3997                         tmp_win = t;                 /* PF */
3998                         RaiseStickyAbove();          /* DSE */
3999                         RaiseAutoPan();
4000
4001                         /* djhjr - 6/3/03 */
4002 #ifndef NO_SOUND_SUPPORT
4003                         PlaySound(func);
4004 #endif
4005                         did_warpto = TRUE;
4006
4007                         WarpToWindow(tmp_win);       /* PF */
4008                         break;
4009                 }
4010             }
4011
4012             /* djhjr - 6/3/03 */
4013             if (!did_warpto)
4014                 DoAudible();
4015         }
4016         break;
4017
4018     case F_WARP:                                                /* PF */
4019         {                                                           /* PF */
4020                 /* added '&& warp_if_warpunmapped()' - djhjr - 5/13/98 */
4021                 /* added the second argument - djhjr - 5/28/00 */
4022                 if (tmp_win && warp_if_warpunmapped(tmp_win, F_NOFUNCTION)) /* PF */
4023                 {
4024                         RaiseStickyAbove();                                 /* DSE */
4025                         RaiseAutoPan();                                     
4026
4027 /* djhjr - 6/3/03 */
4028 #ifndef NO_SOUND_SUPPORT
4029                         PlaySound(func);
4030 #endif
4031
4032                         WarpToWindow(tmp_win);                              /* PF */
4033                 } else {                                                
4034                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */                                         
4035             }                                                       
4036         }                                                           /* PF */
4037         break;
4038
4039     case F_WARPTOICONMGR:
4040         {
4041             TwmWindow *t;
4042             int len;
4043
4044 /* djhjr - 5/13/98
4045             Window raisewin = None, iconwin = None;
4046 */
4047 /*
4048  * raisewin now points to the window's icon manager entry, and
4049  * iconwin now points to raisewin's icon manager - djhjr - 5/30/00
4050  *
4051             TwmWindow *raisewin = None;
4052             Window iconwin = None;
4053 */
4054             WList *raisewin = NULL;
4055             TwmWindow *iconwin = None;
4056
4057             len = strlen(action);
4058             if (len == 0) {
4059                 if (tmp_win && tmp_win->list) {
4060 /* djhjr - 5/13/98
4061                     raisewin = tmp_win->list->iconmgr->twm_win->frame;
4062 */
4063 /* djhjr - 5/30/00
4064                     raisewin = tmp_win->list->iconmgr->twm_win;
4065                     iconwin = tmp_win->list->icon;
4066 */
4067                     raisewin = tmp_win->list;
4068                 } else if (Scr->iconmgr.active) {
4069 /* djhjr - 5/13/98
4070                     raisewin = Scr->iconmgr.twm_win->frame;
4071 */
4072 /* djhjr - 5/30/00
4073                     raisewin = Scr->iconmgr.twm_win;
4074                     iconwin = Scr->iconmgr.active->w;
4075 */
4076                     raisewin = Scr->iconmgr.active;
4077                 }
4078             } else {
4079                 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
4080                     if (strncmp (action, t->icon_name, len) == 0) {
4081                         if (t->list && t->list->iconmgr->twm_win->mapped) {
4082
4083 /* djhjr - 5/13/98
4084                             raisewin = t->list->iconmgr->twm_win->frame;
4085 */
4086 /* djhjr - 5/30/00
4087                             raisewin = t->list->iconmgr->twm_win;
4088                             iconwin = t->list->icon;
4089 */
4090                             raisewin = t->list;
4091                             break;
4092                         }
4093                     }
4094                 }
4095             }
4096
4097                 /* djhjr - 6/14/00 */
4098                 if (!raisewin)
4099                 {
4100                         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4101                         break;
4102                 }
4103
4104                 /* djhjr - 5/30/00 */
4105                 iconwin = raisewin->iconmgr->twm_win;
4106
4107                 /* added '&& warp_if_warpunmapped()' - djhjr - 5/13/98 */
4108                 /* added the second argument - djhjr - 5/28/00 */
4109                 /* was 'raisewin' - djhjr - 5/30/00 */
4110                 if (iconwin && warp_if_warpunmapped(iconwin, F_NOFUNCTION)) {
4111 /* djhjr - 6/3/03 */
4112 #ifndef NO_SOUND_SUPPORT
4113                         PlaySound(func);
4114 #endif
4115
4116 /* djhjr - 5/30/00
4117                         XWarpPointer (dpy, None, iconwin, 0, 0, 0, 0,
4118                                         EDGE_OFFSET, EDGE_OFFSET); * DSE *
4119 */
4120                         WarpInIconMgr(raisewin, iconwin);
4121             } else {
4122                 DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4123             }
4124         }
4125         break;
4126
4127         case F_SQUEEZELEFT:/*RFB*/
4128         {
4129             static SqueezeInfo left_squeeze = { J_LEFT, 0, 0 };
4130             
4131             /* too much dup'd code - djhjr - 9/17/02 */
4132             if (do_squeezetitle(context, func, tmp_win, &left_squeeze))
4133                 return TRUE;    /* deferred */
4134         }
4135         break;
4136
4137         case F_SQUEEZERIGHT:/*RFB*/
4138         {
4139             static SqueezeInfo right_squeeze = { J_RIGHT, 0, 0 };
4140
4141             /* too much dup'd code - djhjr - 9/17/02 */
4142             if (do_squeezetitle(context, func, tmp_win, &right_squeeze))
4143                 return TRUE;    /* deferred */
4144         }
4145         break;
4146         
4147         case F_SQUEEZECENTER:/*RFB*/
4148         {
4149             static SqueezeInfo center_squeeze = { J_CENTER, 0, 0 };
4150
4151             /* too much dup'd code - djhjr - 9/17/02 */
4152             if (do_squeezetitle(context, func, tmp_win, &center_squeeze))
4153                 return TRUE;    /* deferred */
4154         }
4155         break;
4156
4157         case F_RING:/*RFB*/
4158         if (DeferExecution (context, func, Scr->SelectCursor))
4159           return TRUE;
4160         if ( tmp_win->ring.next || tmp_win->ring.prev )
4161                 RemoveWindowFromRing(tmp_win);
4162         else
4163                 AddWindowToRing(tmp_win);
4164 #ifdef ORIGINAL_WARPRINGCOORDINATES /* djhjr - 5/11/98 */
4165     tmp_win->ring.cursor_valid = False;
4166 #endif
4167         break;
4168
4169     case F_WARPRING:
4170         switch (action[0]) {
4171           case 'n':
4172             WarpAlongRing (&eventp->xbutton, True);
4173             break;
4174           case 'p':
4175             WarpAlongRing (&eventp->xbutton, False);
4176             break;
4177           default:
4178             DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4179             break;
4180         }
4181         break;
4182
4183     case F_FILE:
4184         action = ExpandFilename(action);
4185         fd = open(action, 0);
4186         if (fd >= 0)
4187         {
4188             count = read(fd, buff, MAX_FILE_SIZE - 1);
4189             if (count > 0)
4190                 XStoreBytes(dpy, buff, count);
4191
4192             close(fd);
4193         }
4194         else
4195         {
4196             fprintf (stderr, "%s:  unable to open file \"%s\"\n",
4197                      ProgramName, action);
4198         }
4199         break;
4200
4201     case F_REFRESH:
4202         {
4203             XSetWindowAttributes attributes;
4204             unsigned long valuemask;
4205
4206             valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
4207             attributes.background_pixel = Scr->Black;
4208             attributes.backing_store = NotUseful;
4209             attributes.save_under = False;
4210             w = XCreateWindow (dpy, Scr->Root, 0, 0,
4211                                (unsigned int) Scr->MyDisplayWidth,
4212                                (unsigned int) Scr->MyDisplayHeight,
4213                                (unsigned int) 0,
4214                                CopyFromParent, (unsigned int) CopyFromParent,
4215                                (Visual *) CopyFromParent, valuemask,
4216                                &attributes);
4217             XMapWindow (dpy, w);
4218             XDestroyWindow (dpy, w);
4219             XFlush (dpy);
4220         }
4221         break;
4222
4223     case F_WINREFRESH:
4224         if (DeferExecution(context, func, Scr->SelectCursor))
4225             return TRUE;
4226
4227         if (context == C_ICON && tmp_win->icon_w)
4228             w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
4229                 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
4230         else
4231             w = XCreateSimpleWindow(dpy, tmp_win->frame,
4232                 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
4233
4234         XMapWindow(dpy, w);
4235         XDestroyWindow(dpy, w);
4236         XFlush(dpy);
4237         break;
4238
4239      case F_NAIL:
4240         if (DeferExecution(context, func, Scr->SelectCursor))
4241             return TRUE;
4242
4243         tmp_win->nailed = !tmp_win->nailed;
4244         /* update the vd display */
4245         /* UpdateDesktop(tmp_win); Stig */
4246         NailDesktop(tmp_win); /* Stig */
4247
4248 #ifdef DEBUG
4249         fprintf(stdout, "%s:  nail state of %s is now %s\n",
4250                 ProgramName, tmp_win->name, (tmp_win->nailed ? "nailed" : "free"));
4251 #endif /* DEBUG */
4252
4253         RaiseStickyAbove(); /* DSE */
4254         RaiseAutoPan(); /* DSE */
4255
4256         break;
4257
4258         /*
4259          * move a percentage in a particular direction
4260          */
4261     case F_PANDOWN:
4262         PanRealScreen(0, (atoi(action) * Scr->MyDisplayHeight) / 100
4263                 /* DSE */ ,NULL,NULL);
4264         break;
4265     case F_PANLEFT:
4266         PanRealScreen(-((atoi(action) * Scr->MyDisplayWidth) / 100), 0
4267                 /* DSE */ ,NULL,NULL);
4268         break;
4269     case F_PANRIGHT:
4270         PanRealScreen((atoi(action) * Scr->MyDisplayWidth) / 100, 0
4271                 /* DSE */ ,NULL,NULL);
4272         break;
4273     case F_PANUP:
4274         PanRealScreen(0, -((atoi(action) * Scr->MyDisplayHeight) / 100)
4275                 /* DSE */ ,NULL,NULL);
4276         break;
4277         
4278     case F_RESETDESKTOP:
4279                 SetRealScreen(0, 0);
4280                 break;
4281
4282 /*SNUG*/        /* Robert Forsman added these two functions <thoth@ufl.edu> */
4283 /*SNUG*/        {
4284 /*SNUG*/          TwmWindow     *scan;
4285 /*SNUG*/          int           right, left, up, down;
4286 /*SNUG*/          int           inited;
4287 /*SNUG*/    case F_SNUGDESKTOP:
4288 /*SNUG*/
4289 /*SNUG*/          inited = 0;
4290 /*SNUG*/          for (scan = Scr->TwmRoot.next; scan!=NULL; scan = scan->next)
4291 /*SNUG*/            {
4292 /*SNUG*/              if (scan->nailed)
4293 /*SNUG*/                continue;
4294 /*SNUG*/              if (scan->frame_x > Scr->MyDisplayWidth ||
4295 /*SNUG*/                  scan->frame_y > Scr->MyDisplayHeight)
4296 /*SNUG*/                continue;
4297 /*SNUG*/              if (scan->frame_x+scan->frame_width < 0 ||
4298 /*SNUG*/                  scan->frame_y+scan->frame_height < 0)
4299 /*SNUG*/                continue;
4300 /*SNUG*/              if ( inited==0 || scan->frame_x<right )
4301 /*SNUG*/                right = scan->frame_x;
4302 /*SNUG*/              if ( inited==0 || scan->frame_y<up )
4303 /*SNUG*/                up = scan->frame_y;
4304 /*SNUG*/              if ( inited==0 || scan->frame_x+scan->frame_width>left )
4305 /*SNUG*/                left = scan->frame_x+scan->frame_width;
4306 /*SNUG*/              if ( inited==0 || scan->frame_y+scan->frame_height>down )
4307 /*SNUG*/                down = scan->frame_y+scan->frame_height;
4308 /*SNUG*/              inited = 1;
4309 /*SNUG*/            }
4310 /*SNUG*/          if (inited)
4311 /*SNUG*/            {
4312 /*SNUG*/              int       dx,dy;
4313 /*SNUG*/              if (left-right < Scr->MyDisplayWidth && (right<0 || left>Scr->MyDisplayWidth) )
4314 /*SNUG*/                dx = right - ( Scr->MyDisplayWidth - (left-right) ) /2;
4315 /*SNUG*/              else
4316 /*SNUG*/                dx = 0;
4317 /*SNUG*/              if (down-up < Scr->MyDisplayHeight && (up<0 || down>Scr->MyDisplayHeight) )
4318 /*SNUG*/                dy = up - (Scr->MyDisplayHeight - (down-up) ) /2;
4319 /*SNUG*/              else
4320 /*SNUG*/                dy = 0;
4321 /*SNUG*/              if (dx!=0 || dy!=0)
4322 /*SNUG*/                PanRealScreen(dx,dy,NULL,NULL);
4323 /*SNUG*/                                    /* DSE */
4324 /*SNUG*/              else
4325 /*SNUG*/                DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4326 /*SNUG*/            }
4327 /*SNUG*/          else
4328 /*SNUG*/            DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4329 /*SNUG*/          break;
4330 /*SNUG*/
4331 /*SNUG*/     case F_SNUGWINDOW:
4332 /*SNUG*/          if (DeferExecution(context, func, Scr->SelectCursor))
4333 /*SNUG*/            return TRUE;
4334 /*SNUG*/
4335 /*SNUG*/          inited = 0;
4336 /*SNUG*/          right = tmp_win->frame_x;
4337 /*SNUG*/          left = tmp_win->frame_x + tmp_win->frame_width;
4338 /*SNUG*/          up = tmp_win->frame_y;
4339 /*SNUG*/          down = tmp_win->frame_y + tmp_win->frame_height;
4340 /*SNUG*/          inited = 1;
4341 /*SNUG*/          if (inited)
4342 /*SNUG*/            {
4343 /*SNUG*/              int       dx,dy;
4344 /*SNUG*/              dx = 0;
4345 /*SNUG*/              if (left-right < Scr->MyDisplayWidth)
4346 /*SNUG*/                {
4347 /*SNUG*/                if (right<0)
4348 /*SNUG*/                  dx = right;
4349 /*SNUG*/                else if (left>Scr->MyDisplayWidth)
4350 /*SNUG*/                  dx = left - Scr->MyDisplayWidth;
4351 /*SNUG*/                }
4352 /*SNUG*/
4353 /*SNUG*/              dy = 0;
4354 /*SNUG*/              if (down-up < Scr->MyDisplayHeight)
4355 /*SNUG*/                {
4356 /*SNUG*/                if (up<0)
4357 /*SNUG*/                  dy = up;
4358 /*SNUG*/                else if (down>Scr->MyDisplayHeight)
4359 /*SNUG*/                  dy = down - Scr->MyDisplayHeight;
4360 /*SNUG*/                }
4361 /*SNUG*/
4362 /*SNUG*/              if (dx!=0 || dy!=0)
4363 /*SNUG*/                PanRealScreen(dx,dy,NULL,NULL);
4364 /*SNUG*/                                    /* DSE */
4365 /*SNUG*/              else
4366 /*SNUG*/                DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4367 /*SNUG*/            }
4368 /*SNUG*/          else
4369 /*SNUG*/            DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
4370 /*SNUG*/
4371 /*SNUG*/        break;
4372 /*SNUG*/        }
4373
4374     /* Next four submitted by Seth Robertson - 9/9/02 */
4375     case F_BINDBUTTONS:
4376         {
4377             int i, j;
4378          
4379             if (DeferExecution(context, func, Scr->SelectCursor))
4380                 return TRUE;
4381             for (i = 0; i < MAX_BUTTONS+1; i++)
4382                 for (j = 0; j < MOD_SIZE; j++)
4383                     if (Scr->Mouse[i][C_WINDOW][j].func != F_NOFUNCTION)
4384                         XGrabButton(dpy, i, j, tmp_win->frame,
4385                                     True, ButtonPressMask | ButtonReleaseMask,
4386                                     GrabModeAsync, GrabModeAsync, None,
4387                                     Scr->FrameCursor);  
4388             break;
4389         }
4390     case F_BINDKEYS:
4391         {
4392             FuncKey *tmp;
4393
4394             if (DeferExecution(context, func, Scr->SelectCursor))
4395                 return TRUE;
4396             for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
4397                 if (tmp->cont == C_WINDOW)
4398 /* djhjr - 9/10/03
4399                     XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
4400                              GrabModeAsync, GrabModeAsync);
4401 */
4402                     GrabModKeys(tmp_win->w, tmp);
4403             break;
4404         }
4405     case F_UNBINDBUTTONS:
4406         {
4407             int i, j;
4408
4409             if (DeferExecution(context, func, Scr->SelectCursor))
4410                 return TRUE;
4411             for (i = 0; i < MAX_BUTTONS+1; i++)
4412                 for (j = 0; j < MOD_SIZE; j++)
4413                     if (Scr->Mouse[i][C_WINDOW][j].func != F_NOFUNCTION)
4414                         XUngrabButton(dpy, i, j, tmp_win->frame);
4415             break;
4416         }
4417     case F_UNBINDKEYS:
4418         {
4419             FuncKey *tmp;
4420
4421             if (DeferExecution(context, func, Scr->SelectCursor))
4422                 return TRUE;
4423             for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
4424                 if (tmp->cont == C_WINDOW)
4425 /* djhjr - 9/10/03
4426                     XUngrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w);
4427 */
4428                     UngrabModKeys(tmp_win->w, tmp);
4429             break;
4430         }
4431
4432     case F_MOVESCREEN:
4433
4434         /*
4435          * Breaks badly if not called by the default button press.
4436          */
4437
4438         {
4439             long releaseEvent = ButtonRelease;
4440             long movementMask = ButtonMotionMask;
4441 #ifndef NO_SOUND_SUPPORT
4442             int did_playsound = FALSE;
4443 #endif
4444
4445             StartMoveWindowInDesktop(eventp->xmotion);
4446
4447             while (TRUE)
4448             {
4449                 /* added exposure event masks - djhjr - 10/11/01 */
4450                 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
4451                            EnterWindowMask | LeaveWindowMask |
4452                            ExposureMask | VisibilityChangeMask |
4453                            movementMask, &Event);
4454
4455                 /*
4456                  * Don't discard exposure events before release
4457                  * or window borders and/or their titles in the
4458                  * virtual desktop won't get redrawn - djhjr
4459                  */
4460
4461                 /* discard any extra motion events before a release */
4462                 if (Event.type == MotionNotify)
4463                 {
4464                     /* was 'ButtonMotionMask' - djhjr - 10/11/01 */
4465                     while (XCheckMaskEvent(dpy, releaseEvent | movementMask,
4466                                            &Event))
4467                     {
4468                         if (Event.type == releaseEvent)
4469                             break;
4470                     }
4471                 }
4472
4473                 if (Event.type == releaseEvent)
4474                 {
4475                     EndMoveWindowOnDesktop();
4476                     break;
4477                 }
4478
4479                 if (!DispatchEvent()) continue;
4480
4481                 if (Event.type != MotionNotify) continue;
4482
4483 #ifndef NO_SOUND_SUPPORT
4484                 if (did_playsound == FALSE)
4485                 {
4486                     PlaySound(func);
4487                     did_playsound = TRUE;
4488                 }
4489 #endif
4490
4491                 DoMoveWindowOnDesktop(Event.xmotion.x, Event.xmotion.y);
4492             }
4493             
4494             /* discard queued enter and leave events */
4495             while (XCheckMaskEvent(dpy, EnterWindowMask | LeaveWindowMask,
4496                                    &Event))
4497                 ;
4498
4499             /* will clear the XGrabPointer() in events.c:HandleButtonPress() */
4500             ButtonPressed = -1;
4501
4502             break;
4503         }
4504
4505     case F_SNAP:
4506         SnapRealScreen();
4507         /* and update the data structures */
4508         SetRealScreen(Scr->VirtualDesktopX, Scr->VirtualDesktopY);
4509         break;
4510
4511         case F_SNAPREALSCREEN:
4512                 Scr->snapRealScreen = ! Scr->snapRealScreen;
4513                 break;
4514
4515         /* djhjr - 12/14/98 */
4516         case F_STATICICONPOSITIONS:
4517                 Scr->StaticIconPositions = ! Scr->StaticIconPositions;
4518                 break;
4519
4520         /* djhjr - 12/14/98 */
4521         case F_STRICTICONMGR:
4522         {
4523                 TwmWindow *t;
4524                         
4525                 Scr->StrictIconManager = ! Scr->StrictIconManager;
4526                 if (Scr->StrictIconManager)
4527                 {
4528                         for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
4529                                 if (!t->icon)
4530                                         RemoveIconManager(t);
4531                 }
4532                 else
4533                 {
4534                         for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
4535                                 if (!t->list)
4536                                         AddIconManager(t);
4537                 }
4538
4539                 break;
4540         }
4541
4542     case F_SETREALSCREEN:
4543         {
4544                 int newx = Scr->VirtualDesktopX;
4545                 int newy = Scr->VirtualDesktopY;
4546
4547                 /* parse the geometry */
4548                 JunkMask = XParseGeometry (action, &JunkX, &JunkY, &JunkWidth, &JunkHeight);
4549
4550                 if (JunkMask & XValue)
4551                         newx = JunkX;
4552                 if (JunkMask & YValue)
4553                         newy = JunkY;
4554
4555                 if (newx < 0)
4556                         newx = Scr->VirtualDesktopWidth + newx;
4557                 if (newy < 0)
4558                         newy = Scr->VirtualDesktopHeight + newy;
4559
4560                 SetRealScreen(newx, newy);
4561
4562                 break;
4563         }
4564
4565     case F_HIDEDESKTOP:
4566         if (Scr->Virtual)
4567                 XUnmapWindow(dpy, Scr->VirtualDesktopDisplayTwin->frame);
4568         break;
4569
4570     case F_SHOWDESKTOP:
4571         if (Scr->Virtual) {
4572                 XMapWindow(dpy, Scr->VirtualDesktopDisplayTwin->frame);
4573
4574                 /* djhjr - 9/14/96 */
4575                 if (Scr->VirtualDesktopDisplayTwin->icon)
4576                     DeIconify(Scr->VirtualDesktopDisplayTwin);
4577         }
4578         break;
4579
4580     case F_ENTERDOOR:
4581         {
4582                 TwmDoor *d;
4583
4584                 if (XFindContext(dpy, tmp_win->w, DoorContext,
4585                                  (caddr_t *) &d) != XCNOENT)
4586                         door_enter(tmp_win->w, d);
4587                 break;
4588         }
4589
4590     case F_DELETEDOOR:
4591         {       /*marcel@duteca.et.tudelft.nl*/
4592                 TwmDoor *d;
4593
4594                 if (DeferExecution(context, func, Scr->DestroyCursor))
4595                         return TRUE;
4596
4597 /* djhjr - 6/22/01 */
4598 #ifndef NO_SOUND_SUPPORT
4599         /* flag for the handler */
4600         if (PlaySound(func)) destroySoundFromFunction = TRUE;
4601 #endif
4602
4603                 if (XFindContext(dpy, tmp_win->w, DoorContext,
4604                                  (caddr_t *) &d) != XCNOENT)
4605                 {
4606                         /* for some reason, we don't get the button up event - djhjr - 5/13/99 */
4607                         ButtonPressed = -1;
4608
4609                         door_delete(tmp_win->w, d);
4610                 }
4611                 break;
4612         }
4613
4614      case F_NEWDOOR:
4615         PopDownMenu();
4616         door_new();
4617         break;
4618
4619         /* djhjr - 4/20/98 */
4620         case F_NAMEDOOR:
4621         {
4622                 TwmDoor *d;
4623
4624                 if (XFindContext(dpy, tmp_win->w, DoorContext,
4625                                 (caddr_t *) &d) != XCNOENT)
4626                         door_paste_name(tmp_win->w, d);
4627                 break;
4628         }
4629
4630      case F_QUIT:
4631 /* djhjr - 9/14/96 - it's in Done()...
4632         SetRealScreen(0,0);
4633 */
4634
4635 /* djhjr - 6/22/01 */
4636 #ifndef NO_SOUND_SUPPORT
4637         if (PlaySound(func))
4638         {
4639                 /* allow time to emit */
4640                 if (Scr->PauseOnQuit) sleep(Scr->PauseOnQuit);
4641         }
4642         else
4643                 PlaySoundDone();
4644 #endif
4645
4646         Done();
4647         break;
4648
4649      case F_VIRTUALGEOMETRIES:
4650         Scr->GeometriesAreVirtual = ! Scr->GeometriesAreVirtual;
4651         break;
4652
4653         /* submitted by Ugen Antsilevitch - 5/28/00 */
4654         case F_WARPVISIBLE:
4655                 Scr->WarpVisible = ! Scr->WarpVisible;
4656                 break;
4657
4658         /* djhjr - 5/30/00 */
4659         case F_WARPSNUG:
4660                 Scr->WarpSnug = ! Scr->WarpSnug;
4661                 break;
4662
4663 /* djhjr - 6/22/01 */
4664 #ifndef NO_SOUND_SUPPORT
4665         case F_SOUNDS:
4666                 ToggleSounds();
4667                 break;
4668     
4669         /* djhjr - 11/15/02 */
4670         case F_PLAYSOUND:
4671                 PlaySoundAdhoc(action);
4672                 break;
4673 #endif
4674     }
4675
4676     if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
4677     return do_next_action;
4678 }
4679
4680 \f
4681
4682 /***********************************************************************
4683  *
4684  *  Procedure:
4685  *      DeferExecution - defer the execution of a function to the
4686  *          next button press if the context is C_ROOT
4687  *
4688  *  Inputs:
4689  *      context - the context in which the mouse button was pressed
4690  *      func    - the function to defer
4691  *      cursor  - the cursor to display while waiting
4692  *
4693  ***********************************************************************
4694  */
4695
4696 int
4697 DeferExecution(context, func, cursor)
4698 int context, func;
4699 Cursor cursor;
4700 {
4701   if (context == C_ROOT)
4702     {
4703         LastCursor = cursor;
4704         XGrabPointer(dpy, Scr->Root, True,
4705             ButtonPressMask | ButtonReleaseMask,
4706             GrabModeAsync, GrabModeAsync,
4707             Scr->Root, cursor, CurrentTime);
4708
4709         RootFunction = func;
4710         Action = actionHack; /* Submitted by Michel Eyckmans */
4711
4712         return (TRUE);
4713     }
4714
4715     return (FALSE);
4716 }
4717
4718 \f
4719
4720 /***********************************************************************
4721  *
4722  *  Procedure:
4723  *      ReGrab - regrab the pointer with the LastCursor;
4724  *
4725  ***********************************************************************
4726  */
4727
4728 void ReGrab()
4729 {
4730     XGrabPointer(dpy, Scr->Root, True,
4731         ButtonPressMask | ButtonReleaseMask,
4732         GrabModeAsync, GrabModeAsync,
4733         Scr->Root, LastCursor, CurrentTime);
4734 }
4735
4736 \f
4737
4738 /***********************************************************************
4739  *
4740  *  Procedure:
4741  *      NeedToDefer - checks each function in the list to see if it
4742  *              is one that needs to be defered.
4743  *
4744  *  Inputs:
4745  *      root    - the menu root to check
4746  *
4747  ***********************************************************************
4748  */
4749
4750 /* was of type 'int' - Submitted by Michel Eyckmans */
4751 Cursor
4752 NeedToDefer(root)
4753 MenuRoot *root;
4754 {
4755     MenuItem *mitem;
4756
4757     for (mitem = root->first; mitem != NULL; mitem = mitem->next)
4758     {
4759         switch (mitem->func)
4760         {
4761         case F_RESIZE:
4762           return Scr->ResizeCursor; /* Submitted by Michel Eyckmans */
4763         case F_MOVE:
4764         case F_FORCEMOVE:
4765           return Scr->MoveCursor; /* Submitted by Michel Eyckmans */
4766     /* these next four - Submitted by Michel Eyckmans */
4767         case F_DELETE:
4768         case F_DELETEDOOR:
4769         case F_DESTROY:
4770           return Scr->DestroyCursor;
4771         case F_IDENTIFY: /* was with 'F_RESIZE' - Submitted by Michel Eyckmans */
4772         case F_DEICONIFY:
4773         case F_ICONIFY:
4774         case F_RAISELOWER:
4775         case F_RAISE:
4776         case F_LOWER:
4777         case F_FOCUS:
4778         case F_WINREFRESH:
4779         case F_ZOOM:
4780         case F_FULLZOOM:
4781         case F_HORIZOOM:
4782         case F_RIGHTZOOM:
4783         case F_LEFTZOOM:
4784         case F_TOPZOOM:
4785         case F_BOTTOMZOOM:
4786         case F_AUTORAISE:
4787         case F_NAIL:
4788         case F_SNUGWINDOW:
4789             return Scr->SelectCursor;
4790         }
4791     }
4792     return None;
4793 }
4794
4795 \f
4796
4797 void
4798 Execute(s)
4799     char *s;
4800 {
4801     static char buf[256];
4802     char *ds = DisplayString (dpy);
4803     char *colon, *dot1;
4804     char oldDisplay[256];
4805     char *doisplay;
4806     int restorevar = 0;
4807     
4808     char *append_this = " &";
4809     char *es = (char *)malloc(strlen(s)+strlen(append_this)+1);
4810     sprintf(es,s);
4811         /* a new copy of s, with extra space incase -- DSE */
4812
4813         if (Scr->EnhancedExecResources) /* DSE */
4814                 {    
4815             /* chop all space characters from the end of the string */
4816         while ( isspace ( es[strlen(es)-1] ) )
4817                 {
4818                 es[strlen(es)-1] = '\0';
4819                         }
4820                 switch ( es[strlen(es)-1] ) /* last character */
4821                         {
4822                         case ';':
4823                                 es[strlen(es)-1] = '\0'; /* remove the semicolon */
4824                                 break;
4825                         case '&': /* already there so do nothing */
4826                                 break;
4827                         default:
4828                                 strcat(es,append_this); /* don't block the window manager */
4829                                 break;
4830                         }
4831                 }
4832
4833     oldDisplay[0] = '\0';
4834     doisplay=getenv("DISPLAY");
4835     if (doisplay)
4836                 strcpy (oldDisplay, doisplay);
4837
4838     /*
4839      * Build a display string using the current screen number, so that
4840      * X programs which get fired up from a menu come up on the screen
4841      * that they were invoked from, unless specifically overridden on
4842      * their command line.
4843      */
4844     colon = rindex (ds, ':');
4845     if (colon) {                        /* if host[:]:dpy */
4846         strcpy (buf, "DISPLAY=");
4847         strcat (buf, ds);
4848         colon = buf + 8 + (colon - ds); /* use version in buf */
4849         dot1 = index (colon, '.');      /* first period after colon */
4850         if (!dot1) dot1 = colon + strlen (colon);  /* if not there, append */
4851         (void) sprintf (dot1, ".%d", Scr->screen);
4852         putenv (buf);
4853         restorevar = 1;
4854     }
4855
4856     (void) system (es); /* DSE */
4857     free (es); /* DSE */
4858
4859     if (restorevar) {           /* why bother? */
4860         (void) sprintf (buf, "DISPLAY=%s", oldDisplay);
4861         putenv (buf);
4862     }
4863 }
4864
4865 \f
4866
4867 /***********************************************************************
4868  *
4869  *  Procedure:
4870  *      FocusOnRoot - put input focus on the root window
4871  *
4872  ***********************************************************************
4873  */
4874
4875 void
4876 FocusOnRoot()
4877 {
4878     SetFocus ((TwmWindow *) NULL, LastTimestamp());
4879     if (Scr->Focus != NULL)
4880     {
4881         SetBorder (Scr->Focus, False);
4882
4883 /* djhjr - 4/25/96
4884         if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
4885 */
4886         PaintTitleHighlight(Scr->Focus, off);
4887
4888     }
4889     InstallWindowColormaps(0, &Scr->TwmRoot);
4890     Scr->Focus = NULL;
4891     Scr->FocusRoot = TRUE;
4892 }
4893
4894 void DeIconify(tmp_win)
4895 TwmWindow *tmp_win;
4896 {
4897     TwmWindow *t;
4898
4899     /*
4900      * De-iconify the main window first
4901      */
4902
4903     /* re-vamped the zoom stuff - djhjr - 10/11/01 */
4904     if (Scr->DoZoom && Scr->ZoomCount > 0)
4905     {
4906         IconMgr *ipf = NULL;
4907         Window wt = None, wf = None;
4908
4909         if (tmp_win->icon)
4910         {
4911             if (tmp_win->icon_on)
4912             {
4913                 wf = tmp_win->icon_w; wt = tmp_win->frame;
4914             }
4915             else if (tmp_win->list) /* djhjr - 10/11/01 */
4916             {
4917                 wf = tmp_win->list->w; wt = tmp_win->frame;
4918                 ipf = tmp_win->list->iconmgr;
4919             }
4920             else if (tmp_win->group != None)
4921             {
4922                 for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
4923                     if (tmp_win->group == t->w)
4924                     {
4925                         if (t->icon_on)
4926                             wf = t->icon_w;
4927                         else if (t->list) /* djhjr - 10/11/01 */
4928                         {
4929                             wf = t->list->w;
4930                             ipf = t->list->iconmgr;
4931                         }
4932
4933                         wt = tmp_win->frame;
4934                         break;
4935                     }
4936             }
4937         }
4938
4939         /* added Zoom()s args to iconmgrs - djhjr - 10/11/01 */
4940         if (Scr->ZoomZoom || (wf != None && wt != None))
4941             Zoom(wf, ipf, wt, NULL);    /* RFBZOOM */
4942     }
4943
4944     XMapWindow(dpy, tmp_win->w);
4945     tmp_win->mapped = TRUE;
4946
4947     if (Scr->NoRaiseDeicon)
4948         XMapWindow(dpy, tmp_win->frame);
4949     else
4950     {
4951         XMapRaised(dpy, tmp_win->frame);
4952         XRaiseWindow(dpy, tmp_win->VirtualDesktopDisplayWindow);
4953     }
4954     SetMapStateProp(tmp_win, NormalState);
4955
4956     if (tmp_win->icon_w) {
4957         XUnmapWindow(dpy, tmp_win->icon_w);
4958         IconDown (tmp_win);
4959     }
4960
4961     tmp_win->icon = FALSE;
4962     tmp_win->icon_on = FALSE;
4963
4964     if (tmp_win->list)
4965         XUnmapWindow(dpy, tmp_win->list->icon);
4966
4967     /*
4968      * RemoveIconManager() done in events.c:HandleMapNotify()
4969      */
4970
4971     UpdateDesktop(tmp_win);
4972
4973     /*
4974      * Now de-iconify transients
4975      */
4976
4977     for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
4978     {
4979         if (t->transient && t->transientfor == tmp_win->w)
4980         {
4981             /* this 'if (...) else' (see also Iconify()) - djhjr - 6/22/99 */
4982             if (Scr->DontDeiconifyTransients && t->icon_w &&
4983                         t->icon == TRUE && t->icon_on == FALSE)
4984             {
4985                 IconUp(t);
4986                 XMapRaised(dpy, t->icon_w);
4987                 t->icon_on = TRUE;
4988             }
4989             else
4990             {
4991                 /* added Zoom()s args to iconmgrs - djhjr - 10/11/01 */
4992                 if (t->icon_on)
4993                     Zoom(t->icon_w, NULL, t->frame, NULL);
4994                 else
4995                     Zoom(tmp_win->icon_w, NULL, t->frame, NULL);
4996
4997                 XMapWindow(dpy, t->w);
4998                 t->mapped = TRUE;
4999
5000                 if (Scr->NoRaiseDeicon)
5001                     XMapWindow(dpy, t->frame);
5002                 else
5003                 {
5004                     XMapRaised(dpy, t->frame);
5005                     XRaiseWindow(dpy, t->VirtualDesktopDisplayWindow);
5006                 }
5007                 SetMapStateProp(t, NormalState);
5008
5009                 if (t->icon_w)
5010                 {
5011                     XUnmapWindow(dpy, t->icon_w);
5012                     IconDown (t);
5013                 }
5014
5015                 t->icon = FALSE;
5016                 t->icon_on = FALSE;
5017
5018                 if (t->list) XUnmapWindow(dpy, t->list->icon);
5019
5020                 /*
5021                  * RemoveIconManager() done in events.c:HandleMapNotify()
5022                  */
5023
5024                 UpdateDesktop(t);
5025             }
5026         }
5027     }
5028
5029     RaiseStickyAbove(); /* DSE */
5030     RaiseAutoPan();
5031
5032     /*
5033      * added '&& Scr->WarpWindows'.
5034      * see the kludge in ExecuteFunction(F_ICONIFY, ...).
5035      * djhjr - 1/24/98
5036      */
5037     if (((Scr->WarpCursor ||
5038                 LookInList(Scr->WarpCursorL, tmp_win->full_name,
5039                                 &tmp_win->class)) &&
5040                 tmp_win->icon) && Scr->WarpWindows)
5041         WarpToWindow (tmp_win);
5042
5043     XSync (dpy, 0);
5044 }
5045
5046 \f
5047
5048 void Iconify(tmp_win, def_x, def_y)
5049 TwmWindow *tmp_win;
5050 int def_x, def_y;
5051 {
5052     TwmWindow *t;
5053     int iconify;
5054     XWindowAttributes winattrs;
5055     unsigned long eventMask;
5056     /* djhjr - 6/22/99 */
5057     short fake_icon;
5058
5059     iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
5060     if (iconify)
5061     {
5062         if (tmp_win->icon_w == None)
5063             CreateIconWindow(tmp_win, def_x, def_y);
5064         else
5065             IconUp(tmp_win);
5066
5067         XMapRaised(dpy, tmp_win->icon_w);
5068         
5069         RaiseStickyAbove(); /* DSE */
5070         RaiseAutoPan();
5071     }
5072
5073     XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
5074     eventMask = winattrs.your_event_mask;
5075
5076     /*
5077      * Iconify transients first
5078      */
5079
5080     for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
5081       {
5082         if (t->transient && t->transientfor == tmp_win->w)
5083           {
5084
5085             /* RemoveFromDesktop(t); Stig */
5086
5087             /*
5088              * Prevent the receipt of an UnmapNotify, since that would
5089              * cause a transition to the Withdrawn state.
5090              */
5091             t->mapped = FALSE;
5092             XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
5093             XUnmapWindow(dpy, t->w);
5094             XSelectInput(dpy, t->w, eventMask);
5095             XUnmapWindow(dpy, t->frame);
5096
5097             /* moved to make zooms more aesthetically pleasing -- DSE */
5098             if (iconify)
5099             {
5100                 /* added Zoom()s args to iconmgrs - djhjr - 10/11/01 */
5101                 if (t->icon_on)
5102                   Zoom(t->icon_w, NULL, tmp_win->icon_w, NULL);
5103                 else
5104                   Zoom(t->frame, NULL, tmp_win->icon_w, NULL);
5105             }
5106
5107             if (t->icon_w)
5108               XUnmapWindow(dpy, t->icon_w);
5109             SetMapStateProp(t, IconicState);
5110             SetBorder (t, False);
5111             if (t == Scr->Focus)
5112               {
5113                 SetFocus ((TwmWindow *) NULL, LastTimestamp());
5114                 Scr->Focus = NULL;
5115                 Scr->FocusRoot = TRUE;
5116               }
5117
5118             /*
5119              * let current status ride, but "fake out" UpdateDesktop()
5120              * (see also DeIconify()) - djhjr - 6/22/99
5121              */
5122             fake_icon = t->icon;
5123
5124             t->icon = TRUE;
5125             t->icon_on = FALSE;
5126
5127             /* djhjr - 10/2/01 */
5128             if (Scr->StrictIconManager)
5129                 if (!t->list)
5130                     AddIconManager(t);
5131
5132             if (t->list) XMapWindow(dpy, t->list->icon);
5133
5134             UpdateDesktop(t);
5135
5136             /* restore icon status - djhjr - 6/22/99 */
5137             t->icon = fake_icon;
5138           }
5139       }
5140
5141     /*
5142      * Now iconify the main window
5143      */
5144
5145 /*    if (iconify) RFBZOOM*/
5146
5147     /* RemoveFromDesktop(tmp_win); Stig */
5148
5149     /*
5150      * Prevent the receipt of an UnmapNotify, since that would
5151      * cause a transition to the Withdrawn state.
5152      */
5153     tmp_win->mapped = FALSE;
5154     XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
5155     XUnmapWindow(dpy, tmp_win->w);
5156     XSelectInput(dpy, tmp_win->w, eventMask);
5157     XUnmapWindow(dpy, tmp_win->frame);
5158
5159     SetMapStateProp(tmp_win, IconicState);
5160
5161     SetBorder (tmp_win, False);
5162     if (tmp_win == Scr->Focus)
5163     {
5164         SetFocus ((TwmWindow *) NULL, LastTimestamp());
5165         Scr->Focus = NULL;
5166         Scr->FocusRoot = TRUE;
5167     }
5168
5169     tmp_win->icon = TRUE;
5170     if (iconify)
5171         tmp_win->icon_on = TRUE;
5172     else
5173         tmp_win->icon_on = FALSE;
5174
5175     /* djhjr - 10/2/01 */
5176     if (Scr->StrictIconManager)
5177         if (!tmp_win->list)
5178             AddIconManager(tmp_win);
5179
5180     /* moved to make zooms more aesthetically pleasing -- DSE */
5181     /* moved again to ensure an icon manager entry exists - djhjr - 10/11/01 */
5182     /* added Zoom()s args to iconmgrs - djhjr - 10/11/01 */
5183     if (iconify)
5184         Zoom(tmp_win->frame, NULL, tmp_win->icon_w, NULL);
5185     else if (tmp_win->list) /* djhjr - 10/11/01 */
5186         Zoom(tmp_win->frame, NULL, tmp_win->list->w, tmp_win->list->iconmgr);
5187
5188     if (tmp_win->list)
5189         XMapWindow(dpy, tmp_win->list->icon);
5190
5191     UpdateDesktop(tmp_win);
5192     XSync (dpy, 0);
5193 }
5194
5195 \f
5196
5197 static void Identify (t)
5198 TwmWindow *t;
5199 {
5200     int i, n, twidth, width, height;
5201     int x, y;
5202     unsigned int wwidth, wheight, bw, depth;
5203     Window junk;
5204     int px, py, dummy;
5205     unsigned udummy;
5206
5207 /* djhjr - 6/22/01 */
5208 #ifndef NO_SOUND_SUPPORT
5209     PlaySound(F_IDENTIFY);
5210 #endif
5211
5212     n = 0;
5213     (void) sprintf(Info[n++], "%s", Version);
5214     Info[n++][0] = '\0';
5215
5216     if (t) {
5217         XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
5218                       &wwidth, &wheight, &bw, &depth);
5219         (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
5220                                       &x, &y, &junk);
5221
5222 /* looks bad with variable fonts... djhjr - 5/10/96
5223         (void) sprintf(Info[n++], "Name             = \"%s\"", t->full_name);
5224         (void) sprintf(Info[n++], "Class.res_name   = \"%s\"", t->class.res_name);
5225         (void) sprintf(Info[n++], "Class.res_class  = \"%s\"", t->class.res_class);
5226         Info[n++][0] = '\0';
5227         (void) sprintf(Info[n++], "Geometry/root    = %dx%d+%d+%d", wwidth, wheight, x, y);
5228         (void) sprintf(Info[n++], "Border width     = %d", bw);
5229         (void) sprintf(Info[n++], "Depth            = %d", depth);
5230 */
5231         (void) sprintf(Info[n++], "Name:  \"%s\"", t->full_name);
5232         (void) sprintf(Info[n++], "Class.res_name:  \"%s\"", t->class.res_name);
5233         (void) sprintf(Info[n++], "Class.res_class:  \"%s\"", t->class.res_class);
5234         Info[n++][0] = '\0';
5235         (void) sprintf(Info[n++], "Geometry/root:  %dx%d+%d+%d", wwidth, wheight, x, y);
5236         (void) sprintf(Info[n++], "Border width:  %d", bw);
5237         (void) sprintf(Info[n++], "Depth:  %d", depth);
5238
5239         Info[n++][0] = '\0';
5240     }
5241 /* djhjr - 9/19/96 */
5242 #ifndef NO_BUILD_INFO
5243         else
5244         {
5245                 char is_m4, is_xpm;
5246                 char is_rplay; /* djhjr - 6/22/01 */
5247                 char is_regex; /* djhjr - 10/20/01 */
5248                 char is_i18n; /* djhjr - 10/20/01 */
5249
5250 /* djhjr - 6/22/99 */
5251 #ifdef WE_REALLY_DO_WANT_TO_SEE_THIS
5252                 (void) sprintf(Info[n++], "X Server:  %s Version %d.%d Release %d",
5253                                 ServerVendor(dpy), ProtocolVersion(dpy), ProtocolRevision(dpy),
5254                                 VendorRelease(dpy));
5255 #endif
5256
5257                 /*
5258                  * Was a 'do ... while()' that accessed unallocated memory.
5259                  * This and the change to Imakefile submitted by Takeharu Kato
5260                  */
5261                 i = 0;
5262                 while (lastmake[i][0] != '\0')
5263                         (void) sprintf(Info[n++], "%s", lastmake[i++]);
5264
5265 /* djhjr - 1/31/99 */
5266 #ifdef NO_M4_SUPPORT
5267                 is_m4 = '-';
5268 #else
5269                 is_m4 = '+';
5270 #endif
5271 #ifdef NO_XPM_SUPPORT
5272                 is_xpm = '-';
5273 #else
5274                 is_xpm = '+';
5275 #endif
5276 /* djhjr - 6/22/01 */
5277 #ifdef NO_SOUND_SUPPORT
5278                 is_rplay = '-';
5279 #else
5280                 is_rplay = '+';
5281 #endif
5282 /* djhjr - 6/22/01 */
5283 #ifdef NO_REGEX_SUPPORT
5284                 is_regex = '-';
5285 #else
5286                 is_regex = '+';
5287 #endif
5288 /* djhjr - 9/14/03 */
5289 #ifdef NO_I18N_SUPPORT
5290                 is_i18n = '-';
5291 #else
5292                 is_i18n = '+';
5293 #endif
5294                 (void) sprintf(Info[n++],
5295                                "Options:  %ci18n %cm4 %cregex %crplay %cxpm",
5296                                is_i18n, is_m4, is_regex, is_rplay, is_xpm);
5297
5298                 Info[n++][0] = '\0';
5299         }
5300 #endif
5301
5302     (void) sprintf(Info[n++], "Click to dismiss...");
5303
5304     /* figure out the width and height of the info window */
5305
5306 /* djhjr - 4/29/98
5307     height = (n * (Scr->InfoFont.height+2)) + 10; * some padding *
5308 */
5309         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
5310         i = (Scr->InfoBevelWidth > 0) ? Scr->InfoBevelWidth + 8 : 10;
5311         height = (n * (Scr->InfoFont.height+2)) + i; /* some padding */
5312
5313     width = 1;
5314     for (i = 0; i < n; i++)
5315     {
5316 /* djhjr - 9/14/03 */
5317 #ifndef NO_I18N_SUPPORT
5318         twidth = MyFont_TextWidth(&Scr->InfoFont,
5319 #else
5320         twidth = XTextWidth(Scr->InfoFont.font,
5321 #endif
5322             Info[i], strlen(Info[i]));
5323         if (twidth > width)
5324             width = twidth;
5325     }
5326     if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
5327
5328 /* djhjr - 4/29/98
5329     width += 20; * some padding *
5330 */
5331         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
5332         i = (Scr->InfoBevelWidth > 0) ? Scr->InfoBevelWidth + 18 : 20;
5333         width += i; /* some padding */
5334
5335     if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
5336                        &dummy, &dummy, &udummy)) {
5337         px -= (width / 2);
5338         py -= (height / 3);
5339
5340         /* added this 'if ()' - djhjr - 4/29/98 */
5341         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
5342         if (Scr->InfoBevelWidth > 0)
5343         {
5344                 if (px + width + 2 * Scr->InfoBevelWidth >= Scr->MyDisplayWidth)
5345                   px = Scr->MyDisplayWidth - width - 2 * Scr->InfoBevelWidth;
5346                 if (py + height + 2 * Scr->InfoBevelWidth >= Scr->MyDisplayHeight)
5347                   py = Scr->MyDisplayHeight - height - 2 * Scr->InfoBevelWidth;
5348         }
5349         else
5350         {
5351                 if (px + width + BW2 >= Scr->MyDisplayWidth)
5352                   px = Scr->MyDisplayWidth - width - BW2;
5353                 if (py + height + BW2 >= Scr->MyDisplayHeight)
5354                   py = Scr->MyDisplayHeight - height - BW2;
5355         }
5356
5357         if (px < 0) px = 0;
5358         if (py < 0) py = 0;
5359     } else {
5360         px = py = 0;
5361     }
5362
5363     XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
5364
5365 /* done in HandleExpose() in events.c - djhjr - 4/30/98 */
5366 #ifdef NEVER
5367         /* djhjr - 5/9/96 */
5368         if (Scr->use3Dborders > 0)
5369         {
5370                 XGetGeometry (dpy, Scr->InfoWindow, &JunkRoot, &JunkX, &JunkY,
5371                                 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
5372             Draw3DBorder(Scr->InfoWindow, 0, 0, JunkWidth, JunkHeight,
5373 /* djhjr - 4/29/98
5374                          BW, Scr->DefaultC, off, False, False);
5375 */
5376                          Scr->InfoBevelWidth, Scr->DefaultC, off, False, False);
5377         }
5378 #endif
5379
5380     XMapRaised(dpy, Scr->InfoWindow);
5381     InfoLines = n;
5382 }
5383
5384 \f
5385
5386 void SetMapStateProp(tmp_win, state)
5387 TwmWindow *tmp_win;
5388 int state;
5389 {
5390     unsigned long data[2];              /* "suggested" by ICCCM version 1 */
5391
5392     data[0] = (unsigned long) state;
5393     data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
5394                            tmp_win->icon_w);
5395
5396     XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
5397                  PropModeReplace, (unsigned char *) data, 2);
5398 }
5399
5400 \f
5401
5402 Bool GetWMState (w, statep, iwp)
5403     Window w;
5404     int *statep;
5405     Window *iwp;
5406 {
5407     Atom actual_type;
5408     int actual_format;
5409     unsigned long nitems, bytesafter;
5410     unsigned long *datap = NULL;
5411     Bool retval = False;
5412
5413         /* used to test for '!datap' - djhjr - 1/10/98 */
5414     if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
5415                             &actual_type, &actual_format, &nitems, &bytesafter,
5416                             (unsigned char **) &datap) != Success ||
5417                             actual_type == None)
5418       return False;
5419
5420     if (nitems <= 2) {                  /* "suggested" by ICCCM version 1 */
5421         *statep = (int) datap[0];
5422         *iwp = (Window) datap[1];
5423         retval = True;
5424     }
5425
5426     XFree ((char *) datap);
5427     return retval;
5428 }
5429
5430 \f
5431
5432 /*
5433  * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
5434  */
5435
5436 void BumpWindowColormap (tmp, inc)
5437     TwmWindow *tmp;
5438     int inc;
5439 {
5440     int i, j, previously_installed;
5441     ColormapWindow **cwins;
5442
5443     if (!tmp) return;
5444
5445     if (inc && tmp->cmaps.number_cwins > 0) {
5446         cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
5447                                            tmp->cmaps.number_cwins);
5448         if (cwins) {
5449             if ((previously_installed =
5450                 (Scr->cmapInfo.cmaps == &tmp->cmaps) &&
5451                 tmp->cmaps.number_cwins)) {
5452                 for (i = tmp->cmaps.number_cwins; i-- > 0; )
5453                     tmp->cmaps.cwins[i]->colormap->state = 0;
5454             }
5455
5456             for (i = 0; i < tmp->cmaps.number_cwins; i++) {
5457                 j = i - inc;
5458                 if (j >= tmp->cmaps.number_cwins)
5459                     j -= tmp->cmaps.number_cwins;
5460                 else if (j < 0)
5461                     j += tmp->cmaps.number_cwins;
5462                 cwins[j] = tmp->cmaps.cwins[i];
5463             }
5464
5465             free((char *) tmp->cmaps.cwins);
5466
5467             tmp->cmaps.cwins = cwins;
5468
5469             if (tmp->cmaps.number_cwins > 1)
5470                 memset( tmp->cmaps.scoreboard, 0,
5471                        ColormapsScoreboardLength(&tmp->cmaps));
5472
5473             if (previously_installed)
5474                 InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
5475         }
5476     } else
5477         FetchWmColormapWindows (tmp);
5478 }
5479
5480 \f
5481
5482 void HideIconManager(tmp_win)
5483 TwmWindow *tmp_win;
5484 {
5485         /* added this 'if (...) else ...' - djhjr - 9/21/99 */
5486         if (tmp_win == NULL)
5487         {
5488                 name_list *list;
5489
5490                 HideIconMgr(&Scr->iconmgr);
5491
5492                 /*
5493                  * New code in list.c necessitates 'next_entry()' and
5494                  * 'contents_of_entry()' - djhjr - 10/20/01
5495                  */
5496                 for (list = Scr->IconMgrs; list != NULL; list = next_entry(list))
5497                         HideIconMgr((IconMgr *)contents_of_entry(list));
5498         }
5499         else
5500         {
5501                 IconMgr *ip;
5502
5503                 if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name,
5504                                 &tmp_win->class)) == NULL)
5505                         ip = &Scr->iconmgr;
5506
5507                 HideIconMgr(ip);
5508         }
5509 }
5510
5511 /* djhjr - 9/21/99 */
5512 void HideIconMgr(ip)
5513 IconMgr *ip;
5514 {
5515         /* djhjr - 6/10/98 */
5516         if (ip->count == 0)
5517             return;
5518
5519     SetMapStateProp (ip->twm_win, WithdrawnState);
5520     XUnmapWindow(dpy, ip->twm_win->frame);
5521     if (ip->twm_win->icon_w)
5522       XUnmapWindow (dpy, ip->twm_win->icon_w);
5523     ip->twm_win->mapped = FALSE;
5524     ip->twm_win->icon = TRUE;
5525 }
5526
5527 /* djhjr - 9/21/99 */
5528 void ShowIconMgr(ip)
5529 IconMgr *ip;
5530 {
5531         /* added the second condition - djhjr - 6/10/98 */
5532         if (Scr->NoIconManagers || ip->count == 0)
5533                 return;
5534
5535         DeIconify(ip->twm_win);
5536         XRaiseWindow(dpy, ip->twm_win->frame);
5537         XRaiseWindow(dpy, ip->twm_win->VirtualDesktopDisplayWindow);
5538 }
5539
5540
5541 void SetBorder (tmp, onoroff)
5542 TwmWindow       *tmp;
5543 Bool            onoroff;
5544 {
5545         if (tmp->highlight)
5546         {
5547                 /* djhjr - 4/22/96 */
5548                 /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
5549                 if (Scr->BorderBevelWidth > 0)
5550                         PaintBorders (tmp, onoroff);
5551                 else
5552                 {
5553                         if (onoroff)
5554                         {
5555 /* djhjr - 4/24/96
5556                                 XSetWindowBorder (dpy, tmp->frame, tmp->border);
5557 */
5558 /* djhjr - 11/17/97
5559                                 XSetWindowBorder (dpy, tmp->frame, tmp->border_tile.back);
5560 */
5561                                 XSetWindowBorder (dpy, tmp->frame, tmp->border.back);
5562
5563                                 if (tmp->title_w)
5564 /* djhjr - 4/24/96
5565                                         XSetWindowBorder (dpy, tmp->title_w, tmp->border);
5566 */
5567 /* djhjr - 11/17/97
5568                                         XSetWindowBorder (dpy, tmp->title_w, tmp->border_tile.back);
5569 */
5570                                         XSetWindowBorder (dpy, tmp->title_w, tmp->border.back);
5571                         }
5572                         else
5573                         {
5574                                 XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
5575
5576                                 if (tmp->title_w)
5577                                         XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
5578                         }
5579                 }
5580
5581                 /* djhjr - 11/17/97 */
5582                 /* rem'd out test for button color - djhjr - 9/15/99 */
5583                 if (/*Scr->ButtonColorIsFrame && */tmp->titlebuttons)
5584                 {
5585                         int i, nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
5586                         TBWindow *tbw;
5587
5588                         /* collapsed two functions - djhjr - 8/10/98 */
5589                         for (i = 0, tbw = tmp->titlebuttons; i < nb; i++, tbw++)
5590                                 PaintTitleButton(tmp, tbw, (onoroff) ? 2 : 1);
5591                 }
5592         }
5593 }
5594
5595 \f
5596
5597 void DestroyMenu (menu)
5598     MenuRoot *menu;
5599 {
5600     MenuItem *item;
5601
5602     if (menu->w) {
5603         XDeleteContext (dpy, menu->w, MenuContext);
5604         XDeleteContext (dpy, menu->w, ScreenContext);
5605         if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
5606         XDestroyWindow(dpy, menu->w);
5607     }
5608
5609     for (item = menu->first; item; ) {
5610         MenuItem *tmp = item;
5611         item = item->next;
5612         free ((char *) tmp);
5613     }
5614 }
5615
5616 \f
5617
5618 /*
5619  * warping routines
5620  */
5621
5622 /* for moves and resizes from center - djhjr - 10/4/02 */
5623 void WarpScreenToWindow(t)
5624 TwmWindow *t;
5625 {
5626         int warpwin = Scr->WarpWindows;
5627         int warpsnug = Scr->WarpSnug;
5628
5629         Scr->WarpWindows = Scr->WarpSnug = FALSE;
5630         WarpToWindow(t);
5631         Scr->WarpWindows = warpwin;
5632         Scr->WarpSnug = warpsnug;
5633
5634         /*
5635          * This is an attempt to have windows redraw themselves, but
5636          * it doesn't always work (non-raising windows in particular).
5637          */
5638         XSync(dpy, 0);
5639 }
5640
5641 /* was in-lined in WarpToWindow() - djhjr - 5/30/00 */
5642 void WarpWindowOrScreen(t)
5643 TwmWindow *t;
5644 {
5645         
5646         /* 
5647          * we are either moving the window onto the screen, or the screen to the
5648      * window, the distances remain the same
5649      */
5650
5651         if ((t->frame_x < Scr->MyDisplayWidth)
5652             && (t->frame_y < Scr->MyDisplayHeight)
5653             && (t->frame_x + t->frame_width >= 0)
5654             && (t->frame_y + t->frame_height >= 0))
5655         {
5656                 
5657                 /*
5658                  *      window is visible; you can simply
5659                  *      snug it if WarpSnug or WarpWindows is set -- DSE
5660                  */
5661                 
5662                 if (Scr->WarpSnug || Scr->WarpWindows)
5663                 { 
5664                         int right,left,up,down,dx,dy;
5665
5666                         /*
5667                          * Adjustment for border widths submitted by Steve Ratcliffe
5668                          * Note: Do not include the 3D border width!
5669                          */
5670                         right = t->frame_x;
5671                         left = t->frame_x + t->frame_width + 2 * t->frame_bw;
5672                         up = t->frame_y;
5673                         down = t->frame_y + t->frame_height + 2 * t->frame_bw;
5674         
5675                         dx = 0;
5676                         if (left-right < Scr->MyDisplayWidth)
5677                         {
5678                                 if (right<0)
5679                                         dx = right;
5680                                 else if (left>Scr->MyDisplayWidth)
5681                                         dx = left - Scr->MyDisplayWidth;
5682                         }
5683         
5684                         dy = 0;
5685                         if (down-up < Scr->MyDisplayHeight)
5686                         {
5687                                 if (up<0)
5688                                         dy = up;
5689                                 else if (down>Scr->MyDisplayHeight)
5690                                         dy = down - Scr->MyDisplayHeight;
5691                         }
5692         
5693                         if (dx!=0 || dy!=0) {
5694                                 /* added 'Scr->WarpSnug ||' - djhjr - 5/30/00 */
5695                                 if (Scr->WarpSnug || Scr->WarpWindows)
5696                                 {
5697                                         /* move the window */
5698                                         VirtualMoveWindow(t, t->virtual_frame_x - dx,
5699                                             t->virtual_frame_y - dy);
5700                                 }
5701                                 else
5702                                 {
5703                                         /* move the screen */
5704                                         PanRealScreen(dx,dy,NULL,NULL);
5705                                 }
5706                         }
5707                 }
5708         }
5709         else
5710         {
5711
5712                 /*
5713                  *      Window is invisible; we need to move it or the screen.
5714                  */
5715                  
5716                 int xdiff, ydiff;
5717
5718                 xdiff = ((Scr->MyDisplayWidth - t->frame_width) / 2) - t->frame_x;
5719                 ydiff = ((Scr->MyDisplayHeight - t->frame_height) / 2) - t->frame_y;
5720
5721                 /* added 'Scr->WarpSnug ||' - djhjr - 5/30/00 */
5722                 if (Scr->WarpSnug || Scr->WarpWindows)
5723                 {
5724                         /* move the window */
5725                         VirtualMoveWindow(t, t->virtual_frame_x + xdiff,
5726                             t->virtual_frame_y + ydiff);
5727                 }
5728                 else
5729                 {
5730                         /* move the screen */
5731                         PanRealScreen(-xdiff, -ydiff,NULL,NULL); /* DSE */
5732                 }
5733         }
5734
5735         if (t->auto_raise || !Scr->NoRaiseWarp)
5736                 AutoRaiseWindow (t);
5737 }
5738
5739 /* for icon manager management - djhjr - 5/30/00 */
5740 void WarpInIconMgr(w, t)
5741 WList *w;
5742 TwmWindow *t;
5743 {
5744         int x, y, pan_margin = 0;
5745         /* djhjr - 9/9/02 */
5746         int bw = t->frame_bw3D + t->frame_bw;
5747
5748         RaiseStickyAbove();
5749         RaiseAutoPan();                                     
5750
5751         WarpWindowOrScreen(t);
5752
5753         /* was 'Scr->BorderWidth' - djhjr - 9/9/02 */
5754         x = w->x + bw + EDGE_OFFSET + 5;
5755         x += (Scr->IconMgrBevelWidth > 0) ? Scr->IconMgrBevelWidth : bw;
5756         y = w->y + bw + w->height / 2;
5757         y += (Scr->IconMgrBevelWidth > 0) ? Scr->IconMgrBevelWidth : bw;
5758         y += w->iconmgr->twm_win->title_height;
5759
5760         /*
5761          * adjust the pointer for partially visible windows and the
5762          * AutoPan border width
5763          */
5764
5765         if (Scr->AutoPanX) pan_margin = Scr->AutoPanBorderWidth;
5766
5767         if (x + t->frame_x >= Scr->MyDisplayWidth - pan_margin)
5768                 x = Scr->MyDisplayWidth - t->frame_x - pan_margin - 2;
5769         if (x + t->frame_x <= pan_margin)
5770                 x = -t->frame_x + pan_margin + 2;
5771         if (y + t->frame_y >= Scr->MyDisplayHeight - pan_margin)
5772                 y = Scr->MyDisplayHeight - t->frame_y - pan_margin - 2;
5773         if (y + t->frame_y <= pan_margin)
5774                 y = -t->frame_y + pan_margin + 2;
5775
5776         XWarpPointer(dpy, None, t->frame, 0, 0, 0, 0, x, y); /* DSE */
5777 }
5778
5779 /*
5780  * substantially re-written and added passing 'next' to next_by_class()
5781  *
5782  * djhjr - 5/13/98 6/6/98 6/15/98
5783  */
5784 #ifdef ORIGINAL_WARPCLASS
5785 void WarpClass (next, t, class)
5786     int next;
5787     TwmWindow *t;
5788     char *class;
5789 {
5790     int len = strlen(class);
5791
5792     if (!strncmp(class, t->class.res_class, len))
5793         t = next_by_class(t, class);
5794     else
5795         t = next_by_class((TwmWindow *)NULL, class);
5796     if (t) {
5797         if (Scr->WarpUnmapped || t->mapped) {
5798             if (!t->mapped) DeIconify (t);
5799             if (!Scr->NoRaiseWarp)
5800                 {
5801                     XRaiseWindow (dpy, t->frame);
5802                 }
5803             XRaiseWindow (dpy, t->VirtualDesktopDisplayWindow);
5804
5805             RaiseStickyAbove(); /* DSE */
5806             RaiseAutoPan();
5807
5808             WarpToWindow (t);
5809         }
5810     }
5811 }
5812 #else /* ORIGINAL_WARPCLASS */
5813 void WarpClass(next, t, class)
5814     int next;
5815     TwmWindow *t;
5816     char *class;
5817 {
5818     TwmWindow *tt;
5819         XClassHint ch;
5820         int i;
5821
5822         /*
5823          * if an empty class string
5824          *     if a TwmWindow
5825          *         class = the TwmWindow's class
5826          *     else if a window with focus
5827          *         if it's classed
5828          *             class = the focused window's class
5829          *     else
5830          *         return
5831          * if still an empty class string
5832          *     class = "VTWM"
5833          */
5834         if (!strlen(class))
5835         {
5836                 if (t)
5837                         class = t->class.res_class;
5838                 else if (Scr->Focus)
5839                 {
5840                         i = XGetClassHint(dpy, Scr->Focus->w, &ch);
5841                         if (i && !strncmp(class, ch.res_class, strlen(class)))
5842                                 class = ch.res_class;
5843                 }
5844                 /* djhjr - 6/21/00 */
5845                 else
5846                 {
5847                         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
5848                         return;
5849                 }
5850         }
5851         if (!strlen(class) || !strncmp(class, "VTWM", 4))
5852                 class = "VTWM";
5853
5854 /* djhjr - 8/3/98
5855         if (!(tt = next_by_class(next, t, class)))
5856                 if (t) tt = t;
5857 */
5858
5859         /* djhjr - 5/28/00 */
5860         while (1)
5861         {
5862
5863         tt = NULL;
5864         do
5865         {
5866                 if ((tt = next_by_class(next, t, class)))
5867                 {
5868                         /* multiple icon managers: gotta test for those without entries */
5869                         if (tt->iconmgr && tt->iconmgrp->count == 0)
5870                         {
5871                                 t = tt;
5872                                 tt = NULL;
5873                         }
5874                 }
5875                 else if (t)
5876                         tt = t;
5877                 else
5878                         break;
5879         } while (!tt);
5880
5881         /* added the second argument - djhjr - 5/28/00 */
5882         if (tt && warp_if_warpunmapped(tt, (next) ? F_WARPCLASSNEXT: F_WARPCLASSPREV))
5883         {
5884                 RaiseStickyAbove(); /* DSE */
5885                 RaiseAutoPan();
5886
5887 /* djhjr - 6/3/03 */
5888 #ifndef NO_SOUND_SUPPORT
5889                 PlaySound((next) ? F_WARPCLASSNEXT: F_WARPCLASSPREV);
5890 #endif
5891
5892                 WarpToWindow(tt);
5893
5894                 /* djhjr - 5/28/00 */
5895                 break;
5896     }
5897 /* djhjr - 5/28/00
5898         else
5899                 XBell(dpy, 0);
5900 */
5901         t = tt;
5902         } /* while (1) */
5903 }
5904 #endif /* ORIGINAL_WARPCLASS */
5905
5906 \f
5907
5908 /* moved from add_window.c - djhjr - 10/27/02 */
5909 void AddWindowToRing(tmp_win)
5910 TwmWindow *tmp_win;
5911 {
5912         if (Scr->Ring)
5913         {
5914                 /* link window in after Scr->Ring */
5915                 tmp_win->ring.prev = Scr->Ring;
5916                 tmp_win->ring.next = Scr->Ring->ring.next;
5917
5918                 /* Scr->Ring's next's prev points to this */
5919                 /*if (Scr->Ring->ring.next->ring.prev)*/
5920                         Scr->Ring->ring.next->ring.prev = tmp_win;
5921
5922                 /* Scr->Ring's next points to this */
5923                 Scr->Ring->ring.next = tmp_win;
5924         }
5925         else
5926                 tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
5927 }
5928
5929 /* moved from events.c - djhjr - 10/27/02 */
5930 void RemoveWindowFromRing(tmp_win)
5931 TwmWindow *tmp_win;
5932 {
5933         /* unlink window */
5934         if (tmp_win->ring.prev)
5935                 tmp_win->ring.prev->ring.next = tmp_win->ring.next;
5936         if (tmp_win->ring.next)
5937                 tmp_win->ring.next->ring.prev = tmp_win->ring.prev;
5938
5939         /*  if window was only thing in ring, null out ring */
5940         if (Scr->Ring == tmp_win)
5941                 Scr->Ring = (tmp_win->ring.next != tmp_win) ?
5942                             tmp_win->ring.next : (TwmWindow *)NULL;
5943
5944         /* if window was ring leader, set to next (or null) */
5945         if (!Scr->Ring || Scr->RingLeader == tmp_win)
5946                 Scr->RingLeader = Scr->Ring;
5947
5948         tmp_win->ring.next = tmp_win->ring.prev = NULL;
5949 }
5950
5951 void WarpAlongRing (ev, forward)
5952     XButtonEvent *ev;
5953     Bool forward;
5954 {
5955     TwmWindow *r, *head;
5956
5957     /*
5958      * Re-vamped much of this to properly handle icon managers, and
5959      * clean up dumb code I added some time back.
5960      * djhjr - 11/8/01
5961      * Cleaned it up again. I musta been high. Twice.
5962      * djhjr - 10/27/02
5963      */
5964
5965     if (!(head = (Scr->RingLeader) ? Scr->RingLeader : Scr->Ring))
5966     {
5967         DoAudible();
5968         return;
5969     }
5970
5971     if (forward)
5972         r = head->ring.next;
5973     else
5974         r = head->ring.prev;
5975
5976     while (r && r != head)
5977     {
5978         if (r->mapped || warp_if_warpunmapped(r, F_WARPRING))
5979             break;
5980             
5981         r = (forward) ? r->ring.next : r->ring.prev;
5982     }
5983
5984     if (r && r->mapped)
5985     {
5986 #ifdef ORIGINAL_WARPRINGCOORDINATES /* djhjr - 5/11/98 */
5987         TwmWindow *p = Scr->RingLeader, *t;
5988 #endif
5989
5990 /* done in WarpToWindow - djhjr - 10/27/02
5991         Scr->RingLeader = r;
5992 */
5993
5994         RaiseStickyAbove();
5995         RaiseAutoPan();
5996
5997 /* djhjr - 6/3/03 */
5998 #ifndef NO_SOUND_SUPPORT
5999         PlaySound(F_WARPRING);
6000 #endif
6001
6002         WarpToWindow (r);
6003
6004 #ifdef ORIGINAL_WARPRINGCOORDINATES /* djhjr - 5/11/98 */
6005         if (p && p->mapped &&
6006             XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
6007             p == t)
6008         {
6009             p->ring.cursor_valid = True;
6010             p->ring.curs_x = ev->x_root - t->frame_x;
6011             p->ring.curs_y = ev->y_root - t->frame_y;
6012             if (p->ring.curs_x < -p->frame_bw ||
6013                 p->ring.curs_x >= p->frame_width + p->frame_bw ||
6014                 p->ring.curs_y < -p->frame_bw ||
6015                 p->ring.curs_y >= p->frame_height + p->frame_bw)
6016             {
6017                 /* somehow out of window */
6018                 p->ring.curs_x = p->frame_width / 2;
6019                 p->ring.curs_y = p->frame_height / 2;
6020             }
6021         }
6022 #endif
6023     }
6024     else
6025         DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
6026 }
6027
6028 \f
6029
6030 void WarpToScreen (n, inc)
6031     int n, inc;
6032 {
6033     Window dumwin;
6034     int x, y, dumint;
6035     unsigned int dummask;
6036     ScreenInfo *newscr = NULL;
6037
6038     while (!newscr) {
6039                                         /* wrap around */
6040         if (n < 0)
6041           n = NumScreens - 1;
6042         else if (n >= NumScreens)
6043           n = 0;
6044
6045         newscr = ScreenList[n];
6046         if (!newscr) {                  /* make sure screen is managed */
6047             if (inc) {                  /* walk around the list */
6048                 n += inc;
6049                 continue;
6050             }
6051             fprintf (stderr, "%s:  unable to warp to unmanaged screen %d\n",
6052                      ProgramName, n);
6053             DoAudible(); /* was 'XBell()' - djhjr - 6/22/01 */
6054             return;
6055         }
6056     }
6057
6058     if (Scr->screen == n) return;       /* already on that screen */
6059
6060     PreviousScreen = Scr->screen;
6061     XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
6062                    &dumint, &dumint, &dummask);
6063
6064 /* djhjr - 6/3/03 */
6065 #ifndef NO_SOUND_SUPPORT
6066     PlaySound(F_WARPTOSCREEN);
6067 #endif
6068
6069     XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
6070     return;
6071 }
6072
6073 \f
6074
6075 void WarpToWindow (t)
6076 TwmWindow *t;
6077 {
6078         int x, y;
6079         int pan_margin = 0;                     /* djhjr - 5/28/00 */
6080         int bw = t->frame_bw3D + t->frame_bw;   /* djhjr - 9/9/02 */
6081         Window w = t->frame;                    /* djhjr - 5/30/00 */
6082         
6083         WarpWindowOrScreen(t);  /* djhjr - 5/30/00 */
6084
6085 #ifdef ORIGINAL_WARPRINGCOORDINATES /* djhjr - 5/11/98 */
6086         if (t->ring.cursor_valid) {
6087                 x = t->ring.curs_x;
6088                 y = t->ring.curs_y;
6089                 }
6090         else {
6091                 x = t->frame_width / 2;
6092                 y = t->frame_height / 2;
6093                 }
6094 #else
6095         /* added this 'if (...) else' - djhjr - 6/10/98 */
6096         if (t->iconmgr)
6097         {
6098 /* djhjr - 5/30/00
6099                 if (t->iconmgrp->count > 0)
6100                         XWarpPointer(dpy, None, t->iconmgrp->first->icon, 0,0,0,0,
6101                                         EDGE_OFFSET, EDGE_OFFSET);
6102
6103                 return;
6104 */
6105                 if (t->iconmgrp->count > 0)
6106                 {
6107                         w = t->iconmgrp->twm_win->frame;
6108
6109                         /* was 'Scr->BorderWidth' - djhjr - 9/9/02 */
6110                         x = t->iconmgrp->x + bw + EDGE_OFFSET + 5;
6111                         x += (Scr->IconMgrBevelWidth > 0) ? Scr->IconMgrBevelWidth : bw;
6112                         y = t->iconmgrp->y + bw + t->iconmgrp->first->height / 2;
6113                         y += (Scr->IconMgrBevelWidth > 0) ? Scr->IconMgrBevelWidth : bw;
6114                         y += t->iconmgrp->twm_win->title_height;
6115                 }
6116         }
6117         else if (!t->title_w)
6118         {
6119                 /* added this 'if (...) else' - djhjr - 10/16/02 */
6120                 if (Scr->WarpCentered & WARPC_UNTITLED)
6121                 {
6122                         x = t->frame_width / 2;
6123                         y = t->frame_height / 2;
6124                 }
6125                 else
6126                 {
6127                         x = t->frame_width / 2;
6128                         y = (t->wShaped) ? bw : bw / 2; /* djhjr - 9/9/02 */
6129                 }
6130         }
6131         else
6132         {
6133                 /* added this 'if (...) else' - djhjr - 10/16/02 */
6134                 if (Scr->WarpCentered & WARPC_TITLED)
6135                 {
6136                         x = t->frame_width / 2;
6137                         y = t->frame_height / 2;
6138                 }
6139                 else
6140                 {
6141                         /*
6142                          * Added 't->title_x + ' to handle titlebars that
6143                          * aren't flush left.
6144                          * Submitted by Steve Ratcliffe
6145                          * was '(t->frame_bw3D + t->frame_bw)' - djhjr - 9/9/02
6146                          */
6147                         x = t->title_x + t->title_width / 2 + bw;
6148                         y = t->title_height / 2 + bw;
6149                 }
6150         }
6151
6152         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
6153         if (!Scr->BorderBevelWidth > 0) y -= t->frame_bw;
6154 #endif
6155
6156         /*
6157          * adjust the pointer for partially visible windows and the
6158          * AutoPan border width - djhjr - 5/30/00
6159          * was '(t->frame_bw3D + t->frame_bw)' - djhjr - 9/9/02
6160          */
6161
6162         if (Scr->AutoPanX) pan_margin = Scr->AutoPanBorderWidth;
6163
6164         if (x + t->frame_x >= Scr->MyDisplayWidth - pan_margin)
6165                 x = Scr->MyDisplayWidth - t->frame_x - pan_margin - 2;
6166         if (x + t->frame_x <= pan_margin)
6167         {
6168                 if (t->title_w)
6169                         x = t->title_width - (t->frame_x + t->title_width) +
6170                             pan_margin + 2;
6171                 else
6172                         x = -t->frame_x + pan_margin + 2;
6173         }
6174
6175         /* added test for centered warps - djhjr - 10/16/02 */
6176         if (t->title_w && !(Scr->WarpCentered & WARPC_TITLED) &&
6177                         (x < t->title_x || x > t->title_x + t->title_width))
6178         {
6179                 y = t->title_height + bw / 2;
6180         }
6181         if (y + t->frame_y >= Scr->MyDisplayHeight - pan_margin)
6182         {
6183                 y = Scr->MyDisplayHeight - t->frame_y - pan_margin - 2;
6184
6185                 /* move centered warp to titlebar - djhjr - 10/16/02 */
6186                 if (y < t->title_y + t->title_height)
6187                         x = t->title_x + t->title_width / 2 + bw;
6188         }
6189         if (y + t->frame_y <= pan_margin)
6190                 y = -t->frame_y + pan_margin + 2;
6191
6192         /* was 't->frame' - djhjr - 5/30/00 */
6193         XWarpPointer (dpy, None, w, 0, 0, 0, 0, x, y);
6194
6195         /* djhjr - 10/27/02 */
6196         if (t->ring.next) Scr->RingLeader = t;
6197 }
6198
6199 \f
6200
6201 /*
6202  * substantially re-written and added receiving and using 'next'
6203  *
6204  * djhjr - 5/13/98 5/19/98 6/6/98 6/15/98
6205  */
6206 #ifdef ORIGINAL_WARPCLASS
6207 TwmWindow *
6208 next_by_class (t, class)
6209 TwmWindow *t;
6210 char *class;
6211 {
6212     TwmWindow *tt;
6213     int len = strlen(class);
6214
6215     if (t)
6216         for (tt = t->next; tt != NULL; tt = tt->next)
6217             if (!strncmp(class, tt->class.res_class, len)) return tt;
6218     for (tt = Scr->TwmRoot.next; tt != NULL; tt = tt->next)
6219         if (!strncmp(class, tt->class.res_class, len)) return tt;
6220     return NULL;
6221 }
6222 #else /* ORIGINAL_WARPCLASS */
6223 static TwmWindow *
6224 next_by_class (next, t, class)
6225 int next;
6226 TwmWindow *t;
6227 char *class;
6228 {
6229         static TwmWindow *tp = NULL;
6230     TwmWindow *tt, *tl;
6231     int i, len = strlen(class);
6232         XClassHint ch;
6233
6234 #ifdef DEBUG_WARPCLASS
6235         fprintf(stderr, "class=\"%s\", next=%d, %s t, ", class, next, (t) ? "have" : "no");
6236 #endif
6237
6238         /* forward or backward from current */
6239         tl = (next) ? ((tp) ? tp->next : Scr->TwmRoot.next) : ((tp) ? tp->prev : Scr->TwmRoot.prev);
6240         for (tt = (next) ? ((t) ? t->next : tl) : ((t) ? t->prev : tl);
6241                         tt != NULL;
6242                         tt = (next) ? tt->next : tt->prev)
6243                 if (Scr->WarpUnmapped || tt->mapped)
6244                 {
6245                         i = XGetClassHint(dpy, tt->w, &ch);
6246                         if (i && !strncmp(class, ch.res_class, len))
6247                         {
6248 #ifdef DEBUG_WARPCLASS
6249                                 fprintf(stderr, "matched \"%s\" \"%s\"\n", tt->class.res_class, tt->class.res_name);
6250 #endif
6251                                 tp = tt;
6252                                 return tp;
6253                         }
6254                         else
6255                         {
6256 #ifdef DEBUG_WARPCLASS
6257                                 fprintf(stderr, "(1) skipping \"%s\"\n", (i) ? tt->class.res_class : "NO RES_CLASS!");
6258 #endif
6259                                 if (i == 0) break;
6260                         }
6261                 }
6262
6263         /* no match, wrap and retry */
6264         tp = tl = NULL;
6265         for (tt = Scr->TwmRoot.next; tt != NULL; tt = tt->next)
6266                 if (Scr->WarpUnmapped || tt->mapped)
6267                 {
6268                         i = XGetClassHint(dpy, tt->w, &ch);
6269                         if (i && !strncmp(class, ch.res_class, len))
6270                         {
6271                                 if (next)
6272                                 {
6273 #ifdef DEBUG_WARPCLASS
6274                                         fprintf(stderr, "next wrapped to \"%s\ \"%s\"\n", tt->class.res_class, tt->class.res_name);
6275 #endif
6276                                         tp = tt;
6277                                         return tp;
6278                                 }
6279                                 else
6280                                         tl = tt;
6281                         }
6282 #ifdef DEBUG_WARPCLASS
6283                         else
6284                                 fprintf(stderr, "(2) skipping \"%s\"\n", (i) ? tt->class.res_class : "NO RES_CLASS!");
6285 #endif
6286                 }
6287
6288 #ifdef DEBUG_WARPCLASS
6289         i = 0; if (tl) i = XGetClassHint(dpy, tl->w, &ch);
6290         fprintf(stderr, "prev wrapped to \"%s\ \"%s\"\n", (i) ? ch.res_class : "NO RES_CLASS!", (i) ? ch.res_name : "NO RES_CLASS!");
6291 #endif
6292         tp = tl;
6293         return tp;
6294 }
6295 #endif /* ORIGINAL_WARPCLASS */
6296
6297 /* this was inlined in many places, and even more now - djhjr - 5/13/98 */
6298 /* added the second argument - djhjr - 5/28/00 */
6299 static int warp_if_warpunmapped(w, func)
6300 TwmWindow *w;
6301 int func;
6302 {
6303         /* skip empty icon managers - 10/27/02 */
6304         if (w && (w->iconmgr && w->iconmgrp->count == 0))
6305                 return (0);
6306
6307         if (Scr->WarpUnmapped || w->mapped)
6308         {
6309                 /* submitted by Ugen Antsilevitch - 5/28/00 */
6310                 /* if F_NOFUNCTION, override WarpVisible - djhjr - 5/28/00 */
6311                 if (func != F_NOFUNCTION && Scr->WarpVisible)
6312                 {
6313                         int pan_margin = 0;
6314
6315                         if (Scr->AutoPanX) pan_margin = Scr->AutoPanBorderWidth;
6316
6317                         if (w->frame_x >= Scr->MyDisplayWidth - pan_margin ||
6318                                 w->frame_y >= Scr->MyDisplayHeight - pan_margin ||
6319                                 w->frame_x + w->frame_width <= pan_margin ||
6320                                 w->frame_y + w->frame_height <= pan_margin)
6321                         return 0;
6322                 }
6323
6324                 if (!w->mapped) DeIconify(w);
6325                 if (!Scr->NoRaiseWarp) XRaiseWindow(dpy, w->frame);
6326                 XRaiseWindow(dpy, w->VirtualDesktopDisplayWindow);
6327
6328                 return (1);
6329         }
6330
6331         return (0);
6332 }
6333
6334 /* djhjr - 9/17/02 */
6335 static int
6336 do_squeezetitle(context, func, tmp_win, squeeze)
6337 int context, func;
6338 TwmWindow *tmp_win;
6339 SqueezeInfo *squeeze;
6340 {
6341     if (DeferExecution (context, func, Scr->SelectCursor))
6342         return TRUE;
6343
6344     /* honor "Don't Squeeze" resources - djhjr - 9/17/02 */
6345     if (Scr->SqueezeTitle &&
6346                 !LookInList(Scr->DontSqueezeTitleL, tmp_win->full_name, &tmp_win->class))
6347     {
6348         if ( tmp_win->title_height )    /* Not for untitled windows! */
6349         {
6350             PopDownMenu();      /* djhjr - 9/17/02 */
6351
6352 #ifndef NO_SOUND_SUPPORT
6353             PlaySound(func);
6354 #endif
6355
6356             tmp_win->squeeze_info = squeeze;
6357             SetFrameShape( tmp_win );
6358
6359             /* Can't go in SetFrameShape()... - djhjr - 4/1/00 */
6360             if (Scr->WarpCursor ||
6361                         LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class))
6362                 WarpToWindow(tmp_win);
6363         }
6364     }
6365     else
6366         DoAudible();
6367
6368     return FALSE;
6369 }
6370
6371 /*
6372  * Two functions to handle a restart from a SIGUSR1 signal
6373  * (see also twm.c:Done() and twm.c:QueueRestartVtwm())
6374  *
6375  * adapted from TVTWM-pl11 - djhjr - 7/31/98
6376  */
6377
6378 static void setup_restart(time)
6379         Time time;
6380 {
6381 /* djhjr - 6/22/01 */
6382 #ifndef NO_SOUND_SUPPORT
6383         CloseSound();
6384 #endif
6385
6386         SetRealScreen(0,0);
6387         XSync (dpy, 0);
6388         Reborder (time);
6389         XSync (dpy, 0);
6390
6391         /* djhjr - 3/13/97 */
6392         XCloseDisplay(dpy);
6393
6394         /* djhjr - 12/2/01 */
6395         delete_pidfile();
6396 }
6397
6398 void RestartVtwm(time)
6399         Time time;
6400 {
6401         setup_restart(time);
6402
6403         execvp(*Argv, Argv);
6404         fprintf (stderr, "%s:  unable to restart \"%s\"\n", ProgramName, *Argv);
6405 }
6406
6407
6408 /*
6409  * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
6410  * client messages will have the following form:
6411  *
6412  *     event type       ClientMessage
6413  *     message type     _XA_WM_PROTOCOLS
6414  *     window           tmp->w
6415  *     format           32
6416  *     data[0]          message atom
6417  *     data[1]          time stamp
6418  */
6419
6420 static void send_clientmessage (w, a, timestamp)
6421     Window w;
6422     Atom a;
6423     Time timestamp;
6424 {
6425     XClientMessageEvent ev;
6426
6427     ev.type = ClientMessage;
6428     ev.window = w;
6429     ev.message_type = _XA_WM_PROTOCOLS;
6430     ev.format = 32;
6431     ev.data.l[0] = a;
6432     ev.data.l[1] = timestamp;
6433     XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
6434 }
6435
6436 void SendDeleteWindowMessage (tmp, timestamp)
6437     TwmWindow *tmp;
6438     Time timestamp;
6439 {
6440     send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
6441 }
6442
6443 void SendSaveYourselfMessage (tmp, timestamp)
6444     TwmWindow *tmp;
6445     Time timestamp;
6446 {
6447     send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
6448 }
6449
6450 void SendTakeFocusMessage (tmp, timestamp)
6451     TwmWindow *tmp;
6452     Time timestamp;
6453 {
6454     send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
6455 }
6456
6457
6458 /* djhjr - 4/27/96 */
6459 void DisplayPosition (x, y)
6460 int x, y;
6461 {
6462     char str [100];
6463         int i;
6464
6465 /* djhjr - 5/10/96
6466     char signx = '+';
6467     char signy = '+';
6468
6469     if (x < 0) {
6470         x = -x;
6471         signx = '-';
6472     }
6473     if (y < 0) {
6474         y = -y;
6475         signy = '-';
6476     }
6477
6478     i = sprintf (str, " %c%-4d %c%-4d ", signx, x, signy, y);
6479 */
6480 /*
6481  * Non-SysV systems - specifically, BSD-derived systems - return a
6482  * pointer to the string, not its length. Submitted by Goran Larsson
6483     i = sprintf (str, "%+6d %-+6d", x, y);
6484  */
6485     sprintf (str, "%+6d %-+6d", x, y);
6486     i = strlen (str);
6487
6488     XRaiseWindow (dpy, Scr->SizeWindow);
6489     /* font was font.font->fid - djhjr - 9/14/03 */
6490     FBF (Scr->DefaultC.fore, Scr->DefaultC.back, Scr->SizeFont);
6491 /* djhjr - 9/14/03 */
6492 #ifndef NO_I18N_SUPPORT
6493     MyFont_DrawImageString (dpy, Scr->SizeWindow, &Scr->SizeFont,
6494 #else
6495     XDrawImageString (dpy, Scr->SizeWindow,
6496 #endif
6497                           Scr->NormalGC,
6498
6499 /* djhjr - 5/9/96
6500                       Scr->SizeStringOffset,
6501 */
6502                           (Scr->SizeStringWidth -
6503 /* djhjr - 9/14/03 */
6504 #ifndef NO_I18N_SUPPORT
6505                            MyFont_TextWidth(&Scr->SizeFont,
6506 #else
6507                            XTextWidth(Scr->SizeFont.font,
6508 #endif
6509                                         str, i)) / 2,
6510
6511 /* djhjr - 4/29/98
6512                         Scr->SizeFont.font->ascent + SIZE_VINDENT,
6513 */
6514                         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
6515 /* djhjr - 9/14/03
6516                         Scr->SizeFont.font->ascent +
6517 */
6518                         Scr->SizeFont.ascent +
6519                                  SIZE_VINDENT +
6520                                  ((Scr->InfoBevelWidth > 0) ? Scr->InfoBevelWidth : 0),
6521
6522                         str, i);
6523
6524         /* I know, I know, but the above code overwrites it... djhjr - 5/9/96 */
6525         /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
6526         if (Scr->InfoBevelWidth > 0)
6527             Draw3DBorder(Scr->SizeWindow, 0, 0,
6528                                 Scr->SizeStringWidth,
6529
6530 /* djhjr - 4/29/98
6531                                 (unsigned int) (Scr->SizeFont.height + SIZE_VINDENT*2),
6532                                 BW, Scr->DefaultC, off, False, False);
6533 */
6534                                 /* was 'Scr->use3Dborders' - djhjr - 8/11/98 */
6535                                 (unsigned int) (Scr->SizeFont.height + SIZE_VINDENT*2) +
6536                                         ((Scr->InfoBevelWidth > 0) ? 2 * Scr->InfoBevelWidth : 0),
6537                                 Scr->InfoBevelWidth, Scr->DefaultC, off, False, False);
6538 }
6539
6540 /* djhjr - 9/21/99 */
6541 int FindMenuOrFuncInBindings(contexts, mr, func)
6542 int contexts;
6543 MenuRoot *mr;
6544 int func;
6545 {
6546         MenuRoot *start;
6547         FuncKey *key;
6548         int found = 0; /* context bitmap for menu or function */
6549         int i, j, k, l, fallback = 0;
6550
6551         if (mr)
6552         {
6553                 if (Scr->DefaultFunction.func == F_MENU)
6554                         if (FindMenuInMenus(Scr->DefaultFunction.menu, mr))
6555                                 fallback = 1;
6556         }
6557         else
6558         {
6559                 if (Scr->DefaultFunction.func == func)
6560                         fallback = 1;
6561                 else if (Scr->DefaultFunction.func == F_MENU)
6562                         if (FindFuncInMenus(Scr->DefaultFunction.menu, func))
6563                                 fallback = 1;
6564         }
6565
6566         for (j = 0; j < NUM_CONTEXTS; j++)
6567         {
6568                 if ((contexts & (1 << j)) == 0) continue;
6569
6570                 if (fallback)
6571                 {
6572                         found |= (1 << j);
6573                         continue;
6574                 }
6575
6576                 for (i = 0; i < MAX_BUTTONS + 1; i++)
6577                 {
6578                         l = 0;
6579
6580                         for (k = 0; k < MOD_SIZE; k++)
6581                         {
6582                                 if (mr)
6583                                 {
6584                                         if (Scr->Mouse[i][j][k].func == F_MENU)
6585                                                 l = FindMenuInMenus(Scr->Mouse[i][j][k].menu, mr);
6586                                 }
6587                                 else
6588                                 {
6589                                         if (Scr->Mouse[i][j][k].func == func)
6590                                                 l = 1;
6591                                         else if (Scr->Mouse[i][j][k].func == F_MENU)
6592                                                 l = FindFuncInMenus(Scr->Mouse[i][j][k].menu, func);
6593                                 }
6594
6595                                 if (l)
6596                                 {
6597                                         found |= (1 << j);
6598                                         i = MAX_BUTTONS + 1;
6599                                         break;
6600                                 }
6601                         }
6602                 }
6603
6604                 l = 0;
6605                 for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
6606                         if (key->cont & (1 << j))
6607                         {
6608                                 if (mr)
6609                                 {
6610                                         if (key->func == F_MENU)
6611                                                 for (start = Scr->MenuList; start != NULL; start = start->next)
6612                                                         if (strcmp(start->name, key->action) == 0)
6613                                                         {
6614                                                                 l = FindMenuInMenus(start, mr);
6615                                                                 break;
6616                                                         }
6617                                 }
6618                                 else
6619                                 {
6620                                         if (key->func == func)
6621                                                 l = 1;
6622                                         else if (key->func == F_MENU)
6623                                                 for (start = Scr->MenuList; start != NULL; start = start->next)
6624                                                         if (strcmp(start->name, key->action) == 0)
6625                                                         {
6626                                                                 l = FindFuncInMenus(start, func);
6627                                                                 break;
6628                                                         }
6629                                 }
6630
6631                                 if (l)
6632                                 {
6633                                         found |= (1 << j);
6634                                         break;
6635                                 }
6636                         }
6637         }
6638
6639         return found;
6640 }
6641
6642 /* djhjr - 9/21/99 */
6643 int FindMenuOrFuncInWindows(tmp_win, contexts, mr, func)
6644 TwmWindow *tmp_win;
6645 int contexts;
6646 MenuRoot *mr;
6647 int func;
6648 {
6649         TwmWindow *twin;
6650         TwmDoor *d;
6651         TBWindow *tbw;
6652         int i, nb;
6653
6654         if (contexts & C_ROOT_BIT) return 1;
6655
6656         for (twin = Scr->TwmRoot.next; twin != NULL; twin = twin->next)
6657                 if (twin != tmp_win)
6658                 {
6659                         /*
6660                          * if this window is an icon manager,
6661                          * skip the windows that aren't in it
6662                          */
6663                         if (tmp_win->iconmgr && twin->list &&
6664                                         tmp_win != twin->list->iconmgr->twm_win)
6665                                 continue;
6666
6667                         if (twin->mapped)
6668                         {
6669                                 for (i = 1; i < C_ALL_BITS; i = (1 << i))
6670                                 {
6671                                         if ((contexts & i) == 0) continue;
6672
6673                                         switch (i)
6674                                         {
6675                                                 case C_WINDOW_BIT:
6676                                                 case C_FRAME_BIT:
6677                                                         break;
6678                                                 case C_TITLE_BIT:
6679                                                         if (!twin->title_height) continue;
6680                                                         break;
6681                                                 case C_VIRTUAL_BIT:
6682                                                         if (twin->w != Scr->VirtualDesktopDisplayOuter)
6683                                                                 continue;
6684                                                         break;
6685                                                 case C_DOOR_BIT:
6686                                                         if (XFindContext(dpy, twin->w, DoorContext,
6687                                                                         (caddr_t *)&d) == XCNOENT)
6688                                                                 continue;
6689                                                         break;
6690                                                 default:
6691                                                         continue;
6692                                                         break;
6693                                         }
6694
6695                                         return 1;
6696                                 }
6697
6698                                 if (twin->titlebuttons)
6699                                 {
6700                                         nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
6701
6702                                         for (tbw = twin->titlebuttons; nb > 0; tbw++, nb--)
6703                                                 if (mr)
6704                                                 {
6705                                                         if (tbw->info->menuroot)
6706                                                                 if (FindMenuInMenus(tbw->info->menuroot, mr))
6707                                                                         return 1;
6708                                                 }
6709                                                 else
6710                                                 {
6711                                                         if (tbw->info->func == func)
6712                                                                 return 1;
6713                                                         else if (tbw->info->menuroot)
6714                                                                 if (FindFuncInMenus(tbw->info->menuroot, func))
6715                                                                         return 1;
6716                                                 }
6717                                 }
6718                         }
6719                         else if (!twin->iconify_by_unmapping)
6720                         {
6721                                 /* not mapped and shows an icon */
6722
6723                                 if (contexts & C_ICON_BIT) return 1;
6724                         }
6725                 }
6726
6727         return 0;
6728 }
6729
6730 /* djhjr - 9/21/99 */
6731 int FindMenuInMenus(start, sought)
6732 MenuRoot *start, *sought;
6733 {
6734         MenuItem *mi;
6735
6736         if (!start) return 0;   /* submitted by Jonathan Paisley - 11/11/02 */
6737         if (start == sought) return 1;
6738
6739         for (mi = start->first; mi != NULL; mi = mi->next)
6740                 if (mi->sub)
6741                         if (FindMenuInMenus(mi->sub, sought))
6742                                 return 1;
6743
6744         return 0;
6745 }
6746
6747 /* djhjr - 9/21/99 */
6748 int FindFuncInMenus(mr, func)
6749 MenuRoot *mr;
6750 int func;
6751 {
6752         MenuItem *mi;
6753
6754         for (mi = mr->first; mi != NULL; mi = mi->next)
6755                 if (mi->func == func)
6756                         return 1;
6757                 else if (mi->sub)
6758                         if (FindFuncInMenus(mi->sub, func))
6759                                 return 1;
6760
6761         return 0;
6762 }
6763
6764 /* djhjr - 6/22/01 */
6765 void DoAudible()
6766 {
6767 #ifndef NO_SOUND_SUPPORT
6768         if (PlaySound(S_BELL)) return;
6769 #endif
6770
6771         XBell(dpy, 0);
6772 }
6773