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