1 /*****************************************************************************/
2 /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
3 /** Salt Lake City, Utah **/
4 /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
5 /** Cambridge, Massachusetts **/
6 /** **/
7 /** All Rights Reserved **/
8 /** **/
9 /** Permission to use, copy, modify, and distribute this software and **/
10 /** its documentation for any purpose and without fee is hereby **/
11 /** granted, provided that the above copyright notice appear in all **/
12 /** copies and that both that copyright notice and this permis- **/
13 /** sion notice appear in supporting documentation, and that the **/
14 /** names of Evans & Sutherland and M.I.T. not be used in advertising **/
15 /** in publicity pertaining to distribution of the software without **/
16 /** specific, written prior permission. **/
17 /** **/
18 /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
19 /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
20 /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
21 /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
22 /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
23 /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
24 /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
25 /** OR PERFORMANCE OF THIS SOFTWARE. **/
26 /*****************************************************************************/
27
28
29 /***********************************************************************
30 *
31 * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
32 *
33 * twm menu code
34 *
35 * $Log: menus.c,v $
36 * Revision 1.25 1995/02/09 20:08:59 cross
37 * Document a lack of a feature...
38 *
39 * Revision 1.24 1995/02/03 00:13:17 cross
40 * Use XmuCompareISOLatin1(), not FIXED_XmuCompareISOLatin1(), since it
41 * seems to be free of the original bug in R5 and greater (and,
42 * FIXED_XmuCompareISOLatin1() had a bug in it that XmuCompareISOLatin1()
43 * doesn't...)
44 *
45 * Revision 1.23 1994/10/17 20:06:20 cross
46 * Fixed relative resize buglet, and changed around to the X11R6 code
47 * for warping...
48 *
49 * Revision 1.22 1994/03/14 17:33:08 cross
50 * Doesn't SEGV (doesn't do anything at all, now) if you call relativemove
51 * when there's not a window for it to act upon.
52 *
53 * Revision 1.21 1993/12/01 22:58:42 cross
54 * Added f.relativemove...
55 *
56 * Revision 1.20 1993/05/20 15:40:06 cross
57 * pl9b5. Mostly double-headed machine stuff
58 * XPM fixes to such.
59 *
60 * Revision 1.18 1993/01/20 23:14:34 cross
61 * RJC changes
62 *
63 * Revision 1.17 1992/11/04 01:17:22 cross
64 * Added code from rjc, with filtering.
65 * See text in CHANGES for details.
66 *
67 * Revision 1.16 1992/08/17 15:04:24 cross
68 * Added a needed include of sys/types.h
69 *
70 * Revision 1.15 1992/05/09 02:48:56 cross
71 * Minor modification that should be more correct, but doesn't seem
72 * to change much...
73 *
74 * Revision 1.14 1992/05/02 19:46:35 cross
75 * Added changes by RJC. A few bug fixes, reorganization of lots of
76 * code, and many new features
77 *
78 * Revision 1.13 1992/02/09 21:50:03 cross
79 * First attempt to make StayUpMenus work again... There should be
80 * more work done on this...
81 *
82 * Revision 1.12 1992/01/20 20:27:39 cross
83 * Fixed a bug that caused incorect colors on titlebar pixmaps
84 *
85 * Revision 1.11 1992/01/08 18:55:49 cross
86 * rewrote all the color/pixmap code
87 * fixes from Bob Mende (mende@piecomputer.rutgers.edu)
88 * - f.menufunc works
89 * - SIGUSR1 implementation
90 * - ListRings works
91 * don't use m4 by default; added -m/-M flag
92 * DontInterpolateTitles
93 * icon stuff. IconWindow doesn't get a bad mask.
94 * colors passed to xloadimage
95 *
96 * Revision 1.10 1991/10/29 22:28:11 cross
97 * Updated to be a strict superset of X11R5's twm, not X11R4's.
98 *
99 * Revision 1.9 1991/10/05 08:39:16 cross
100 * Changed to the new version of Xpm (v3.0, released a whole day before
101 * the contrib deadline. Ugh.)
102 *
103 * Revision 1.8 1991/10/04 22:44:03 cross
104 * Changed the pixmap definition for the pullright pixmap.
105 * Now R5'ized.
106 *
107 * Revision 1.7 1991/10/03 00:09:23 cross
108 * Fixed some bogus uses of the NULL symbol. Also, had to cast menu12_data
109 * to type char*. It's unsigned char * in the R5 dist, but XCrPFBData()
110 * still wants a char*. gcc caught it.
111 *
112 * Revision 1.6 1991/10/02 23:20:05 cross
113 * Spacing changes
114 *
115 * Revision 1.5 1991/10/02 22:36:23 cross
116 * Made some minor adjustements to text in the info window
117 *
118 * Revision 1.4 1991/10/01 20:12:10 cross
119 * Fixed a typo. Had a "<" where I meant ">="
120 *
121 * Revision 1.3 1991/09/26 00:41:59 cross
122 * Changed old-style call to XCreatePixmapFromData to new-style (Xpm
123 * v3.0 +)
124 * Also, included X11/xpm.h
125 *
126 * Revision 1.2 1991/09/26 00:19:00 cross
127 * Changed all calls to FindBitmap() to FindPixmap().
128 * also, changed ispixmap stuff to isxpm
129 *
130 * Revision 1.1 1991/09/26 00:14:58 cross
131 * Initial revision
132 *
133 * Revision 10.0 91/06/12 09:05:38 toml
134 * Revision bump
135 *
136 * Revision 9.1 91/05/14 11:27:44 toml
137 * Fixed crash problem and removed #include "malloc.h"
138 *
139 * Revision 9.0 91/04/23 07:40:40 toml
140 * Revision bump
141 *
142 * Revision 8.3 91/04/15 09:13:24 toml
143 * Remove version comment
144 *
145 * Revision 8.2 90/12/29 16:39:35 toml
146 * RJC patches
147 *
148 * Revision 8.1 90/12/29 10:13:12 toml
149 * StayUpMenus
150 *
151 * Revision 8.0 90/11/15 20:02:43 toml
152 * Revision bump
153 *
154 * Revision 7.4 90/11/15 19:59:42 toml
155 * removed a printf from a patch
156 *
157 * Revision 7.3 90/11/12 22:05:00 toml
158 * Applied opaque move patches
159 *
160 * Revision 7.2 90/11/12 21:34:54 toml
161 * Implemented Scr->StickyAbove
162 *
163 * Revision 7.1 90/11/12 19:57:25 toml
164 * Patches to allow sticky windows to lower
165 *
166 * Revision 1.2 90/11/04 18:38:22 brossard
167 * Sticky windows are now child of the virtual root.
168 * This has the advantage that they can now be raised and lowered like
169 * any other window. They no longuer are above everything else.
170 * It has the disadvantage that when you move the desktop, the
171 * sticky windows have to be moved back after scrolling the desktop.
172 *
173 *
174 * 17-Nov-87 Thomas E. LaStrange File created
175 *
176 ***********************************************************************/
177
178 #include <stdio.h>
179 #include <signal.h>
180 #include <sys/types.h>
181 #include <sys/stat.h>
182 #include <X11/Xos.h>
183 #include <X11/Xatom.h>
184 #include "twm.h"
185 #include "gc.h"
186 #include "menus.h"
187 #include "resize.h"
188 #include "events.h"
189 #include "util.h"
190 #include "parse.h"
191 #include "gram.h"
192 #include "screen.h"
193 #include <X11/Xmu/CharSet.h> /* for XmuCompareISOLatin1() */
194 #include "version.h"
195 #include "vdt.h"
196 #include "add_window.h"
197 #include "patchlevel.h"
198
199 extern XEvent Event;
200
201 int RootFunction = 0;
202 char *RootAction = NULL;
203
204 MenuRoot *ActiveMenu = NULL; /* the active menu */
205 MenuItem *ActiveItem = NULL; /* the active menu item */
206 int MoveFunction; /* either F_MOVE or F_FORCEMOVE */
207 int WindowMoved = FALSE;
208 int menuFromFrameOrWindowOrTitlebar = FALSE;
209
210 int ConstMove = FALSE; /* constrained move variables */
211 int ConstMoveDir;
212 int ConstMoveX;
213 int ConstMoveY;
214 int ConstMoveXL;
215 int ConstMoveXR;
216 int ConstMoveYT;
217 int ConstMoveYB;
218
219 /* Globals used to keep track of whether the mouse has moved during
220 a resize function. */
221 int ResizeOrigX;
222 int ResizeOrigY;
223
224 int MenuDepth = 0; /* number of menus up */
225 static struct {
226 int x;
227 int y;
228 } MenuOrigins[MAXMENUDEPTH];
229 static Cursor LastCursor;
230
231 void WarpAlongRing(), WarpToWindow();
232
233 extern char *Action;
234 extern int Context;
235 extern TwmWindow *ButtonWindow, *Tmp_win;
236 extern XEvent Event, ButtonEvent;
237 extern char *InitFile;
238 static void Identify();
239
240 #define MAX(x,y) ((x)>(y)?(x):(y))
241
242
243
244 /***********************************************************************
245 *
246 * Procedure:
247 * InitMenus - initialize menu roots
248 *
249 ***********************************************************************
250 */
251
252 void
InitMenus()253 InitMenus()
254 {
255 int i, j, k;
256 FuncKey *key, *tmp;
257
258 for (i = 0; i < MAX_BUTTONS+1; i++)
259 for (j = 0; j < NUM_CONTEXTS; j++)
260 for (k = 0; k < MOD_SIZE; k++)
261 {
262 Scr->Mouse[i][j][k].func = 0;
263 Scr->Mouse[i][j][k].item = NULL;
264 }
265
266 Scr->DefaultFunction.func = 0;
267 Scr->WindowFunction.func = 0;
268
269 if (FirstScreen)
270 {
271 for (key = Scr->FuncKeyRoot.next; key != NULL;)
272 {
273 free(key->name);
274 tmp = key;
275 key = key->next;
276 free((char *) tmp);
277 }
278 Scr->FuncKeyRoot.next = NULL;
279 }
280
281 }
282
283
284
285 /***********************************************************************
286 *
287 * Procedure:
288 * AddFuncKey - add a function key to the list
289 *
290 * Inputs:
291 * name - the name of the key
292 * cont - the context to look for the key press in
293 * mods - modifier keys that need to be pressed
294 * func - the function to perform
295 * win_name- the window name (if any)
296 * action - the action string associated with the function (if any)
297 *
298 ***********************************************************************
299 */
300
AddFuncKey(name,cont,mods,func,win_name,action)301 Bool AddFuncKey (name, cont, mods, func, win_name, action)
302 char *name;
303 int cont, mods, func;
304 char *win_name;
305 char *action;
306 {
307 FuncKey *tmp;
308 KeySym keysym;
309 KeyCode keycode;
310
311 /*
312 * Don't let a 0 keycode go through, since that means AnyKey to the
313 * XGrabKey call in GrabKeys().
314 */
315 if ((keysym = XStringToKeysym(name)) == NoSymbol ||
316 (keycode = XKeysymToKeycode(dpy, keysym)) == 0)
317 {
318 return False;
319 }
320
321 /* see if there already is a key defined for this context */
322 for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
323 {
324 if (tmp->keysym == keysym &&
325 tmp->cont == cont &&
326 tmp->mods == mods)
327 break;
328 }
329
330 if (tmp == NULL)
331 {
332 tmp = (FuncKey *) malloc(sizeof(FuncKey));
333 tmp->next = Scr->FuncKeyRoot.next;
334 Scr->FuncKeyRoot.next = tmp;
335 }
336
337 tmp->name = name;
338 tmp->keysym = keysym;
339 tmp->keycode = keycode;
340 tmp->cont = cont;
341 tmp->mods = mods;
342 tmp->func = func;
343 tmp->win_name = win_name;
344 tmp->action = action;
345
346 return True;
347 }
348
349
350
CreateTitleButton(name,func,action,menuroot,rightside,append)351 int CreateTitleButton (name, func, action, menuroot, rightside, append)
352 char *name;
353 int func;
354 char *action;
355 MenuRoot *menuroot;
356 Bool rightside;
357 Bool append;
358 {
359 TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
360
361 if (!tb) {
362 fprintf (stderr,
363 "%s: unable to allocate %d bytes for title button\n",
364 ProgramName, sizeof(TitleButton));
365 return 0;
366 }
367
368
369 tb->next = NULL;
370 tb->name = name; /* note that we are not copying */
371 tb->bitmap = None; /* WARNING, values not set yet */
372 #ifdef XPM
373 tb->isXpm = False; /* assume a bitmap */
374 #endif /* XPM */
375 tb->width = 0; /* see InitTitlebarButtons */
376 tb->height = 0; /* ditto */
377 tb->func = func;
378 tb->action = action;
379 tb->menuroot = menuroot;
380 tb->rightside = rightside;
381 if (rightside) {
382 Scr->TBInfo.nright++;
383 } else {
384 Scr->TBInfo.nleft++;
385 }
386
387 /*
388 * Cases for list:
389 *
390 * 1. empty list, prepend left put at head of list
391 * 2. append left, prepend right put in between left and right
392 * 3. append right put at tail of list
393 *
394 * Do not refer to widths and heights yet since buttons not created
395 * (since fonts not loaded and heights not known).
396 */
397 if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */
398 tb->next = Scr->TBInfo.head;
399 Scr->TBInfo.head = tb;
400 } else if (append && rightside) { /* 3 */
401 register TitleButton *t;
402 for /* SUPPRESS 530 */
403 (t = Scr->TBInfo.head; t->next; t = t->next) ;
404 t->next = tb;
405 tb->next = NULL;
406 } else { /* 2 */
407 register TitleButton *t, *prev = NULL;
408 for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
409 prev = t;
410 }
411 if (prev) {
412 tb->next = prev->next;
413 prev->next = tb;
414 } else {
415 tb->next = Scr->TBInfo.head;
416 Scr->TBInfo.head = tb;
417 }
418 }
419
420 return 1;
421 }
422
423
424
425 /*
426 * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
427 * button. If we can't find the button, then put in a question; if we can't
428 * find the question mark, something is wrong and we are probably going to be
429 * in trouble later on.
430 */
InitTitlebarButtons()431 void InitTitlebarButtons ()
432 {
433 TitleButton *tb;
434 int h;
435 Pixel bg_color;
436
437 /*
438 * initialize dimensions
439 */
440 Scr->TBInfo.width = (Scr->TitleHeight -
441 2 * (Scr->FramePadding + Scr->ButtonIndent));
442 Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
443 ? ((Scr->TitlePadding + 1) / 2) : 1);
444 h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
445
446 /*
447 * add in some useful buttons and bindings so that novices can still
448 * use the system.
449 */
450 if (!Scr->NoDefaults) {
451 /* insert extra buttons */
452 if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
453 False, False)) {
454 fprintf (stderr, "%s: unable to add iconify button\n",
455 ProgramName);
456 }
457 if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
458 True, True)) {
459 fprintf (stderr, "%s: unable to add resize button\n",
460 ProgramName);
461 }
462 AddDefaultBindings ();
463 }
464 ComputeCommonTitleOffsets ();
465
466 /*
467 * load in images and do appropriate centering
468 */
469
470 for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
471 tb->bitmap = FindPixmap (tb->name, &tb->width, &tb->height,
472 &tb->isXpm, &bg_color, NULL, 0, NULL);
473 if (!tb->bitmap) {
474 tb->bitmap = FindPixmap (TBPM_QUESTION, &tb->width, &tb->height,
475 &tb->isXpm, &bg_color, NULL, 0, NULL);
476 if (!tb->bitmap) { /* cannot happen (see util.c) */
477 fprintf (stderr,
478 "%s: unable to add titlebar button \"%s\"\n",
479 ProgramName, tb->name);
480 }
481 } else if ((tb->name[0] != ':') && (tb->name[0] != '#') &&
482 (tb->isXpm == False))
483 tb->bitmap = XmuLocateBitmapFile(ScreenOfDisplay(dpy, Scr->screen),
484 tb->name, NULL, 0, &tb->width, &tb->height,
485 &JunkX, &JunkY);
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 if (tb->isXpm == True) {
505 Pixmap new_btn;
506 GC gc;
507 XGCValues vals;
508
509 new_btn = XCreatePixmap(dpy, Scr->Root, h, h,
510 DefaultDepth(dpy, Scr->screen));
511 vals.foreground = bg_color;
512 gc = XCreateGC(dpy, new_btn, GCForeground, &vals);
513 XFillRectangle(dpy, new_btn, gc, 0, 0, h, h);
514 XCopyArea(dpy, tb->bitmap, new_btn, gc, tb->srcx, tb->srcy,
515 tb->width, tb->height, tb->dstx, tb->dsty);
516 XFreeGC(dpy, gc);
517 XFreePixmap(dpy, tb->bitmap);
518 tb->bitmap = new_btn;
519 /* A completely new pixmap has been generated, so tvtwm must be
520 * told that it is the same size as the window, and therefore the
521 * coords for src and dst should all be 0. */
522 tb->width = tb->height = h;
523 tb->dstx = tb->dsty = tb->srcx = tb->srcy = 0;
524 }
525 }
526 }
527
528
529
PaintEntry(mr,mi,exposure)530 PaintEntry(mr, mi, exposure)
531 MenuRoot *mr;
532 MenuItem *mi;
533 int exposure;
534 {
535 int y_offset;
536 int text_y;
537 GC gc;
538 MyFont *font;
539
540 XSynchronize(dpy, True);
541
542 #ifdef DEBUG_MENUS
543 fprintf(stderr, "Paint entry\n");
544 #endif
545 y_offset = mi->item_num * Scr->EntryHeight;
546
547 if (mi->func != F_TITLE)
548 {
549 int x, y;
550
551 font = &(Scr->MenuFont);
552
553 text_y = y_offset + font->y;
554
555 if (mi->state)
556 {
557 XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
558
559 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
560 mr->width, Scr->EntryHeight);
561
562 FBF(mi->hi_fore, mi->hi_back, font->font->fid);
563
564 XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
565 text_y, mi->item, mi->strlen);
566
567 gc = Scr->NormalGC;
568 }
569 else
570 {
571 if (mi->user_colors || !exposure)
572 {
573 XSetForeground(dpy, Scr->NormalGC, mi->back);
574
575 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
576 mr->width, Scr->EntryHeight);
577
578 FBF(mi->fore, mi->back, font->font->fid);
579 gc = Scr->NormalGC;
580 }
581 else
582 gc = Scr->MenuGC;
583
584 XDrawString(dpy, mr->w, gc, mi->x,
585 text_y, mi->item, mi->strlen);
586 }
587
588 if (mi->func == F_MENU || mi->func == F_MENUFUNC)
589 {
590 /* Get or create the pull right menu icon */
591 if (Scr->pullrightPm.pm == None) {
592 if (Scr->pullrightPm.name) {
593 #ifdef XPM
594 XpmColorSymbol ctrans[2];
595
596 ctrans[0].name = "foreground";
597 ctrans[0].value = NULL;
598 ctrans[0].pixel = Scr->MenuC.fore;
599 ctrans[1].name = "background";
600 ctrans[1].value = NULL;
601 ctrans[1].pixel = Scr->MenuC.back;
602 #endif
603
604 Scr->pullrightPm.pm = FindPixmap(Scr->pullrightPm.name,
605 &Scr->pullrightPm.width,
606 &Scr->pullrightPm.height,
607 &Scr->pullrightPm.isXpm,
608 NULL,
609 #ifdef XPM
610 ctrans, 2,
611 #else
612 NULL, 0,
613 #endif
614 &Scr->pullrightPm.mask);
615 } else {
616 Scr->pullrightPm.pm = CreateMenuIcon(Scr->MenuFont.height,
617 &Scr->pullrightPm.width,
618 &Scr->pullrightPm.height);
619 Scr->pullrightPm.isXpm = FALSE;
620 Scr->pullrightPm.mask = None;
621 }
622 }
623 x = mr->width - Scr->pullrightPm.width - 5;
624 y = y_offset + ((font->height - Scr->pullrightPm.height) / 2);
625 if (Scr->pullrightPm.name && (Scr->pullrightPm.name[0] != '#'))
626 XCopyArea(dpy, Scr->pullrightPm.pm, mr->w, gc, 0, 0,
627 Scr->pullrightPm.width, Scr->pullrightPm.height, x, y);
628 else
629 XCopyPlane(dpy, Scr->pullrightPm.pm, mr->w, gc, 0, 0,
630 Scr->pullrightPm.width, Scr->pullrightPm.height,
631 x, y, 1);
632 }
633 if (abs(mr->def) == (mi->item_num+1))
634 XDrawRectangle(dpy, mr->w, gc, 0, text_y-2, 2, 2);
635 }
636 else
637 {
638 int y;
639
640 if (Scr->MenuTitleFont.name != NULL )
641 font = &(Scr->MenuTitleFont);
642 else
643 font = &(Scr->MenuFont);
644
645 text_y = y_offset + font->y;
646
647 XSetForeground(dpy, Scr->NormalGC, mi->back);
648
649 /* fill the rectangle with the title background color */
650 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
651 mr->width, Scr->EntryHeight);
652
653 if ( Scr->MenuLineWidth > 0 ) /* note we loose the high efficiancy `0' line width */
654 {
655 XSetForeground(dpy, Scr->NormalGC, mi->fore);
656 XSetLineAttributes(dpy,Scr->NormalGC,
657 Scr->MenuLineWidth,
658 LineSolid,
659 CapButt,
660 JoinMiter);
661
662 /* now draw the dividing lines */
663 if (y_offset)
664 XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
665 mr->width, y_offset);
666 y = ((mi->item_num+1) * Scr->EntryHeight)-1;
667 XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
668 XSetLineAttributes(dpy,Scr->NormalGC,
669 0,
670 LineSolid,
671 CapButt,
672 JoinMiter);
673 }
674
675 FBF(mi->fore, mi->back, font->font->fid);
676 /* finally render the title */
677 XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
678 text_y, mi->item, mi->strlen);
679
680 if (abs(mr->def) == (mi->item_num+1))
681 XDrawRectangle(dpy, mr->w, Scr->NormalGC, 0, text_y-2, 2, 2);
682 }
683 }
684
685
686
PaintMenu(mr,e)687 PaintMenu(mr, e)
688 MenuRoot *mr;
689 XEvent *e;
690 {
691 MenuItem *mi;
692
693 for (mi = mr->first; mi != NULL; mi = mi->next)
694 {
695 int y_offset = mi->item_num * Scr->EntryHeight;
696
697 /* be smart about handling the expose, redraw only the entries
698 * that we need to
699 */
700 if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
701 (e->xexpose.y + e->xexpose.height) > y_offset)
702 {
703 PaintEntry(mr, mi, True);
704 }
705 }
706 XSync(dpy, 0);
707 }
708
709
710
711 static Bool fromMenu;
712
713 #if 1
UpdateMenu()714 UpdateMenu()
715 {
716 MenuItem *mi;
717 int i, x, y, x_root, y_root, entry;
718 int done;
719 MenuItem *badItem = NULL;
720 Window aJunkRoot,aJunkChild;
721 unsigned int aJunkMask;
722 static int firstTime = True;
723
724 fromMenu = TRUE;
725
726 while (TRUE)
727 {
728 /* block until there is an event */
729 if (!menuFromFrameOrWindowOrTitlebar) {
730 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
731 EnterWindowMask | ExposureMask |
732 VisibilityChangeMask | LeaveWindowMask |
733 PointerMotionMask, &Event);
734 }
735
736 if (Event.type == MotionNotify) {
737 /* discard any extra motion events before a release */
738 while(XCheckMaskEvent(dpy,
739 ButtonMotionMask | ButtonReleaseMask, &Event))
740 if (Event.type == ButtonRelease)
741 break;
742 }
743
744 if (!DispatchEvent ())
745 continue;
746
747 if (Event.type == ButtonRelease)
748 {
749 menuFromFrameOrWindowOrTitlebar = FALSE;
750 fromMenu = FALSE;
751 if (Scr->StayUpMenus)
752 {
753 if (firstTime == True)
754 {
755 /* it was the first release of the button */
756 firstTime = False;
757 } /* end if */
758 else
759 {
760 /* thats the second we need to return now */
761 firstTime = True;
762 return;
763 } /* end else */
764 } /* end if */
765 else
766 {
767 return;
768 } /* end else */
769 }
770
771 if (Event.type == Cancel || !ActiveMenu) {
772 menuFromFrameOrWindowOrTitlebar = FALSE;
773 fromMenu = FALSE;
774 return;
775 }
776
777 if (Event.type == LeaveNotify
778 && ((XCrossingEvent *)&Event)->window == ActiveMenu->w) {
779 if (ActiveItem && ActiveItem->func != F_TITLE) {
780 ActiveItem->state = 0;
781 PaintEntry(ActiveMenu, ActiveItem, False);
782 }
783 ActiveItem = NULL;
784 continue;
785 }
786
787 if (Event.type != MotionNotify)
788 continue;
789
790 #if 1
791 XQueryPointer( dpy, ActiveMenu->w, &aJunkRoot, &aJunkChild,
792 &x_root, &y_root, &x, &y, &aJunkMask);
793 #else
794 x = ((XMotionEvent *)&Event)->x;
795 y = ((XMotionEvent *)&Event)->y;
796 #endif
797
798 /* if we are in the parent, pop back down, this should prevent
799 * menus that are slow to pop up from hanging around too long.
800 */
801 if (ActiveMenu->prev &&
802 ActiveMenu->prev->w == ((XMotionEvent *)&Event)->window) {
803 if (Scr->Shadow)
804 XUnmapWindow(dpy, ActiveMenu->shadow);
805 XUnmapWindow(dpy, ActiveMenu->w);
806 ActiveMenu->mapped = UNMAPPED;
807 UninstallRootColormap();
808 if (ActiveItem) {
809 ActiveItem->state = 0;
810 PaintEntry(ActiveMenu, ActiveItem, False);
811 }
812 ActiveItem = NULL;
813 ActiveMenu = ActiveMenu->prev;
814 MenuDepth--;
815 continue;
816 }
817
818 if (((XMotionEvent *)&Event)->window != ActiveMenu->w)
819 continue;
820
821 done = FALSE;
822
823 /* if we haven't recieved the enter notify yet, wait */
824 if (ActiveMenu && !ActiveMenu->entered)
825 continue;
826
827 XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
828
829 if (x < 0 || y < 0 ||
830 x >= ActiveMenu->width || y >= ActiveMenu->height)
831 {
832 if (ActiveItem && ActiveItem->func != F_TITLE)
833 {
834 ActiveItem->state = 0;
835 PaintEntry(ActiveMenu, ActiveItem, False);
836 }
837 ActiveItem = NULL;
838 continue;
839 }
840
841 /* look for the entry that the mouse is in */
842 entry = y / Scr->EntryHeight;
843 for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
844 {
845 if (i == entry)
846 break;
847 }
848
849 /* if there is an active item, we might have to turn it off */
850 if (ActiveItem)
851 {
852 /* is the active item the one we are on ? */
853 if (ActiveItem->item_num == entry && ActiveItem->state)
854 done = TRUE;
855
856 /* if we weren't on the active entry, let's turn the old
857 * active one off
858 */
859 if (!done && ActiveItem->func != F_TITLE)
860 {
861 ActiveItem->state = 0;
862 PaintEntry(ActiveMenu, ActiveItem, False);
863 }
864 }
865
866 /* if we weren't on the active item, change the active item and turn
867 * it on
868 */
869 if (!done)
870 {
871 ActiveItem = mi;
872 if (ActiveItem->func != F_TITLE && !ActiveItem->state)
873 {
874 ActiveItem->state = 1;
875 PaintEntry(ActiveMenu, ActiveItem, False);
876 }
877 }
878
879 /* now check to see if we were over the arrow of a pull right entry */
880 if ((ActiveItem->func == F_MENU || ActiveItem->func == F_MENUFUNC) &&
881 (((ActiveMenu->width - x) * 100) <
882 (ActiveMenu->width * Scr->PopupSensitivity)))
883 {
884 MenuRoot *save = ActiveMenu;
885 int savex = MenuOrigins[MenuDepth - 1].x;
886 int savey = MenuOrigins[MenuDepth - 1].y;
887
888 if (MenuDepth < MAXMENUDEPTH) {
889 PopUpMenu (ActiveItem->sub,
890 (savex + (int)(ActiveMenu->width *
891 (100-Scr->PopupSensitivity) / 100.0)),
892 (savey + ActiveItem->item_num * Scr->EntryHeight)
893 /*(savey + ActiveItem->item_num * Scr->EntryHeight +
894 (Scr->EntryHeight >> 1))*/, False);
895 } else if (!badItem) {
896 XBell (dpy, 0);
897 badItem = ActiveItem;
898 }
899
900 /* if the menu did get popped up, unhighlight the active item */
901 if (save != ActiveMenu && ActiveItem->state)
902 {
903 ActiveItem->state = 0;
904 PaintEntry(save, ActiveItem, False);
905 ActiveItem = NULL;
906 }
907 }
908 if (badItem != ActiveItem) badItem = NULL;
909 XFlush(dpy);
910 }
911
912 }
913 #else
UpdateMenu()914 UpdateMenu()
915 {
916 MenuItem *mi;
917 int i, x, y, x_root, y_root, entry;
918 int done;
919 MenuItem *badItem = NULL;
920 Window aJunkRoot, aJunkChild;
921 unsigned int aJunkMask;
922 static int firstTime = True;
923
924 fromMenu = TRUE;
925
926 while (TRUE) {
927 while (XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
928 EnterWindowMask | ExposureMask, &Event)) {
929 if (!DispatchEvent())
930 continue;
931
932 if (Event.type == ButtonRelease || ActiveMenu == NULL) {
933 menuFromFrameOrWindowOrTitlebar = FALSE;
934 fromMenu = FALSE;
935 if (Scr->StayUpMenus) {
936 if (firstTime == True) {
937 /* it was the first release of the button */
938 firstTime = False;
939 }
940 /* end if */
941 else {
942 /* thats the second we need to return now */
943 firstTime = True;
944 return;
945 } /* end else */
946 }
947 /* end if */
948 else {
949 return;
950 } /* end else */
951 }
952 if (Event.type == Cancel) {
953 menuFromFrameOrWindowOrTitlebar = FALSE;
954 fromMenu = FALSE;
955 return;
956 }
957 }
958
959 done = FALSE;
960 XQueryPointer(dpy, ActiveMenu->w, &aJunkRoot, &aJunkChild,
961 &x_root, &y_root, &x, &y, &aJunkMask);
962
963 /* if we haven't received the enter notify yet, wait */
964 if (!ActiveMenu || !ActiveMenu->entered)
965 continue;
966
967 XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *) & Scr);
968
969 if (x < 0 || y < 0 ||
970 x >= ActiveMenu->width || y >= ActiveMenu->height) {
971 if (ActiveItem && ActiveItem->func != F_TITLE) {
972 ActiveItem->state = 0;
973 PaintEntry(ActiveMenu, ActiveItem, False);
974 }
975 ActiveItem = NULL;
976 continue;
977 }
978 /* look for the entry that the mouse is in */
979 entry = y / Scr->EntryHeight;
980 for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi = mi->next) {
981 if (i == entry)
982 break;
983 }
984
985 /* if there is an active item, we might have to turn it off */
986 if (ActiveItem) {
987 /* is the active item the one we are on ? */
988 if (ActiveItem->item_num == entry && ActiveItem->state)
989 done = TRUE;
990
991 /*
992 * if we weren't on the active entry, let's turn the old active
993 * one off
994 */
995 if (!done && ActiveItem->func != F_TITLE) {
996 ActiveItem->state = 0;
997 PaintEntry(ActiveMenu, ActiveItem, False);
998 }
999 }
1000 /*
1001 * if we weren't on the active item, change the active item and turn
1002 * it on
1003 */
1004 if (!done) {
1005 ActiveItem = mi;
1006 if (ActiveItem->func != F_TITLE && !ActiveItem->state) {
1007 ActiveItem->state = 1;
1008 PaintEntry(ActiveMenu, ActiveItem, False);
1009 }
1010 }
1011 /* now check to see if we were over the arrow of a pull right entry */
1012 if ((ActiveItem->func == F_MENU || ActiveItem->func == F_MENUFUNC) &&
1013 ((ActiveMenu->width - x) * 100 <
1014 (ActiveMenu->width * Scr->PopupSensitivity))) {
1015 MenuRoot *save = ActiveMenu;
1016 int savex = MenuOrigins[MenuDepth - 1].x;
1017 int savey = MenuOrigins[MenuDepth - 1].y;
1018 if (MenuDepth < MAXMENUDEPTH) {
1019 PopUpMenu(ActiveItem->sub,
1020 (savex + (int)(ActiveMenu->width
1021 * (100-Scr->PopupSensitivity) / 100.0)),
1022 (savey + ActiveItem->item_num * Scr->EntryHeight)
1023 /*
1024 * (savey + ActiveItem->item_num * Scr->EntryHeight +
1025 * (Scr->EntryHeight >> 1))
1026 */ , False);
1027 } else if (!badItem) {
1028 XBell(dpy, 0);
1029 badItem = ActiveItem;
1030 }
1031 /* if the menu did get popped up, unhighlight the active item */
1032 if (save != ActiveMenu && ActiveItem->state) {
1033 ActiveItem->state = 0;
1034 PaintEntry(save, ActiveItem, False);
1035 ActiveItem = NULL;
1036 }
1037 }
1038 if (badItem != ActiveItem)
1039 badItem = NULL;
1040 XFlush(dpy);
1041 }
1042 }
1043 #endif
1044
1045
1046
1047 /***********************************************************************
1048 *
1049 * Procedure:
1050 * NewMenuRoot - create a new menu root
1051 *
1052 * Returned Value:
1053 * (MenuRoot *)
1054 *
1055 * Inputs:
1056 * name - the name of the menu root
1057 *
1058 ***********************************************************************
1059 */
1060
1061 MenuRoot *
NewMenuRoot(name)1062 NewMenuRoot(name)
1063 char *name;
1064 {
1065 MenuRoot *tmp;
1066
1067 #define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */
1068
1069 tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
1070 tmp->hi_fore = UNUSED_PIXEL;
1071 tmp->hi_back = UNUSED_PIXEL;
1072 tmp->name = name;
1073 tmp->file = NULL;
1074 tmp->mtime = 0;
1075 tmp->prev = NULL;
1076 tmp->first = NULL;
1077 tmp->last = NULL;
1078 tmp->items = 0;
1079 tmp->width = 0;
1080 tmp->mapped = NEVER_MAPPED;
1081 tmp->pull = FALSE;
1082 tmp->w = None;
1083 tmp->shadow = None;
1084 tmp->real_menu = FALSE;
1085
1086 if (Scr->MenuList == NULL)
1087 {
1088 Scr->MenuList = tmp;
1089 Scr->MenuList->next = NULL;
1090 }
1091
1092 if (Scr->LastMenu == NULL)
1093 {
1094 Scr->LastMenu = tmp;
1095 Scr->LastMenu->next = NULL;
1096 }
1097 else
1098 {
1099 Scr->LastMenu->next = tmp;
1100 Scr->LastMenu = tmp;
1101 Scr->LastMenu->next = NULL;
1102 }
1103
1104 if (strcmp(name, TWM_WINDOWS) == 0)
1105 Scr->Windows = tmp;
1106
1107 return (tmp);
1108 }
1109
1110
1111
1112 /***********************************************************************
1113 *
1114 * Procedure:
1115 * AddToMenu - add an item to a root menu
1116 *
1117 * Returned Value:
1118 * (MenuItem *)
1119 *
1120 * Inputs:
1121 * menu - pointer to the root menu to add the item
1122 * item - the text to appear in the menu
1123 * action - the string to possibly execute
1124 * sub - the menu root if it is a pull-right entry
1125 * func - the numeric function
1126 * fore - foreground color string
1127 * back - background color string
1128 *
1129 ***********************************************************************
1130 */
1131
1132 MenuItem *
AddToMenu(menu,item,action,sub,func,fore,back)1133 AddToMenu(menu, item, action, sub, func, fore, back)
1134 MenuRoot *menu;
1135 char *item, *action;
1136 MenuRoot *sub;
1137 int func;
1138 char *fore, *back;
1139 {
1140 MenuItem *tmp;
1141 int width;
1142 MyFont *font;
1143
1144 #ifdef DEBUG_MENUS
1145 fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
1146 item, action, sub, func);
1147 #endif
1148
1149 tmp = (MenuItem *) malloc(sizeof(MenuItem));
1150 tmp->root = menu;
1151
1152 if (menu->first == NULL)
1153 {
1154 menu->first = tmp;
1155 tmp->prev = NULL;
1156 }
1157 else
1158 {
1159 menu->last->next = tmp;
1160 tmp->prev = menu->last;
1161 }
1162 menu->last = tmp;
1163
1164 tmp->item = item;
1165 tmp->strlen = strlen(item);
1166 tmp->action = action;
1167 tmp->next = NULL;
1168 tmp->sub = NULL;
1169 tmp->state = 0;
1170 tmp->func = func;
1171
1172 if ( func == F_TITLE && Scr->MenuTitleFont.name != NULL)
1173 font= &(Scr->MenuTitleFont);
1174 else
1175 font= &(Scr->MenuFont);
1176
1177 if (!Scr->HaveFonts) CreateFonts();
1178 width = XTextWidth(font->font, item, tmp->strlen);
1179 if (width <= 0)
1180 width = 1;
1181 if (width > menu->width)
1182 menu->width = width;
1183
1184 tmp->user_colors = FALSE;
1185 if (Scr->Monochrome == COLOR && fore != NULL)
1186 {
1187 int save;
1188
1189 save = Scr->FirstTime;
1190 Scr->FirstTime = TRUE;
1191 GetColor(COLOR, &tmp->fore, fore);
1192 GetColor(COLOR, &tmp->back, back);
1193 Scr->FirstTime = save;
1194 tmp->user_colors = TRUE;
1195 }
1196 if (sub != NULL)
1197 {
1198 tmp->sub = sub;
1199 menu->pull = TRUE;
1200 }
1201 tmp->item_num = menu->items++;
1202
1203 return (tmp);
1204 }
1205
1206
1207
MakeMenus()1208 MakeMenus()
1209 {
1210 MenuRoot *mr;
1211
1212 for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
1213 {
1214 if (mr->real_menu == FALSE)
1215 continue;
1216
1217 MakeMenu(mr);
1218 }
1219 }
1220
1221
1222
MakeMenu(mr)1223 MakeMenu(mr)
1224 MenuRoot *mr;
1225 {
1226 MenuItem *start, *end, *cur, *tmp;
1227 XColor f1, f2, f3;
1228 XColor b1, b2, b3;
1229 XColor save_fore, save_back;
1230 int num, i;
1231 int fred, fgreen, fblue;
1232 int bred, bgreen, bblue;
1233 int width;
1234 unsigned long valuemask;
1235 XSetWindowAttributes attributes;
1236 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
1237 MyFont *titleFont;
1238
1239 if ( Scr->MenuTitleFont.name != NULL )
1240 {
1241 Scr->EntryHeight = MAX(Scr->MenuFont.height,
1242 Scr->MenuTitleFont.height) + 4;
1243 titleFont= &(Scr->MenuTitleFont);
1244 }
1245 else
1246 {
1247 Scr->EntryHeight = Scr->MenuFont.height + 4;
1248 titleFont= &(Scr->MenuFont);
1249 }
1250
1251 /* lets first size the window accordingly */
1252 if (mr->mapped == NEVER_MAPPED)
1253 {
1254 if (mr->items == 0)
1255 AddToMenu(mr, "Empty", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
1256
1257 if (mr->pull == TRUE)
1258 mr->width += 16 + 10;
1259
1260 width = mr->width + 10;
1261
1262 for (cur = mr->first; cur != NULL; cur = cur->next)
1263 {
1264 if (cur->func != F_TITLE)
1265 cur->x = 5;
1266 else
1267 {
1268 cur->x = width - XTextWidth(titleFont->font, cur->item,
1269 cur->strlen);
1270 cur->x /= 2;
1271 }
1272 }
1273 mr->height = mr->items * Scr->EntryHeight;
1274 mr->width += 10;
1275
1276 if (Scr->Shadow)
1277 {
1278 /*
1279 * Make sure that you don't draw into the shadow window or else
1280 * the background bits there will get saved
1281 */
1282 valuemask = CWBorderPixel;
1283 attributes.border_pixel = Scr->MenuShadowColor;
1284 if (Scr->SaveUnder) {
1285 valuemask |= CWSaveUnder;
1286 attributes.save_under = True;
1287 }
1288 if (Scr->shadowPm.name && ! Scr->shadowPm.pm) {
1289 #ifdef XPM
1290 XpmColorSymbol ctrans[2];
1291
1292 ctrans[0].name = "foreground";
1293 ctrans[0].value = NULL;
1294 ctrans[0].pixel = Scr->MenuShadowColor;
1295 ctrans[1].name = "background";
1296 ctrans[1].value = NULL;
1297 ctrans[1].pixel = Scr->MenuC.back;
1298 #endif
1299
1300 Scr->shadowPm.pm = FindPixmap(Scr->shadowPm.name,
1301 &Scr->shadowPm.width,
1302 &Scr->shadowPm.height,
1303 &(Scr->shadowPm.isXpm),
1304 NULL,
1305 #ifdef XPM
1306 ctrans, 2,
1307 #else
1308 NULL, 0,
1309 #endif
1310 &Scr->shadowPm.mask);
1311 if (! Scr->shadowPm.pm)
1312 Scr->shadowPm.name=None;
1313 }
1314
1315 if (Scr->shadowPm.pm) {
1316 valuemask |= CWBackPixmap;
1317 attributes.background_pixmap = Scr->shadowPm.pm;
1318 } else {
1319 valuemask |= CWBackPixel;
1320 attributes.background_pixel = Scr->MenuShadowColor;
1321 }
1322
1323 mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
1324 (unsigned int) mr->width,
1325 (unsigned int) mr->height,
1326 Scr->shadowPm.pm ? (unsigned int)1 :
1327 (unsigned int)0,
1328 CopyFromParent,
1329 (unsigned int) CopyFromParent,
1330 (Visual *) CopyFromParent,
1331 valuemask, &attributes);
1332 }
1333
1334 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
1335 attributes.background_pixel = Scr->MenuC.back;
1336 attributes.border_pixel = Scr->MenuC.fore;
1337 attributes.event_mask = (ExposureMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask);
1338 if (Scr->SaveUnder) {
1339 valuemask |= CWSaveUnder;
1340 attributes.save_under = True;
1341 }
1342 if (Scr->BackingStore) {
1343 valuemask |= CWBackingStore;
1344 attributes.backing_store = Always;
1345 }
1346 mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
1347 (unsigned int) mr->height, (unsigned int) 1,
1348 CopyFromParent, (unsigned int) CopyFromParent,
1349 (Visual *) CopyFromParent,
1350 valuemask, &attributes);
1351
1352
1353 XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
1354 XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
1355
1356 mr->mapped = UNMAPPED;
1357 }
1358
1359 /* get the default colors into the menus */
1360 for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
1361 {
1362 if (!tmp->user_colors) {
1363 if (tmp->func != F_TITLE) {
1364 tmp->fore = Scr->MenuC.fore;
1365 tmp->back = Scr->MenuC.back;
1366 } else {
1367 tmp->fore = Scr->MenuTitleC.fore;
1368 tmp->back = Scr->MenuTitleC.back;
1369 }
1370 }
1371
1372 if (mr->hi_fore != UNUSED_PIXEL)
1373 {
1374 tmp->hi_fore = mr->hi_fore;
1375 tmp->hi_back = mr->hi_back;
1376 }
1377 else
1378 {
1379 tmp->hi_fore = tmp->back;
1380 tmp->hi_back = tmp->fore;
1381 }
1382 }
1383
1384 if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
1385 return;
1386
1387 start = mr->first;
1388 while (TRUE)
1389 {
1390 for (; start != NULL; start = start->next)
1391 {
1392 if (start->user_colors)
1393 break;
1394 }
1395 if (start == NULL)
1396 break;
1397
1398 for (end = start->next; end != NULL; end = end->next)
1399 {
1400 if (end->user_colors)
1401 break;
1402 }
1403 if (end == NULL)
1404 break;
1405
1406 /* we have a start and end to interpolate between */
1407 num = end->item_num - start->item_num;
1408
1409 f1.pixel = start->fore;
1410 XQueryColor(dpy, cmap, &f1);
1411 f2.pixel = end->fore;
1412 XQueryColor(dpy, cmap, &f2);
1413
1414 b1.pixel = start->back;
1415 XQueryColor(dpy, cmap, &b1);
1416 b2.pixel = end->back;
1417 XQueryColor(dpy, cmap, &b2);
1418
1419 fred = ((int)f2.red - (int)f1.red) / num;
1420 fgreen = ((int)f2.green - (int)f1.green) / num;
1421 fblue = ((int)f2.blue - (int)f1.blue) / num;
1422
1423 bred = ((int)b2.red - (int)b1.red) / num;
1424 bgreen = ((int)b2.green - (int)b1.green) / num;
1425 bblue = ((int)b2.blue - (int)b1.blue) / num;
1426
1427 f3 = f1;
1428 f3.flags = DoRed | DoGreen | DoBlue;
1429
1430 b3 = b1;
1431 b3.flags = DoRed | DoGreen | DoBlue;
1432
1433 num -= 1;
1434 for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
1435 {
1436 f3.red += fred;
1437 f3.green += fgreen;
1438 f3.blue += fblue;
1439
1440 b3.red += bred;
1441 b3.green += bgreen;
1442 b3.blue += bblue;
1443
1444 if (Scr->DontInterpolateTitles && (cur->func == F_TITLE))
1445 continue;
1446
1447 save_fore = f3;
1448 save_back = b3;
1449
1450 XAllocColor(dpy, cmap, &f3);
1451 XAllocColor(dpy, cmap, &b3);
1452 cur->hi_back = cur->fore = f3.pixel;
1453 cur->hi_fore = cur->back = b3.pixel;
1454 cur->user_colors = True;
1455
1456 f3 = save_fore;
1457 b3 = save_back;
1458 }
1459 start = end;
1460 }
1461 }
1462
1463
1464
1465 /********************************************************************\
1466 * *
1467 * HandleChangingMenus -- check if the contents of a menu should be *
1468 * changed and if so, do so. *
1469 * *
1470 * Used to be part of PopUpMenu, but it is needed by the code to do *
1471 * default menu actions too. *
1472 * *
1473 \********************************************************************/
1474
HandleChangingMenus(menu)1475 HandleChangingMenus(menu)
1476 MenuRoot *menu;
1477 {
1478 int WindowNameOffset, WindowNameCount;
1479 TwmWindow **WindowNames;
1480 TwmWindow *tmp_win2, *tmp_win3;
1481 TwmWindow **sortlist, *bakwin;
1482 int i, loop, curpos, count;
1483
1484 int (*compar)() = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
1485
1486 if (menu == Scr->Windows) {
1487 TwmWindow *tmp_win;
1488
1489 /* this is the twm windows menu, let's go ahead and build it */
1490
1491 DestroyMenu(menu);
1492
1493 menu->first = NULL;
1494 menu->last = NULL;
1495 menu->items = 0;
1496 menu->width = 0;
1497 menu->mapped = NEVER_MAPPED;
1498 AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
1499
1500 /* CODE to SORT THE MENU @@@@@@@@@@@@@@ */
1501 if (Scr->SortIconMgr) {
1502 for(count=0,tmp_win=Scr->TwmRoot.next; tmp_win != NULL;
1503 tmp_win = tmp_win->next,count++) ;
1504 sortlist = (TwmWindow **)malloc(sizeof(TwmWindow *) * count);
1505 for(loop=0,tmp_win=Scr->TwmRoot.next; tmp_win != NULL;
1506 tmp_win = tmp_win->next,loop++)
1507 sortlist[loop]=tmp_win;
1508
1509 /* Now that we have them in the list, just do an insertion sort. */
1510 for (curpos=1;curpos<count;curpos++) {
1511 /*Everything from 0 to curpos-1 is sorted.*/
1512 bakwin = sortlist[curpos];
1513 for (loop=curpos;(loop>0);loop--)
1514 /*Everything from loop to curpos is sorted*/
1515 /* Sort order is [0] = min, [n]=max */
1516 if (((*compar)(sortlist[loop-1]->name,bakwin->name))>0)
1517 sortlist[loop]=sortlist[loop-1];
1518 else
1519 break;
1520 sortlist[loop]=bakwin;
1521 }
1522
1523 for(loop=0;loop<count;loop++)
1524 AddToMenu(menu,sortlist[loop]->name, (char *)sortlist[loop],
1525 NULL, F_POPUP, NULLSTR, NULLSTR);
1526 } else {
1527 WindowNameOffset=(char *)Scr->TwmRoot.next->name -
1528 (char *)Scr->TwmRoot.next;
1529 for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
1530 tmp_win != NULL;
1531 tmp_win = tmp_win->next)
1532 WindowNameCount++;
1533 WindowNames =
1534 (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
1535 WindowNames[0] = Scr->TwmRoot.next;
1536 for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
1537 tmp_win != NULL; tmp_win = tmp_win->next,WindowNameCount++) {
1538 tmp_win2 = tmp_win;
1539 for (i=0;i<WindowNameCount;i++) {
1540 if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
1541 {
1542 tmp_win3 = tmp_win2;
1543 tmp_win2 = WindowNames[i];
1544 WindowNames[i] = tmp_win3;
1545 }
1546 }
1547 WindowNames[WindowNameCount] = tmp_win2;
1548 }
1549 for (i=0; i<WindowNameCount; i++) {
1550 AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
1551 NULL, F_POPUP,NULL,NULL);
1552 }
1553 free(WindowNames);
1554 }
1555 MakeMenu(menu);
1556 }
1557 else if (menu->file != NULL) {
1558 struct stat buf;
1559
1560 if ( stat(menu->file, &buf) == 0 && buf.st_mtime > menu->mtime ) {
1561 menu->mtime=buf.st_mtime;
1562
1563 menu->real_menu = FALSE;
1564 ParseMenuFile(menu->file, menu->name);
1565 if (menu->real_menu == FALSE)
1566 fprintf(stderr,"%s: Menu %s not defined in %s\n",
1567 ProgramName, menu->name, menu->file);
1568 }
1569 }
1570 }
1571
1572 /***********************************************************************
1573 *
1574 * Procedure:
1575 * PopUpMenu - pop up a pull down menu
1576 *
1577 * Inputs:
1578 * menu - the root pointer of the menu to pop up
1579 * x, y - location of upper left of menu
1580 * center - whether or not to center horizontally over position
1581 *
1582 ***********************************************************************
1583 */
1584
PopUpMenu(menu,x,y,center)1585 Bool PopUpMenu (menu, x, y, center)
1586 MenuRoot *menu;
1587 int x, y;
1588 Bool center;
1589 {
1590 if (!menu) return False;
1591
1592 InstallRootColormap();
1593
1594 /* Prevent recursively bringing up menus. */
1595 if (menu->mapped == MAPPED) return False;
1596
1597 HandleChangingMenus(menu);
1598
1599 if (menu->w == None || menu->items == 0) return False;
1600
1601 /*
1602 * Dynamically set the parent; this allows pull-ups to also be main
1603 * menus, or to be brought up from more than one place.
1604 */
1605 menu->prev = ActiveMenu;
1606
1607 XGrabPointer(dpy, Scr->Root, True,
1608 ButtonPressMask | ButtonReleaseMask |
1609 ButtonMotionMask | PointerMotionHintMask,
1610 GrabModeAsync, GrabModeAsync,
1611 Scr->Root, Scr->MenuCursor, CurrentTime);
1612
1613 ActiveMenu = menu;
1614 menu->mapped = MAPPED;
1615 menu->entered = FALSE;
1616
1617 if (center) {
1618 x -= (menu->width / 2);
1619 y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
1620 }
1621
1622 /* if the menu has a default entry, put it under the cursor */
1623 if (menu->def)
1624 y -= (abs(menu->def) - 1) * Scr->EntryHeight;
1625
1626 /*
1627 * clip to screen
1628 */
1629 if (x + menu->width > Scr->MyDisplayWidth) {
1630 x = Scr->MyDisplayWidth - menu->width;
1631 }
1632 if (x < 0) x = 0;
1633 if (y + menu->height > Scr->MyDisplayHeight) {
1634 y = Scr->MyDisplayHeight - menu->height;
1635 }
1636 if (y < 0) y = 0;
1637
1638 MenuOrigins[MenuDepth].x = x;
1639 MenuOrigins[MenuDepth].y = y;
1640 MenuDepth++;
1641
1642 XMoveWindow(dpy, menu->w, x, y);
1643 if (Scr->Shadow) {
1644 XMoveWindow (dpy, menu->shadow, x + Scr->ShadowWidth, y + Scr->ShadowWidth);
1645 }
1646 if (Scr->Shadow) {
1647 XRaiseWindow (dpy, menu->shadow);
1648 }
1649 XMapRaised(dpy, menu->w);
1650 if (Scr->Shadow) {
1651 XMapWindow (dpy, menu->shadow);
1652 }
1653 XSync(dpy, 0);
1654 return True;
1655 }
1656
1657
1658
1659 /***********************************************************************
1660 *
1661 * Procedure:
1662 * PopDownMenu - unhighlight the current menu selection and
1663 * take down the menus
1664 *
1665 ***********************************************************************
1666 */
1667
PopDownMenu()1668 PopDownMenu()
1669 {
1670 MenuRoot *tmp;
1671
1672 if (ActiveMenu == NULL)
1673 return;
1674
1675 if (ActiveItem)
1676 {
1677 ActiveItem->state = 0;
1678 PaintEntry(ActiveMenu, ActiveItem, False);
1679 }
1680
1681 for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
1682 {
1683 if (Scr->Shadow) {
1684 XUnmapWindow (dpy, tmp->shadow);
1685 }
1686 XUnmapWindow(dpy, tmp->w);
1687 tmp->mapped = UNMAPPED;
1688 UninstallRootColormap();
1689 }
1690
1691 XFlush(dpy);
1692 ActiveMenu = NULL;
1693 ActiveItem = NULL;
1694 MenuDepth = 0;
1695 if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
1696 menuFromFrameOrWindowOrTitlebar = TRUE;
1697 }
1698
1699
1700
1701 /***********************************************************************
1702 *
1703 * Procedure:
1704 * FindMenuRoot - look for a menu root
1705 *
1706 * Returned Value:
1707 * (MenuRoot *) - a pointer to the menu root structure
1708 *
1709 * Inputs:
1710 * name - the name of the menu root
1711 *
1712 ***********************************************************************
1713 */
1714
1715 MenuRoot *
FindMenuRoot(name)1716 FindMenuRoot(name)
1717 char *name;
1718 {
1719 MenuRoot *tmp;
1720
1721 for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
1722 {
1723 if (strcmp(name, tmp->name) == 0)
1724 return (tmp);
1725 }
1726 return NULL;
1727 }
1728
1729
1730
belongs_to_twm_window(t,w)1731 static Bool belongs_to_twm_window (t, w)
1732 register TwmWindow *t;
1733 register Window w;
1734 {
1735 if (!t) return False;
1736
1737 if (w == t->frame || w == t->title_w || w == t->hilite_w ||
1738 w == t->icon.w
1739 || w == t->icon.image_w
1740 || w == t->icon.text_w) return True;
1741
1742 if (t && t->titlebuttons) {
1743 register TBWindow *tbw;
1744 register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1745 for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
1746 if (tbw->window == w) return True;
1747 }
1748 }
1749 return False;
1750 }
1751
1752
1753
1754
1755 /***********************************************************************
1756 *
1757 * Procedure:
1758 * resizeFromCenter -
1759 *
1760 ***********************************************************************
1761 */
1762
1763
1764 extern int AddingX;
1765 extern int AddingY;
1766 extern int AddingW;
1767 extern int AddingH;
1768
resizeFromCenter(w,tmp_win)1769 void resizeFromCenter(w, tmp_win)
1770 Window w;
1771 TwmWindow *tmp_win;
1772 {
1773 int lastx, lasty, width, height, bw2;
1774 int namelen;
1775 int stat;
1776 XEvent event;
1777 Window junk;
1778
1779 namelen = strlen (tmp_win->name);
1780 bw2 = tmp_win->frame_bw * 2;
1781 AddingW = tmp_win->attr.width + bw2;
1782 AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
1783 width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
1784 tmp_win->name, namelen));
1785 height = Scr->SizeFont.height + SIZE_VINDENT * 2;
1786 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
1787 (unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
1788 &JunkBW, &JunkDepth);
1789 XWarpPointer(dpy, None, w,
1790 0, 0, 0, 0, DragWidth/2, DragHeight/2);
1791 XQueryPointer(dpy, Scr->Root, &JunkRoot,
1792 &JunkChild, &JunkX, &JunkY,
1793 &AddingX, &AddingY, &JunkMask);
1794 /*****
1795 Scr->SizeStringOffset = width +
1796 XTextWidth(Scr->SizeFont.font, ": ", 2);
1797 XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
1798 Scr->SizeStringWidth, height);
1799 XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width,
1800 SIZE_VINDENT + Scr->SizeFont.font->ascent,
1801 ": ", 2);
1802 *****/
1803 lastx = -10000;
1804 lasty = -10000;
1805 /*****
1806 MoveOutline(Scr->Root,
1807 origDragX - JunkBW, origDragY - JunkBW,
1808 DragWidth * JunkBW, DragHeight * JunkBW,
1809 tmp_win->frame_bw,
1810 tmp_win->title_height);
1811 *****/
1812 MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
1813 while (TRUE)
1814 {
1815 XMaskEvent(dpy,
1816 ButtonPressMask | PointerMotionMask, &event);
1817
1818 if (event.type == MotionNotify) {
1819 /* discard any extra motion events before a release */
1820 while(XCheckMaskEvent(dpy,
1821 ButtonMotionMask | ButtonPressMask, &event))
1822 if (event.type == ButtonPress)
1823 break;
1824 }
1825
1826 if (event.type == ButtonPress)
1827 {
1828 MenuEndResize(tmp_win);
1829 XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
1830 break;
1831 }
1832
1833 /* if (!DispatchEvent ()) continue; */
1834
1835 if (event.type != MotionNotify) {
1836 continue;
1837 }
1838
1839 /*
1840 * XXX - if we are going to do a loop, we ought to consider
1841 * using multiple GXxor lines so that we don't need to
1842 * grab the server.
1843 */
1844 XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
1845 &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
1846
1847 if (lastx != AddingX || lasty != AddingY)
1848 {
1849 MenuDoResize(AddingX, AddingY, tmp_win);
1850
1851 lastx = AddingX;
1852 lasty = AddingY;
1853 }
1854
1855 }
1856 }
1857
1858
1859
1860 /***********************************************************************
1861 *
1862 * Procedure:
1863 * RestartTwm - Restart Twm
1864 ***********************************************************************
1865 */
1866
1867 void
RestartTwm(time)1868 RestartTwm(time)
1869 Time time;
1870 {
1871 XSync (dpy, 0);
1872 Reborder (time);
1873 XSync (dpy, 0);
1874 execvp(*Argv, Argv);
1875 fprintf (stderr, "%s: unable to restart: %s\n", ProgramName, *Argv);
1876 }
1877
1878
1879 /***********************************************************************
1880 *
1881 * Procedure:
1882 * ExecuteFunction - execute a twm root function
1883 *
1884 * Inputs:
1885 * func - the function to execute
1886 * action - the menu action to execute
1887 * sub - pullright menu, if any
1888 * w - the window to execute this function on
1889 * tmp_win - the twm window structure
1890 * event - the event that caused the function
1891 * context - the context in which the button was pressed
1892 * pulldown- flag indicating execution from pull down menu
1893 *
1894 * Returns:
1895 * TRUE if should continue with remaining actions else FALSE to abort
1896 *
1897 ***********************************************************************
1898 */
1899
1900 /* for F_WARPTO */
1901 int
1902 #ifdef __STDC__
WarpThere(TwmWindow * t)1903 WarpThere(TwmWindow *t)
1904 #else
1905 WarpThere(t)
1906 TwmWindow *t;
1907 #endif
1908 {
1909 if (Scr->WarpUnmapped || t->mapped) {
1910 if (!t->mapped)
1911 DeIconify(t);
1912 if (!Scr->NoRaiseWarp)
1913 RaiseFrame(t);
1914 WarpToWindow(t);
1915 return TRUE;
1916 }
1917 return FALSE;
1918 }
1919
1920 static struct MenuItem *
GetDefaultAction(menu)1921 GetDefaultAction(menu)
1922 struct MenuRoot *menu;
1923 {
1924 struct MenuItem *item;
1925 int i;
1926
1927 if (!menu)
1928 return NULL;
1929
1930 HandleChangingMenus(menu);
1931
1932 if (!menu->def)
1933 return NULL;
1934
1935 for(item = menu->first, i=abs(menu->def) ; (--i > 0) && (item) ;
1936 item=item->next)
1937 ;
1938
1939 if (item->func == F_MENU)
1940 return GetDefaultAction(item->sub);
1941 else
1942 return item;
1943 }
1944
1945 int
ExecuteFunction(func,action,sub,w,tmp_win,eventp,context,pulldown)1946 ExecuteFunction(func, action, sub, w, tmp_win, eventp, context, pulldown)
1947 int func;
1948 char *action;
1949 struct MenuRoot *sub;
1950 Window w;
1951 TwmWindow *tmp_win;
1952 XEvent *eventp;
1953 int context;
1954 int pulldown;
1955 {
1956 static Time last_time = 0;
1957 short Real_OpaqueMove; /* holder for F_OPAQUEMOVE */
1958 char tmp[200];
1959 char *ptr;
1960 char buff[MAX_FILE_SIZE];
1961 int count, fd;
1962 Window rootw;
1963 int origX, origY;
1964 int do_next_action = TRUE;
1965 int moving_icon = FALSE;
1966 Bool fromtitlebar = False;
1967 extern int ConstrainedMoveTime;
1968 struct MenuItem *item;
1969
1970 RootFunction = 0;
1971 if (Cancel)
1972 return TRUE; /* XXX should this be FALSE? */
1973
1974 switch (func)
1975 {
1976 case F_UPICONMGR:
1977 case F_LEFTICONMGR:
1978 case F_RIGHTICONMGR:
1979 case F_DOWNICONMGR:
1980 case F_FORWICONMGR:
1981 case F_BACKICONMGR:
1982 case F_NEXTICONMGR:
1983 case F_PREVICONMGR:
1984 case F_NOP:
1985 case F_TITLE:
1986 case F_DELTASTOP:
1987 case F_RAISELOWER:
1988 case F_WARPTOSCREEN:
1989 case F_WARPTO:
1990 case F_WARPRING:
1991 case F_WARPTOICONMGR:
1992 case F_COLORMAP:
1993 break;
1994 default:
1995 XGrabPointer(dpy, Scr->Root, True,
1996 ButtonPressMask | ButtonReleaseMask,
1997 GrabModeAsync, GrabModeAsync,
1998 Scr->Root, Scr->WaitCursor, CurrentTime);
1999 break;
2000 }
2001
2002 switch (func)
2003 {
2004 case F_NOP:
2005 case F_TITLE:
2006 break;
2007
2008 case F_MENU:
2009 item = GetDefaultAction(sub);
2010
2011 if (item == NULL) {
2012 XBell(dpy, 0);
2013 return FALSE;
2014 }
2015
2016 if (Deferrable(item->func) && DeferExecution(context, item->func,
2017 item->action, Scr->SelectCursor))
2018 return TRUE;
2019
2020 return ExecuteFunction(item->func,
2021 item->action,
2022 item->sub,
2023 w, tmp_win,
2024 eventp, context, pulldown);
2025 break;
2026
2027 case F_PANNER:
2028 if (Scr->Panner) {
2029 if (XFindContext (dpy, Scr->Panner, TwmContext, (caddr_t *)&tmp_win) != XCSUCCESS)
2030 tmp_win = AddWindow(Scr->Panner, FALSE, NULL);
2031 if (tmp_win->mapped) {
2032 UnmapFrame(tmp_win);
2033 tmp_win->mapped = FALSE;
2034 }
2035 else {
2036 if (tmp_win->isicon)
2037 DeIconify(tmp_win);
2038 else
2039 MapFrame(tmp_win);
2040 tmp_win->mapped = TRUE;
2041 }
2042 }
2043 break;
2044
2045 case F_SCROLL:
2046 case F_SCROLLHOME:
2047 case F_SCROLLLEFT:
2048 case F_SCROLLRIGHT:
2049 case F_SCROLLUP:
2050 case F_SCROLLDOWN:
2051 case F_SCROLLBACK:
2052 ScrollDesktop(func, action);
2053 break;
2054
2055 case F_DELTASTOP:
2056 if (WindowMoved) do_next_action = FALSE;
2057 break;
2058
2059 case F_RESTART:
2060 RestartTwm(eventp->xbutton.time);
2061 break;
2062
2063 case F_UPICONMGR:
2064 case F_DOWNICONMGR:
2065 case F_LEFTICONMGR:
2066 case F_RIGHTICONMGR:
2067 case F_FORWICONMGR:
2068 case F_BACKICONMGR:
2069 MoveIconManager(func);
2070 break;
2071
2072 case F_NEXTICONMGR:
2073 case F_PREVICONMGR:
2074 JumpIconManager(func);
2075 break;
2076
2077 case F_SHOWLIST:
2078 if (Scr->NoIconManagers)
2079 break;
2080 DeIconify(Scr->iconmgr.twm_win);
2081 RaiseFrame(Scr->iconmgr.twm_win);
2082 break;
2083
2084 case F_HIDELIST:
2085 if (Scr->NoIconManagers)
2086 break;
2087 HideIconManager ();
2088 break;
2089
2090 case F_STICK:
2091 if (DeferExecution(context, func, action, Scr->SelectCursor))
2092 return TRUE;
2093
2094 if (Scr->VirtualDesktop) {
2095 int x, y;
2096
2097 if (tmp_win->sticky) {
2098 if (Scr->StickyAbove) {
2099 XReparentWindow(dpy, tmp_win->frame, Scr->VirtualDesktop,
2100 tmp_win->frame_x + Scr->vdtPositionX,
2101 tmp_win->frame_y + Scr->vdtPositionY);
2102 tmp_win->frame_x += Scr->vdtPositionX;
2103 tmp_win->frame_y += Scr->vdtPositionY;
2104 XMoveWindow(dpy, tmp_win->virtualWindow,
2105 tmp_win->frame_x / Scr->PannerScale,
2106 tmp_win->frame_y / Scr->PannerScale);
2107 if (tmp_win->icon.w) {
2108 XReparentWindow(dpy, tmp_win->icon.w, Scr->VirtualDesktop,
2109 tmp_win->icon_loc_x + Scr->vdtPositionX,
2110 tmp_win->icon_loc_y + Scr->vdtPositionY);
2111 tmp_win->icon_loc_x += Scr->vdtPositionX;
2112 tmp_win->icon_loc_y += Scr->vdtPositionY;
2113 XMoveWindow(dpy, tmp_win->virtualIcon,
2114 tmp_win->icon_loc_x / Scr->PannerScale,
2115 tmp_win->icon_loc_y / Scr->PannerScale);
2116 }
2117 tmp_win->root = Scr->VirtualDesktop;
2118 }
2119 if (!tmp_win->isicon)
2120 XMapRaised(dpy, tmp_win->virtualWindow);
2121 else if (tmp_win->virtualIcon)
2122 XMapRaised(dpy, tmp_win->virtualIcon);
2123 tmp_win->sticky = False;
2124 SetSWM_ROOT(tmp_win);
2125 SetTWM_FLAGS(tmp_win);
2126 }
2127 else {
2128 if (Scr->StickyAbove) {
2129 XReparentWindow(dpy, tmp_win->frame, Scr->Root,
2130 tmp_win->frame_x - Scr->vdtPositionX,
2131 tmp_win->frame_y - Scr->vdtPositionY);
2132 tmp_win->frame_x -= Scr->vdtPositionX;
2133 tmp_win->frame_y -= Scr->vdtPositionY;
2134 if (tmp_win->icon.w) {
2135 XReparentWindow(dpy, tmp_win->icon.w, Scr->Root,
2136 tmp_win->icon_loc_x - Scr->vdtPositionX,
2137 tmp_win->icon_loc_y - Scr->vdtPositionY);
2138 tmp_win->icon_loc_x -= Scr->vdtPositionX;
2139 tmp_win->icon_loc_y -= Scr->vdtPositionY;
2140 }
2141 tmp_win->root = Scr->Root;
2142 }
2143 XUnmapWindow(dpy, tmp_win->virtualWindow);
2144 if (tmp_win->virtualIcon)
2145 XUnmapWindow(dpy, tmp_win->virtualIcon);
2146 tmp_win->sticky = True;
2147 SetSWM_ROOT(tmp_win);
2148 SetTWM_FLAGS(tmp_win);
2149 }
2150 }
2151 break;
2152
2153 case F_SORTICONMGR:
2154 if (DeferExecution(context, func, action, Scr->SelectCursor))
2155 return TRUE;
2156
2157 {
2158 int save_sort;
2159
2160 save_sort = Scr->SortIconMgr;
2161 Scr->SortIconMgr = TRUE;
2162
2163 if (context == C_ICONMGR)
2164 SortIconManager((IconMgr *) NULL);
2165 else if (tmp_win->iconmgr)
2166 SortIconManager(tmp_win->iconmgrp);
2167 else
2168 XBell(dpy, 0);
2169
2170 Scr->SortIconMgr = save_sort;
2171 }
2172 break;
2173
2174 case F_IDENTIFY:
2175 if (DeferExecution(context, func, action, Scr->SelectCursor))
2176 return TRUE;
2177
2178 Identify(tmp_win);
2179 break;
2180
2181 case F_VERSION:
2182 Identify ((TwmWindow *) NULL);
2183 break;
2184
2185 case F_AUTORAISE:
2186 if (DeferExecution(context, func, action, Scr->SelectCursor))
2187 return TRUE;
2188
2189 tmp_win->auto_raise = !tmp_win->auto_raise;
2190 if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
2191 else --(Scr->NumAutoRaises);
2192 break;
2193
2194 case F_BEEP:
2195 XBell(dpy, 0);
2196 break;
2197
2198 case F_POPUP:
2199 tmp_win = (TwmWindow *)action;
2200 if (Scr->WindowFunction.func != 0)
2201 {
2202 ExecuteFunction(Scr->WindowFunction.func,
2203 Scr->WindowFunction.item->action,
2204 NULL,
2205 w, tmp_win, eventp, C_FRAME, FALSE);
2206 }
2207 else
2208 {
2209 DeIconify(tmp_win);
2210 if (Scr->VirtualDesktop)
2211 ScrollToQuadrant(tmp_win);
2212 RaiseFrame (tmp_win);
2213 }
2214 break;
2215
2216 case F_RELATIVERESIZE:
2217 case F_RESIZE:
2218 EventHandler[EnterNotify] = HandleUnknown;
2219 EventHandler[LeaveNotify] = HandleUnknown;
2220 if (DeferExecution(context, func, action, Scr->MoveCursor))
2221 return TRUE;
2222
2223 PopDownMenu();
2224 if (pulldown)
2225 XWarpPointer(dpy, None, Scr->Root,
2226 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2227
2228 if (w != tmp_win->icon.w) { /* can't resize icons */
2229
2230 if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
2231 && fromMenu)
2232 resizeFromCenter(w, tmp_win);
2233 else {
2234 /*
2235 * see if this is being done from the titlebar
2236 */
2237 fromtitlebar =
2238 belongs_to_twm_window (tmp_win, eventp->xbutton.window);
2239
2240 /* Save pointer position so we can tell if it was moved or
2241 not during the resize. */
2242 ResizeOrigX = eventp->xbutton.x_root;
2243 ResizeOrigY = eventp->xbutton.y_root;
2244
2245 if (func == F_RELATIVERESIZE) {
2246 short Real_AutoRelativeResize = Scr->AutoRelativeResize;
2247 Scr->AutoRelativeResize = TRUE;
2248 StartResize (eventp, tmp_win, fromtitlebar);
2249 Scr->AutoRelativeResize = Real_AutoRelativeResize;
2250 } else {
2251 StartResize (eventp, tmp_win, fromtitlebar);
2252 }
2253
2254 do {
2255 XMaskEvent(dpy,
2256 ButtonPressMask | ButtonReleaseMask |
2257 EnterWindowMask | LeaveWindowMask |
2258 ButtonMotionMask, &Event);
2259
2260 if (fromtitlebar && Event.type == ButtonPress) {
2261 fromtitlebar = False;
2262 continue;
2263 }
2264
2265 if (Event.type == MotionNotify) {
2266 /* discard any extra motion events before a release */
2267 while
2268 (XCheckMaskEvent
2269 (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
2270 if (Event.type == ButtonRelease)
2271 break;
2272 }
2273
2274 if (!DispatchEvent ()) continue;
2275
2276 } while (!(Event.type == ButtonRelease || Cancel));
2277 return TRUE;
2278 }
2279 }
2280 break;
2281
2282
2283 case F_ZOOM:
2284 case F_HORIZOOM:
2285 case F_FULLZOOM:
2286 case F_LEFTZOOM:
2287 case F_RIGHTZOOM:
2288 case F_TOPZOOM:
2289 case F_BOTTOMZOOM:
2290 if (DeferExecution(context, func, action, Scr->SelectCursor))
2291 return TRUE;
2292 fullzoom(tmp_win, func);
2293 break;
2294
2295 case F_MOVE:
2296 case F_FORCEMOVE:
2297 case F_CONSTRAINEDMOVE:
2298 case F_OPAQUEMOVE:
2299 if (DeferExecution(context, func, action, Scr->MoveCursor))
2300 return TRUE;
2301
2302 PopDownMenu();
2303 rootw = eventp->xbutton.root;
2304 MoveFunction = func;
2305 if (MoveFunction == F_OPAQUEMOVE) {
2306 Real_OpaqueMove = Scr->OpaqueMove;
2307 Scr->OpaqueMove = TRUE;
2308 }
2309
2310 if (pulldown)
2311 XWarpPointer(dpy, None, Scr->Root,
2312 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2313
2314 if (context == C_ICON && tmp_win->icon.w)
2315 {
2316 DragIcon(tmp_win, eventp, pulldown);
2317 }
2318 else if (w != tmp_win->icon.w)
2319 {
2320 DragFrame(tmp_win, eventp, pulldown);
2321 }
2322 #ifdef OLD_MOVE
2323 if (DeferExecution(context, func, action, Scr->MoveCursor))
2324 return TRUE;
2325
2326 PopDownMenu();
2327 rootw = eventp->xbutton.root;
2328 MoveFunction = func;
2329
2330 if (pulldown)
2331 XWarpPointer(dpy, None, Scr->Root,
2332 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2333
2334 EventHandler[EnterNotify] = HandleUnknown;
2335 EventHandler[LeaveNotify] = HandleUnknown;
2336
2337 if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
2338 XGrabServer(dpy);
2339 }
2340 XGrabPointer(dpy, eventp->xbutton.root, True,
2341 ButtonPressMask | ButtonReleaseMask |
2342 ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
2343 GrabModeAsync, GrabModeAsync,
2344 Scr->Root, Scr->MoveCursor, CurrentTime);
2345
2346 if (context == C_ICON && tmp_win->icon.w)
2347 {
2348 w = tmp_win->icon.w;
2349 DragVirtual = tmp_win->virtualIcon;
2350 DragX = eventp->xbutton.x;
2351 DragY = eventp->xbutton.y;
2352 moving_icon = TRUE;
2353 }
2354 else if (w != tmp_win->icon.w)
2355 {
2356 XTranslateCoordinates(dpy, w, tmp_win->frame,
2357 eventp->xbutton.x,
2358 eventp->xbutton.y,
2359 &DragX, &DragY, &JunkChild);
2360
2361 w = tmp_win->frame;
2362 DragVirtual = tmp_win->virtualWindow;
2363 }
2364
2365 DragWindow = None;
2366
2367 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
2368 (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
2369 &JunkDepth);
2370
2371 origX = eventp->xbutton.x_root;
2372 origY = eventp->xbutton.y_root;
2373 CurrentDragX = origDragX;
2374 CurrentDragY = origDragY;
2375
2376 /*
2377 * only do the constrained move if timer is set; need to check it
2378 * in case of stupid or wicked fast servers
2379 */
2380 if ((ConstrainedMoveTime &&
2381 (eventp->xbutton.time - last_time) < ConstrainedMoveTime) ||
2382 (MoveFunction == F_CONSTRAINEDMOVE))
2383
2384 {
2385 int width, height;
2386
2387 ConstMove = TRUE;
2388 ConstMoveDir = MOVE_NONE;
2389 ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
2390 ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
2391 width = DragWidth + 2 * JunkBW;
2392 height = DragHeight + 2 * JunkBW;
2393 ConstMoveXL = ConstMoveX + width/3;
2394 ConstMoveXR = ConstMoveX + 2*(width/3);
2395 ConstMoveYT = ConstMoveY + height/3;
2396 ConstMoveYB = ConstMoveY + 2*(height/3);
2397
2398 XWarpPointer(dpy, None, w,
2399 0, 0, 0, 0, DragWidth/2, DragHeight/2);
2400
2401 XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
2402 &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2403 }
2404 last_time = eventp->xbutton.time;
2405
2406 if (!Scr->OpaqueMove)
2407 {
2408 InstallRootColormap();
2409 if (!Scr->MoveDelta)
2410 {
2411 /*
2412 * Draw initial outline. This was previously done the
2413 * first time though the outer loop by dropping out of
2414 * the XCheckMaskEvent inner loop down to one of the
2415 * MoveOutline's below.
2416 */
2417 MoveOutline(rootw,
2418 origDragX - JunkBW, origDragY - JunkBW,
2419 DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
2420 tmp_win->frame_bw,
2421 moving_icon ? 0 : tmp_win->title_height);
2422 /*
2423 * This next line causes HandleReleaseNotify to call
2424 * XRaiseWindow(). This is solely to preserve the
2425 * previous behaviour that raises a window being moved
2426 * on button release even if you never actually moved
2427 * any distance (unless you move less than MoveDelta or
2428 * NoRaiseMove is set or OpaqueMove is set).
2429 */
2430 DragWindow = w;
2431 }
2432 }
2433
2434 /*
2435 * see if this is being done from the titlebar
2436 */
2437 fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
2438
2439 if (menuFromFrameOrWindowOrTitlebar) {
2440 /* warp the pointer to the middle of the window */
2441 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
2442 origDragX + DragWidth / 2,
2443 origDragY + DragHeight / 2);
2444 XFlush(dpy);
2445 }
2446
2447 while (TRUE)
2448 {
2449 long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
2450 ButtonPress : ButtonRelease;
2451 long movementMask = menuFromFrameOrWindowOrTitlebar ?
2452 PointerMotionMask : ButtonMotionMask;
2453
2454 /* block until there is an interesting event */
2455 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
2456 EnterWindowMask | LeaveWindowMask |
2457 ExposureMask | movementMask |
2458 VisibilityChangeMask, &Event))
2459
2460 /* throw away enter and leave events until release */
2461 if (Event.xany.type == EnterNotify ||
2462 Event.xany.type == LeaveNotify) continue;
2463
2464 if (Event.type == MotionNotify) {
2465 /* discard any extra motion events before a logical release */
2466 while(XCheckMaskEvent(dpy,
2467 movementMask | releaseEvent, &Event))
2468 if (Event.type == releaseEvent)
2469 break;
2470 }
2471
2472 /* test to see if we have a second button press to abort move */
2473 if (!menuFromFrameOrWindowOrTitlebar)
2474 if (Event.type == ButtonPress && DragWindow != None) {
2475 if (Scr->OpaqueMove)
2476 XMoveWindow (dpy, DragWindow, origDragX, origDragY);
2477 else
2478 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
2479 DragWindow = None;
2480 }
2481
2482 if (fromtitlebar && Event.type == ButtonPress) {
2483 fromtitlebar = False;
2484 CurrentDragX = origX = Event.xbutton.x_root;
2485 CurrentDragY = origY = Event.xbutton.y_root;
2486 XTranslateCoordinates (dpy, rootw, tmp_win->frame,
2487 origX, origY,
2488 &DragX, &DragY, &JunkChild);
2489 continue;
2490 }
2491
2492 if (!DispatchEvent2 ()) continue;
2493
2494 if (Cancel)
2495 {
2496 WindowMoved = FALSE;
2497 if (!Scr->OpaqueMove)
2498 UninstallRootColormap();
2499 return TRUE; /* XXX should this be FALSE? */
2500 }
2501 if (Event.type == releaseEvent)
2502 {
2503 MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
2504 if (moving_icon &&
2505 ((CurrentDragX != origDragX ||
2506 CurrentDragY != origDragY)))
2507 tmp_win->icon_moved = TRUE;
2508 if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
2509 XMoveWindow(dpy, DragWindow,
2510 Event.xbutton.x_root - DragWidth / 2,
2511 Event.xbutton.y_root - DragHeight / 2);
2512 break;
2513 }
2514
2515 /* something left to do only if the pointer moved */
2516 if (Event.type != MotionNotify)
2517 continue;
2518
2519 XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
2520 &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
2521 &JunkX, &JunkY, &JunkMask);
2522
2523 if (DragWindow == None &&
2524 abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
2525 abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
2526 continue;
2527
2528 WindowMoved = TRUE;
2529 DragWindow = w;
2530
2531 if (!Scr->NoRaiseMove && Scr->OpaqueMove) /* can't restore... */
2532 XRaiseWindow(dpy, DragWindow);
2533
2534 if (ConstMove)
2535 {
2536 switch (ConstMoveDir)
2537 {
2538 case MOVE_NONE:
2539 if (eventp->xmotion.x_root < ConstMoveXL ||
2540 eventp->xmotion.x_root > ConstMoveXR)
2541 ConstMoveDir = MOVE_HORIZ;
2542
2543 if (eventp->xmotion.y_root < ConstMoveYT ||
2544 eventp->xmotion.y_root > ConstMoveYB)
2545 ConstMoveDir = MOVE_VERT;
2546
2547 XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
2548 &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2549 break;
2550
2551 case MOVE_VERT:
2552 ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
2553 break;
2554
2555 case MOVE_HORIZ:
2556 ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
2557 break;
2558 }
2559
2560 if (ConstMoveDir != MOVE_NONE)
2561 {
2562 int xl, yt, xr, yb, w, h;
2563
2564 xl = ConstMoveX;
2565 yt = ConstMoveY;
2566 w = DragWidth + 2 * JunkBW;
2567 h = DragHeight + 2 * JunkBW;
2568
2569 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2570 {
2571 xr = xl + w;
2572 yb = yt + h;
2573
2574 if (xl < 0)
2575 xl = 0;
2576 if (xr > Scr->MyDisplayWidth)
2577 xl = Scr->MyDisplayWidth - w;
2578
2579 if (yt < 0)
2580 yt = 0;
2581 if (yb > Scr->MyDisplayHeight)
2582 yt = Scr->MyDisplayHeight - h;
2583 }
2584 CurrentDragX = xl;
2585 CurrentDragY = yt;
2586 if (Scr->OpaqueMove)
2587 XMoveWindow(dpy, DragWindow, xl, yt);
2588 else
2589 MoveOutline(eventp->xmotion.root, xl, yt, w, h,
2590 tmp_win->frame_bw,
2591 moving_icon ? 0 : tmp_win->title_height);
2592 }
2593 }
2594 else if (DragWindow != None)
2595 {
2596 int xl, yt, xr, yb, w, h;
2597 if (!menuFromFrameOrWindowOrTitlebar) {
2598 xl = eventp->xmotion.x_root - DragX - JunkBW;
2599 yt = eventp->xmotion.y_root - DragY - JunkBW;
2600 }
2601 else {
2602 xl = eventp->xmotion.x_root - (DragWidth / 2);
2603 yt = eventp->xmotion.y_root - (DragHeight / 2);
2604 }
2605 w = DragWidth + 2 * JunkBW;
2606 h = DragHeight + 2 * JunkBW;
2607
2608 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2609 {
2610 xr = xl + w;
2611 yb = yt + h;
2612
2613 if (xl < 0)
2614 xl = 0;
2615 if (xr > Scr->MyDisplayWidth)
2616 xl = Scr->MyDisplayWidth - w;
2617
2618 if (yt < 0)
2619 yt = 0;
2620 if (yb > Scr->MyDisplayHeight)
2621 yt = Scr->MyDisplayHeight - h;
2622 }
2623
2624 CurrentDragX = xl;
2625 CurrentDragY = yt;
2626 if (Scr->OpaqueMove)
2627 XMoveWindow(dpy, DragWindow, xl, yt);
2628 else
2629 MoveOutline(eventp->xmotion.root, xl, yt, w, h,
2630 tmp_win->frame_bw,
2631 moving_icon ? 0 : tmp_win->title_height);
2632 }
2633
2634 }
2635
2636 if (!Scr->OpaqueMove && DragWindow == None)
2637 UninstallRootColormap();
2638 #endif /* OLD_MOVE */
2639
2640 if (MoveFunction == F_OPAQUEMOVE)
2641 Scr->OpaqueMove = Real_OpaqueMove ;
2642
2643 break;
2644
2645 case F_FUNCTION:
2646 case F_MENUFUNC:
2647 {
2648 MenuRoot *mroot;
2649 MenuItem *mitem;
2650
2651 if ((mroot = FindMenuRoot(action)) == NULL)
2652 {
2653 fprintf (stderr, "%s: couldn't find function \"%s\"\n",
2654 ProgramName, action);
2655 return TRUE;
2656 }
2657
2658 if (NeedToDefer(mroot) && DeferExecution(context, func, action, Scr->SelectCursor))
2659 return TRUE;
2660 else
2661 {
2662 for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
2663 {
2664 if (!ExecuteFunction (mitem->func, mitem->action, NULL, w,
2665 tmp_win, eventp, context, pulldown))
2666 break;
2667 }
2668 }
2669 }
2670 break;
2671
2672 case F_DEICONIFY:
2673 case F_ICONIFY:
2674 if (DeferExecution(context, func, action, Scr->SelectCursor))
2675 return TRUE;
2676
2677 if (tmp_win->isicon || !tmp_win->mapped ) {
2678 DeIconify(tmp_win);
2679 }
2680 else if (func == F_ICONIFY) {
2681 if ( tmp_win->root == Scr->VirtualDesktop ) {
2682 Iconify (tmp_win,
2683 eventp->xbutton.x_root - 5 + Scr->vdtPositionX,
2684 eventp->xbutton.y_root - 5 + Scr->vdtPositionY
2685 );
2686 }
2687 else {
2688 Iconify (tmp_win, eventp->xbutton.x_root - 5,
2689 eventp->xbutton.y_root - 5);
2690 }
2691 }
2692 break;
2693
2694 case F_RAISELOWER:
2695 if (DeferExecution(context, func, action, Scr->SelectCursor))
2696 return TRUE;
2697
2698 if (!WindowMoved) {
2699 Window virtual;
2700 XWindowChanges xwc;
2701
2702 xwc.stack_mode = Opposite;
2703 virtual = tmp_win->virtualIcon;
2704 if (w != tmp_win->icon.w) {
2705 w = tmp_win->frame;
2706 virtual = tmp_win->virtualWindow;
2707 }
2708 XConfigureWindow (dpy, w, CWStackMode, &xwc);
2709 if (tmp_win->sticky && Scr->VirtualDesktop)
2710 XLowerWindow(dpy, Scr->VirtualDesktop);
2711 if (virtual)
2712 XConfigureWindow (dpy, virtual, CWStackMode, &xwc);
2713 }
2714 break;
2715
2716 case F_RAISE:
2717 if (DeferExecution(context, func, action, Scr->SelectCursor))
2718 return TRUE;
2719
2720 /* check to make sure raise is not from the WindowFunction */
2721 if (w == tmp_win->icon.w && Context != C_ROOT)
2722 RaiseIcon(tmp_win);
2723 else
2724 RaiseFrame(tmp_win);
2725
2726 break;
2727
2728 case F_LOWER:
2729 if (DeferExecution(context, func, action, Scr->SelectCursor))
2730 return TRUE;
2731
2732 if (w == tmp_win->icon.w)
2733 LowerIcon(tmp_win);
2734 else
2735 LowerFrame(tmp_win);
2736
2737 break;
2738
2739 case F_FOCUS:
2740 if (DeferExecution(context, func, action, Scr->SelectCursor))
2741 return TRUE;
2742
2743 if (tmp_win->isicon == FALSE)
2744 {
2745 if (!Scr->FocusRoot && Scr->Focus == tmp_win)
2746 {
2747 FocusOnRoot();
2748 }
2749 else
2750 {
2751 if (Scr->Focus != NULL) {
2752 SetBorder (Scr->Focus, False);
2753 if (Scr->Focus->hilite_w)
2754 XUnmapWindow (dpy, Scr->Focus->hilite_w);
2755 }
2756
2757 InstallWindowColormaps (0, tmp_win);
2758 if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
2759 SetBorder (tmp_win, True);
2760 SetFocus (tmp_win, eventp->xbutton.time);
2761 Scr->FocusRoot = FALSE;
2762 Scr->Focus = tmp_win;
2763 }
2764 }
2765 break;
2766
2767 case F_DESTROY:
2768 if (DeferExecution(context, func, action, Scr->DestroyCursor))
2769 return TRUE;
2770
2771 if (tmp_win->iconmgr)
2772 XBell(dpy, 0);
2773 else if (tmp_win->w == Scr->Panner) {
2774 UnmapFrame(tmp_win);
2775 tmp_win->mapped = FALSE;
2776 }
2777 else
2778 XKillClient(dpy, tmp_win->w);
2779 break;
2780
2781 case F_DELETE:
2782 if (DeferExecution(context, func, action, Scr->DestroyCursor))
2783 return TRUE;
2784
2785 if (tmp_win->iconmgr) /* don't send ourself a message */
2786 HideIconManager ();
2787 else if (tmp_win->protocols & DoesWmDeleteWindow)
2788 SendDeleteWindowMessage (tmp_win, LastTimestamp());
2789 else
2790 XBell (dpy, 0);
2791 break;
2792
2793 case F_DELETEORDESTROY:
2794 if (DeferExecution(context, func, action, Scr->DestroyCursor))
2795 return TRUE;
2796
2797 if (tmp_win->iconmgr) /* don't send ourself a message */
2798 HideIconManager();
2799 else if (tmp_win->w == Scr->Panner) {
2800 UnmapFrame(tmp_win);
2801 tmp_win->mapped = FALSE;
2802 } else if (tmp_win->protocols & DoesWmDeleteWindow)
2803 SendDeleteWindowMessage (tmp_win, LastTimestamp());
2804 else
2805 XKillClient(dpy, tmp_win->w);
2806 break;
2807
2808 case F_SAVEYOURSELF:
2809 if (DeferExecution (context, func, action, Scr->SelectCursor))
2810 return TRUE;
2811
2812 if (tmp_win->protocols & DoesWmSaveYourself)
2813 SendSaveYourselfMessage (tmp_win, LastTimestamp());
2814 else
2815 XBell (dpy, 0);
2816 break;
2817
2818 case F_CIRCLEUP:
2819 if (Scr->VirtualDesktop) {
2820 XCirculateSubwindowsUp(dpy, Scr->VirtualDesktop);
2821 XCirculateSubwindowsUp(dpy, Scr->Panner);
2822 }
2823 else
2824 XCirculateSubwindowsUp(dpy, Scr->Root);
2825 break;
2826
2827 case F_CIRCLEDOWN:
2828 if (Scr->VirtualDesktop) {
2829 XCirculateSubwindowsDown(dpy, Scr->VirtualDesktop);
2830 XCirculateSubwindowsDown(dpy, Scr->Panner);
2831 }
2832 else
2833 XCirculateSubwindowsDown(dpy, Scr->Root);
2834 break;
2835
2836 case F_EXEC:
2837 PopDownMenu();
2838 if (!Scr->NoGrabServer) {
2839 XUngrabServer (dpy);
2840 XSync (dpy, 0);
2841 }
2842 (void)Execute(action, tmp_win);
2843 break;
2844
2845 case F_WINEXEC:
2846 if (DeferExecution(context, func, action, Scr->SelectCursor))
2847 return TRUE;
2848
2849 PopDownMenu();
2850 if (!Scr->NoGrabServer)
2851 XUngrabServer(dpy);
2852 XUngrabPointer(dpy, CurrentTime);
2853 XSync(dpy, 0);
2854 (void)Execute(action, tmp_win);
2855 break;
2856
2857 case F_TESTEXEC:
2858 PopDownMenu();
2859 if (!Scr->NoGrabServer) {
2860 XUngrabServer (dpy);
2861 XSync (dpy, 0);
2862 }
2863 do_next_action= (Execute(action, tmp_win)==0);
2864 if ( !do_next_action )
2865 XBell(dpy,0);
2866 break;
2867
2868 case F_TESTWINEXEC:
2869 if (DeferExecution(context, func, action, Scr->SelectCursor))
2870 return TRUE;
2871
2872 PopDownMenu();
2873 if (!Scr->NoGrabServer)
2874 XUngrabServer(dpy);
2875 XUngrabPointer(dpy, CurrentTime);
2876 XSync(dpy, 0);
2877 do_next_action = (Execute(action, tmp_win) == 0);
2878 if (!do_next_action)
2879 XBell(dpy, 0);
2880 break;
2881
2882 case F_UNFOCUS:
2883 FocusOnRoot();
2884 break;
2885
2886 case F_CUT:
2887 strcpy(tmp, action);
2888 strcat(tmp, "\n");
2889 XStoreBytes(dpy, tmp, strlen(tmp));
2890 break;
2891
2892 case F_CUTFILE:
2893 ptr = XFetchBytes(dpy, &count);
2894 if (ptr) {
2895 if (sscanf (ptr, "%s", tmp) == 1) {
2896 XFree (ptr);
2897 ptr = ExpandFilename(tmp);
2898 if (ptr) {
2899 fd = open (ptr, 0);
2900 if (fd >= 0) {
2901 count = read (fd, buff, MAX_FILE_SIZE - 1);
2902 if (count > 0) XStoreBytes (dpy, buff, count);
2903 close(fd);
2904 } else {
2905 fprintf (stderr,
2906 "%s: unable to open cut file \"%s\"\n",
2907 ProgramName, tmp);
2908 }
2909 if (ptr != tmp) free (ptr);
2910 }
2911 } else {
2912 XFree(ptr);
2913 }
2914 } else {
2915 fprintf(stderr, "%s: cut buffer is empty\n", ProgramName);
2916 }
2917 break;
2918
2919 case F_WARPTOSCREEN:
2920 {
2921 if (strcmp (action, WARPSCREEN_NEXT) == 0) {
2922 WarpToScreen (Scr->screen + 1, 1);
2923 } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
2924 WarpToScreen (Scr->screen - 1, -1);
2925 } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
2926 WarpToScreen (PreviousScreen, 0);
2927 } else {
2928 WarpToScreen (atoi (action), 0);
2929 }
2930 }
2931 break;
2932
2933 case F_COLORMAP:
2934 {
2935 if (strcmp (action, COLORMAP_NEXT) == 0) {
2936 BumpWindowColormap (tmp_win, 1);
2937 } else if (strcmp (action, COLORMAP_PREV) == 0) {
2938 BumpWindowColormap (tmp_win, -1);
2939 } else {
2940 BumpWindowColormap (tmp_win, 0);
2941 }
2942 }
2943 break;
2944
2945 case F_WARPTO:
2946 {
2947 register TwmWindow *t;
2948 int len;
2949
2950 len = strlen(action);
2951
2952 if (len == 0) {
2953 if (!tmp_win)
2954 XBell (dpy,0);
2955 else
2956 WarpThere(tmp_win);
2957 } else {
2958 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2959 if (!strncmp(action, t->name, len))
2960 if (WarpThere(t))
2961 break;
2962 }
2963 if (!t) {
2964 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2965 if (!strncmp(action, t->class.res_name, len))
2966 if (WarpThere(t))
2967 break;
2968 }
2969 if (!t) {
2970 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2971 if (!strncmp(action, t->class.res_class, len))
2972 if (WarpThere(t))
2973 break;
2974 }
2975 }
2976 }
2977
2978 if (!t)
2979 XBell (dpy, 0);
2980 }
2981 }
2982 break;
2983
2984 case F_WARPTOICONMGR:
2985 {
2986 TwmWindow *t;
2987 int len;
2988 Window raisewin = None, iconwin = None;
2989 TwmWindow *raiseFrame;
2990
2991 len = strlen(action);
2992 if (len == 0) {
2993 if (tmp_win && tmp_win->list) {
2994 raisewin = tmp_win->list->iconmgr->twm_win->frame;
2995 raiseFrame = tmp_win->list->iconmgr->twm_win;
2996 iconwin = tmp_win->list->icon;
2997 } else if (Scr->iconmgr.active) {
2998 raisewin = Scr->iconmgr.twm_win->frame;
2999 raiseFrame = Scr->iconmgr.twm_win;
3000 iconwin = Scr->iconmgr.active->w;
3001 }
3002 } else {
3003 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
3004 if (strncmp (action, t->icon_name, len) == 0) {
3005 if (t->list && t->list->iconmgr->twm_win->mapped) {
3006 raisewin = t->list->iconmgr->twm_win->frame;
3007 raiseFrame = t->list->iconmgr->twm_win;
3008 iconwin = t->list->icon;
3009 break;
3010 }
3011 }
3012 }
3013 }
3014
3015 if (raisewin) {
3016 RaiseFrame (raiseFrame);
3017 ScrollToQuadrant(raiseFrame);
3018 XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
3019 } else {
3020 XBell (dpy, 0);
3021 }
3022 }
3023 break;
3024
3025 case F_WARPRING:
3026 switch (action[0]) {
3027 case 'n':
3028 WarpAlongRing (&eventp->xbutton, True);
3029 break;
3030 case 'p':
3031 WarpAlongRing (&eventp->xbutton, False);
3032 break;
3033 default:
3034 XBell (dpy, 0);
3035 break;
3036 }
3037 break;
3038
3039 case F_FILE:
3040 action = ExpandFilename(action);
3041 fd = open(action, 0);
3042 if (fd >= 0)
3043 {
3044 count = read(fd, buff, MAX_FILE_SIZE - 1);
3045 if (count > 0)
3046 XStoreBytes(dpy, buff, count);
3047
3048 close(fd);
3049 }
3050 else
3051 {
3052 fprintf (stderr, "%s: unable to open file \"%s\"\n",
3053 ProgramName, action);
3054 }
3055 break;
3056
3057 case F_REFRESH:
3058 {
3059 XSetWindowAttributes attributes;
3060 unsigned long valuemask;
3061
3062 valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
3063 attributes.background_pixel = Scr->Black;
3064 attributes.backing_store = NotUseful;
3065 attributes.save_under = False;
3066 w = XCreateWindow (dpy, Scr->Root, 0, 0,
3067 (unsigned int) Scr->MyDisplayWidth,
3068 (unsigned int) Scr->MyDisplayHeight,
3069 (unsigned int) 0,
3070 CopyFromParent, (unsigned int) CopyFromParent,
3071 (Visual *) CopyFromParent, valuemask,
3072 &attributes);
3073 XMapWindow (dpy, w);
3074 XDestroyWindow (dpy, w);
3075 XFlush (dpy);
3076 }
3077 break;
3078
3079 case F_WINREFRESH:
3080 if (DeferExecution(context, func, action, Scr->SelectCursor))
3081 return TRUE;
3082
3083 if (context == C_ICON && tmp_win->icon.w)
3084 w = XCreateSimpleWindow(dpy, tmp_win->icon.w,
3085 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
3086 else
3087 w = XCreateSimpleWindow(dpy, tmp_win->frame,
3088 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
3089
3090 XMapWindow(dpy, w);
3091 XDestroyWindow(dpy, w);
3092 XFlush(dpy);
3093 break;
3094
3095 case F_RELATIVEMOVE:
3096 if (tmp_win && !tmp_win->isicon && tmp_win->mapped)
3097 RelativeMove(tmp_win, action);
3098 break;
3099
3100 case F_DUMPSTATE:
3101 printf("doing dumpstate\n");
3102 {
3103 Window RootW;
3104 Window root, parent, *children;
3105 unsigned int nchildren;
3106 unsigned int numscr;
3107 unsigned int i;
3108 unsigned int scr;
3109
3110 numscr = ScreenCount(dpy);
3111 printf("# of screens: %d\n",numscr);
3112 for(scr = 0; scr <= (numscr-1); scr++) {
3113 RootW = RootWindow(dpy, scr);
3114 printf("rootw: 0x%x\n",RootW);
3115 XGrabServer(dpy);
3116 XSync(dpy, 0);
3117 XQueryTree(dpy, RootW, &root, &parent, &children, &nchildren);
3118 for (i = 0; i < nchildren; i++) {
3119 if (children[i]) {
3120 XWMHints *wmhintsp = XGetWMHints (dpy, children[i]);
3121 if (wmhintsp) {
3122 if (wmhintsp->flags) {
3123 printf("i: %d wmhints w: 0x%x flags: %d ",
3124 i,children[i], wmhintsp->flags
3125 );
3126 if ( wmhintsp->flags & StateHint ) {
3127 printf("state: %d ",
3128 wmhintsp->initial_state);
3129 }
3130 printf("\n");
3131 }
3132 }
3133 }
3134 else {
3135 printf(" NOT DEFINED\n");
3136 }
3137 }
3138 }
3139 XUngrabServer(dpy);
3140 XFree(children);
3141 }
3142 break;
3143
3144 case F_QUIT:
3145 Done();
3146 break;
3147 }
3148
3149 if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
3150 return do_next_action;
3151 }
3152
3153
3154
3155 /***********************************************************************
3156 *
3157 * Procedure:
3158 * DeferExecution - defer the execution of a function to the
3159 * next button press if the context is C_ROOT
3160 *
3161 * Inputs:
3162 * context - the context in which the mouse button was pressed
3163 * func - the function to defer
3164 * cursor - the cursor to display while waiting
3165 *
3166 ***********************************************************************
3167 */
3168
3169 int
DeferExecution(context,func,action,cursor)3170 DeferExecution(context, func, action, cursor)
3171 int context, func;
3172 char *action;
3173 Cursor cursor;
3174 {
3175 if (context == C_ROOT)
3176 {
3177 LastCursor = cursor;
3178 XGrabPointer(dpy, Scr->Root, True,
3179 ButtonPressMask | ButtonReleaseMask,
3180 GrabModeAsync, GrabModeAsync,
3181 Scr->Root, cursor, CurrentTime);
3182
3183 RootAction = action;
3184 RootFunction = func;
3185
3186 return (TRUE);
3187 }
3188
3189 return (FALSE);
3190 }
3191
3192
3193
3194 /***********************************************************************
3195 *
3196 * Procedure:
3197 * ReGrab - regrab the pointer with the LastCursor;
3198 *
3199 ***********************************************************************
3200 */
3201
ReGrab()3202 ReGrab()
3203 {
3204 XGrabPointer(dpy, Scr->Root, True,
3205 ButtonPressMask | ButtonReleaseMask,
3206 GrabModeAsync, GrabModeAsync,
3207 Scr->Root, LastCursor, CurrentTime);
3208 }
3209
3210
3211
3212 /***********************************************************************
3213 *
3214 * Procedure:
3215 * NeedToDefer - checks each function in the list to see if it
3216 * is one that needs to be defered.
3217 *
3218 * Inputs:
3219 * root - the menu root to check
3220 *
3221 ***********************************************************************
3222 */
3223
Deferrable(func)3224 Deferrable(func)
3225 int func;
3226 {
3227 switch (func) {
3228 case F_IDENTIFY:
3229 case F_RESIZE:
3230 case F_MOVE:
3231 case F_FORCEMOVE:
3232 case F_DEICONIFY:
3233 case F_ICONIFY:
3234 case F_RAISELOWER:
3235 case F_RAISE:
3236 case F_LOWER:
3237 case F_FOCUS:
3238 case F_DESTROY:
3239 case F_DELETE:
3240 case F_DELETEORDESTROY:
3241 case F_DUMPSTATE:
3242 case F_WINREFRESH:
3243 case F_ZOOM:
3244 case F_FULLZOOM:
3245 case F_HORIZOOM:
3246 case F_RIGHTZOOM:
3247 case F_LEFTZOOM:
3248 case F_TOPZOOM:
3249 case F_BOTTOMZOOM:
3250 case F_AUTORAISE:
3251 case F_WINEXEC:
3252 case F_TESTWINEXEC:
3253 return TRUE;
3254 default:
3255 return FALSE;
3256 }
3257 }
3258
NeedToDefer(root)3259 NeedToDefer(root)
3260 MenuRoot *root;
3261 {
3262 MenuItem *mitem;
3263
3264 for (mitem = root->first; mitem != NULL; mitem = mitem->next)
3265 if (Deferrable(mitem->func))
3266 return TRUE;
3267 return FALSE;
3268 }
3269
3270
3271
3272 /***********************************************************************
3273 *
3274 * Procedure:
3275 * Execute - execute the string by /bin/sh
3276 *
3277 * Inputs:
3278 * s - the string containing the command
3279 *
3280 ***********************************************************************
3281 */
3282
3283 int
Execute(s,tmp_win)3284 Execute(s, tmp_win)
3285 char *s;
3286 TwmWindow *tmp_win;
3287 {
3288 static char buf1[256];
3289 static char buf2[256];
3290 static char buf3[256];
3291 static char buf4[256];
3292 static char buf5[256];
3293 static char buf6[256];
3294 char *ds = DisplayString (dpy);
3295 char *colon, *dot1;
3296 char oldDisplay[256];
3297 char *doisplay;
3298 int restorevar = 0;
3299 int status;
3300
3301 oldDisplay[0] = '\0';
3302 doisplay=getenv("DISPLAY");
3303 if (doisplay)
3304 strcpy (oldDisplay, doisplay);
3305
3306 /*
3307 * Build a display string using the current screen number, so that
3308 * X programs which get fired up from a menu come up on the screen
3309 * that they were invoked from, unless specifically overridden on
3310 * their command line.
3311 */
3312 colon = rindex (ds, ':');
3313 if (colon) { /* if host[:]:dpy */
3314 strcpy (buf1, "DISPLAY=");
3315 strcat (buf1, ds);
3316 colon = buf1 + 8 + (colon - ds); /* use version in buf */
3317 dot1 = index (colon, '.'); /* first period after colon */
3318 if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */
3319 (void) sprintf (dot1, ".%d", Scr->screen);
3320 putenv (buf1);
3321 restorevar = 1;
3322 }
3323
3324 if (tmp_win != NULL ) {
3325 sprintf(buf2, "TWM_WIN=0x%lx", tmp_win->w);
3326 putenv(buf2);
3327 sprintf(buf3, "TWM_WIN_NAME=%s", tmp_win->full_name);
3328 putenv(buf3);
3329 sprintf(buf4, "TWM_ICON_NAME=%s", tmp_win->icon_name);
3330 putenv(buf4);
3331 sprintf(buf5, "TWM_RES_NAME=%s", tmp_win->class.res_name);
3332 putenv(buf5);
3333 sprintf(buf6, "TWM_RES_CLASS=%s", tmp_win->class.res_class);
3334 putenv(buf6);
3335 }
3336
3337 status=system (s);
3338
3339 /* this next bit may be horribly BSD specific. */
3340 if ( (status&0xff) == 0 )
3341 status = (status &0xff00) >> 8;
3342
3343 if (restorevar) { /* why bother? */
3344 (void) sprintf (buf1, "DISPLAY=%s", oldDisplay);
3345 putenv (buf1);
3346 }
3347
3348 return status;
3349 }
3350
3351
3352
3353 /***********************************************************************
3354 *
3355 * Procedure:
3356 * FocusOnRoot - put input focus on the root window
3357 *
3358 ***********************************************************************
3359 */
3360
3361 void
FocusOnRoot()3362 FocusOnRoot()
3363 {
3364 SetFocus ((TwmWindow *) NULL, LastTimestamp());
3365 if (Scr->Focus != NULL)
3366 {
3367 SetBorder (Scr->Focus, False);
3368 if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
3369 }
3370 InstallWindowColormaps(0, &Scr->TwmRoot);
3371 Scr->Focus = NULL;
3372 Scr->FocusRoot = TRUE;
3373 }
3374
DeIconify(tmp_win)3375 DeIconify(tmp_win)
3376 TwmWindow *tmp_win;
3377 {
3378 TwmWindow *t;
3379
3380 /* de-iconify the main window */
3381 if (tmp_win->isicon)
3382 {
3383 if (tmp_win->icon_on)
3384 Zoom(tmp_win->icon.w, tmp_win->frame);
3385 else if (tmp_win->group != 0)
3386 {
3387 for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3388 {
3389 if (tmp_win->group == t->w && t->icon_on)
3390 {
3391 Zoom(t->icon.w, tmp_win->frame);
3392 break;
3393 }
3394 }
3395 }
3396 }
3397
3398
3399 tmp_win->mapped = TRUE;
3400 if (!Scr->NoRaiseDeicon)
3401 RaiseFrame(tmp_win);
3402 MapFrame(tmp_win);
3403 SetMapStateProp(tmp_win, NormalState);
3404
3405 if (tmp_win->icon.w) {
3406 UnmapIcon(tmp_win);
3407 IconDown (tmp_win);
3408 }
3409 if (tmp_win->list)
3410 XUnmapWindow(dpy, tmp_win->list->icon);
3411 if ((Scr->WarpCursor ||
3412 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
3413 tmp_win->isicon)
3414 WarpToWindow (tmp_win);
3415 tmp_win->isicon = FALSE;
3416 tmp_win->icon_on = FALSE;
3417
3418
3419 /* now de-iconify transients */
3420 for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3421 {
3422 if (t->transient && t->transientfor == tmp_win->w)
3423 {
3424 if (t->icon_on)
3425 Zoom(t->icon.w, t->frame);
3426 else
3427 Zoom(tmp_win->icon.w, t->frame);
3428
3429 t->mapped = TRUE;
3430 if (!Scr->NoRaiseDeicon)
3431 RaiseFrame(t);
3432 MapFrame(t);
3433 SetMapStateProp(t, NormalState);
3434
3435 if (t->icon.w) {
3436 UnmapIcon(t);
3437 IconDown (t);
3438 }
3439 if (t->list) XUnmapWindow(dpy, t->list->icon);
3440 t->isicon = FALSE;
3441 t->icon_on = FALSE;
3442 }
3443 }
3444
3445 XSync (dpy, 0);
3446 }
3447
3448
3449
Iconify(tmp_win,def_x,def_y)3450 Iconify(tmp_win, def_x, def_y)
3451 TwmWindow *tmp_win;
3452 int def_x, def_y;
3453 {
3454 TwmWindow *t;
3455 int iconify;
3456 XWindowAttributes winattrs;
3457 unsigned long eventMask;
3458
3459 iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
3460 if (iconify)
3461 {
3462 if (tmp_win->icon.w == None)
3463 CreateIconWindow(tmp_win, def_x, def_y);
3464 else
3465 IconUp(tmp_win);
3466 MapIcon(tmp_win);
3467 }
3468 if (tmp_win->list)
3469 XMapWindow(dpy, tmp_win->list->icon);
3470
3471 XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
3472 eventMask = winattrs.your_event_mask;
3473
3474 /* iconify transients first */
3475 for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3476 {
3477 if (t->transient && t->transientfor == tmp_win->w)
3478 {
3479 if (iconify)
3480 {
3481 if (t->icon_on)
3482 Zoom(t->icon.w, tmp_win->icon.w);
3483 else
3484 Zoom(t->frame, tmp_win->icon.w);
3485 }
3486
3487 /*
3488 * Prevent the receipt of an UnmapNotify, since that would
3489 * cause a transition to the Withdrawn state.
3490 */
3491 t->mapped = FALSE;
3492 XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
3493 UnmapFrame(t);
3494 XSelectInput(dpy, t->w, eventMask);
3495 if (t->icon.w)
3496 UnmapIcon(t);
3497 SetMapStateProp(t, IconicState);
3498 SetBorder (t, False);
3499 if (t == Scr->Focus)
3500 {
3501 SetFocus ((TwmWindow *) NULL, LastTimestamp());
3502 Scr->Focus = NULL;
3503 Scr->FocusRoot = TRUE;
3504 }
3505 if (t->list) XMapWindow(dpy, t->list->icon);
3506 t->isicon = TRUE;
3507 t->icon_on = FALSE;
3508 }
3509 }
3510
3511 if (iconify)
3512 Zoom(tmp_win->frame, tmp_win->icon.w);
3513
3514 /*
3515 * Prevent the receipt of an UnmapNotify, since that would
3516 * cause a transition to the Withdrawn state.
3517 */
3518 tmp_win->mapped = FALSE;
3519 XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
3520 UnmapFrame(tmp_win);
3521 XSelectInput(dpy, tmp_win->w, eventMask);
3522 SetMapStateProp(tmp_win, IconicState);
3523
3524 SetBorder (tmp_win, False);
3525 if (tmp_win == Scr->Focus)
3526 {
3527 SetFocus ((TwmWindow *) NULL, LastTimestamp());
3528 Scr->Focus = NULL;
3529 Scr->FocusRoot = TRUE;
3530 }
3531 tmp_win->isicon = TRUE;
3532 if (iconify)
3533 tmp_win->icon_on = TRUE;
3534 else
3535 tmp_win->icon_on = FALSE;
3536 XSync (dpy, 0);
3537 }
3538
3539
3540
Identify(t)3541 static void Identify (t)
3542 TwmWindow *t;
3543 {
3544 int i, n, twidth, width, height;
3545 int x, y;
3546 unsigned int wwidth, wheight, bw, depth;
3547 Window junk;
3548 int px, py, dummy;
3549 unsigned udummy;
3550 char *s;
3551
3552 n = 0;
3553
3554 if (Scr->Identification) {
3555 (void) sprintf(Info[n++], "%s", Scr->Identification);
3556 Info[n++][0] = '\0';
3557 }
3558
3559 (void) sprintf(Info[n++], "tvtwm version: %s", Version);
3560 #ifdef BETA
3561 (void) sprintf(Info[n++], "tvtwm Patchlevel %d%s", PATCHLEVEL, BETA);
3562 #else
3563 (void) sprintf(Info[n++], "tvtwm Patchlevel %d", PATCHLEVEL);
3564 #endif
3565
3566 Info[n++][0] = '\0';
3567
3568 if (t) {
3569 XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
3570 &wwidth, &wheight, &bw, &depth);
3571 (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
3572 &x, &y, &junk);
3573 (void) sprintf(Info[n++], "Name = \"%s\"", t->full_name);
3574 (void) sprintf(Info[n++], "Class.res_name = \"%s\"", t->class.res_name);
3575 (void) sprintf(Info[n++], "Class.res_class = \"%s\"", t->class.res_class);
3576 if ((s = GetPropertyString(t->w, XA_WM_CLIENT_MACHINE)) != NULL)
3577 (void) sprintf(Info[n++], "Host = \"%s\"", s);
3578 else
3579 (void) sprintf(Info[n++], "Host = <empty>");
3580 Info[n++][0] = '\0';
3581 (void) sprintf(Info[n++], "Geometry/root = %dx%d+%d+%d", wwidth, wheight,
3582 x, y);
3583 (void) sprintf(Info[n++], "Border width = %d", bw);
3584 (void) sprintf(Info[n++], "Depth = %d", depth);
3585 }
3586
3587 Info[n++][0] = '\0';
3588 (void) sprintf(Info[n++], "Click to dismiss...");
3589
3590 /* figure out the width and height of the info window */
3591 height = n * (Scr->DefaultFont.height+2);
3592 width = 1;
3593 for (i = 0; i < n; i++)
3594 {
3595 twidth = XTextWidth(Scr->DefaultFont.font, Info[i],
3596 strlen(Info[i]));
3597 if (twidth > width)
3598 width = twidth;
3599 }
3600 if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
3601
3602 width += 10; /* some padding */
3603 if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
3604 &dummy, &dummy, &udummy)) {
3605 px -= (width / 2);
3606 py -= (height / 3);
3607 if (px + width + BW2 >= Scr->MyDisplayWidth)
3608 px = Scr->MyDisplayWidth - width - BW2;
3609 if (py + height + BW2 >= Scr->MyDisplayHeight)
3610 py = Scr->MyDisplayHeight - height - BW2;
3611 if (px < 0) px = 0;
3612 if (py < 0) py = 0;
3613 } else {
3614 px = py = 0;
3615 }
3616 XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
3617 XMapRaised(dpy, Scr->InfoWindow);
3618 #ifdef XPM
3619 if (!t) {
3620 # include "emblem.h"
3621 /* XXX - need to support the None color, at some point here. */
3622 /* currently, the automatic masking stuff in XPM doesn't work */
3623 /* for this image. - cross */
3624 Pixmap pixmap;
3625 int XPMret;
3626 XpmColorSymbol bgcolor;
3627 XpmAttributes attribs;
3628
3629 bgcolor.name = "background";
3630 bgcolor.value = NULL;
3631 bgcolor.pixel = Scr->DefaultC.back;
3632
3633 attribs.valuemask = XpmColorSymbols | XpmVisual |
3634 XpmColormap | XpmDepth;
3635 attribs.colorsymbols = &bgcolor;
3636 attribs.numsymbols = 1;
3637 attribs.visual = Scr->d_visual;
3638 attribs.colormap = DefaultColormap(dpy, Scr->screen);
3639 attribs.depth = Scr->d_depth;
3640
3641 if ((XPMret = XpmCreatePixmapFromData(dpy, RootWindow(dpy, Scr->screen),
3642 emblem, &pixmap, NULL, &attribs)) >= 0) {
3643
3644 XCopyArea(dpy, pixmap, Scr->InfoWindow,
3645 DefaultGC(dpy, Scr->screen), 0, 0,
3646 attribs.width, attribs.height,
3647 (width-attribs.width), (height-attribs.height));
3648 XFlush(dpy);
3649 } else fprintf(stderr, "tvtwm: Error creating info-box pixmap (Error code: %d)\n", XPMret);
3650 }
3651 #endif
3652 InfoLines = n;
3653 }
3654
3655
3656
SetMapStateProp(tmp_win,state)3657 SetMapStateProp(tmp_win, state)
3658 TwmWindow *tmp_win;
3659 int state;
3660 {
3661 unsigned long data[2]; /* "suggested" by ICCCM version 1 */
3662
3663 data[0] = (unsigned long) state;
3664 data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
3665 tmp_win->icon.w);
3666
3667 XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
3668 PropModeReplace, (unsigned char *) data, 2);
3669 }
3670
3671
3672
GetWMState(w,statep,iwp)3673 Bool GetWMState (w, statep, iwp)
3674 Window w;
3675 int *statep;
3676 Window *iwp;
3677 {
3678 Atom actual_type;
3679 int actual_format;
3680 unsigned long nitems, bytesafter;
3681 unsigned long *datap = NULL;
3682 Bool retval = False;
3683
3684 if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
3685 &actual_type, &actual_format, &nitems, &bytesafter,
3686 (unsigned char **) &datap) != Success || !datap)
3687 return False;
3688
3689 if (nitems <= 2) { /* "suggested" by ICCCM version 1 */
3690 *statep = (int) datap[0];
3691 *iwp = (Window) datap[1];
3692 retval = True;
3693 }
3694
3695 XFree ((char *) datap);
3696 return retval;
3697 }
3698
3699
3700
WarpToScreen(n,inc)3701 WarpToScreen (n, inc)
3702 int n, inc;
3703 {
3704 Window dumwin;
3705 int x, y, dumint;
3706 unsigned int dummask;
3707 ScreenInfo *newscr = NULL;
3708
3709 while (!newscr) {
3710 /* wrap around */
3711 if (n < 0)
3712 n = NumScreens - 1;
3713 else if (n >= NumScreens)
3714 n = 0;
3715
3716 newscr = ScreenList[n];
3717 if (!newscr) { /* make sure screen is managed */
3718 if (inc) { /* walk around the list */
3719 n += inc;
3720 continue;
3721 }
3722 fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n",
3723 ProgramName, n);
3724 XBell (dpy, 0);
3725 return;
3726 }
3727 }
3728
3729 if (Scr->screen == n) return; /* already on that screen */
3730
3731 PreviousScreen = Scr->screen;
3732 XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
3733 &dumint, &dumint, &dummask);
3734
3735 XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
3736 return;
3737 }
3738
3739
3740
3741 /*
3742 * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
3743 */
3744
BumpWindowColormap(tmp,inc)3745 BumpWindowColormap (tmp, inc)
3746 TwmWindow *tmp;
3747 int inc;
3748 {
3749 int i, j, previously_installed;
3750 ColormapWindow **cwins;
3751
3752 if (!tmp) return;
3753
3754 if (inc && tmp->cmaps.number_cwins > 0) {
3755 cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
3756 tmp->cmaps.number_cwins);
3757 if (cwins) {
3758 if (previously_installed =
3759 /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
3760 tmp->cmaps.number_cwins)) {
3761 for (i = tmp->cmaps.number_cwins; i-- > 0; )
3762 tmp->cmaps.cwins[i]->colormap->state = 0;
3763 }
3764
3765 for (i = 0; i < tmp->cmaps.number_cwins; i++) {
3766 j = i - inc;
3767 if (j >= tmp->cmaps.number_cwins)
3768 j -= tmp->cmaps.number_cwins;
3769 else if (j < 0)
3770 j += tmp->cmaps.number_cwins;
3771 cwins[j] = tmp->cmaps.cwins[i];
3772 }
3773
3774 free((char *) tmp->cmaps.cwins);
3775
3776 tmp->cmaps.cwins = cwins;
3777
3778 if (tmp->cmaps.number_cwins > 1)
3779 bzero (tmp->cmaps.scoreboard,
3780 ColormapsScoreboardLength(&tmp->cmaps));
3781
3782 if (previously_installed)
3783 InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
3784 }
3785 } else
3786 FetchWmColormapWindows (tmp);
3787 }
3788
3789
3790
HideIconManager()3791 HideIconManager ()
3792 {
3793 SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
3794 UnmapFrame(Scr->iconmgr.twm_win);
3795 if (Scr->iconmgr.twm_win->icon.w)
3796 UnmapIcon(Scr->iconmgr.twm_win);
3797 Scr->iconmgr.twm_win->mapped = FALSE;
3798 Scr->iconmgr.twm_win->isicon = TRUE;
3799 }
3800
3801
3802
SetBorder(tmp,onoroff)3803 SetBorder (tmp, onoroff)
3804 TwmWindow *tmp;
3805 Bool onoroff;
3806 {
3807 if (tmp->highlight) {
3808 if (onoroff) {
3809 XSetWindowBorder (dpy, tmp->frame, tmp->border);
3810 if (tmp->title_w)
3811 XSetWindowBorder (dpy, tmp->title_w, tmp->border);
3812 } else {
3813 XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
3814 if (tmp->title_w)
3815 XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
3816 }
3817 }
3818 }
3819
3820
3821
DestroyMenu(menu)3822 DestroyMenu (menu)
3823 MenuRoot *menu;
3824 {
3825 MenuItem *item;
3826
3827 if (menu->w) {
3828 XDeleteContext (dpy, menu->w, MenuContext);
3829 XDeleteContext (dpy, menu->w, ScreenContext);
3830 if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
3831 XDestroyWindow(dpy, menu->w);
3832 }
3833
3834 for (item = menu->first; item; ) {
3835 MenuItem *tmp = item;
3836 item = item->next;
3837 free ((char *) tmp);
3838 }
3839 }
3840
3841
3842
3843 /*
3844 * warping routines
3845 */
WarpAlongRing(ev,forward)3846 void WarpAlongRing (ev, forward)
3847 XButtonEvent *ev;
3848 Bool forward;
3849 {
3850 TwmWindow *r, *head;
3851
3852 if (Scr->RingLeader)
3853 head = Scr->RingLeader;
3854 else if (!(head = Scr->Ring))
3855 return;
3856
3857 if (forward) {
3858 for (r = head->ring.next; r != head; r = r->ring.next) {
3859 if (!r || r->mapped) break;
3860 }
3861 } else {
3862 for (r = head->ring.prev; r != head; r = r->ring.prev) {
3863 if (!r || r->mapped) break;
3864 }
3865 }
3866
3867 if (r && r != head) {
3868 TwmWindow *p = Scr->RingLeader, *t;
3869
3870 Scr->RingLeader = r;
3871 WarpToWindow (r);
3872
3873 if (p && p->mapped &&
3874 XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
3875 p == t) {
3876 p->ring.cursor_valid = True;
3877 p->ring.curs_x = ev->x_root - t->frame_x;
3878 p->ring.curs_y = ev->y_root - t->frame_y;
3879 if (p->ring.curs_x < -p->frame_bw ||
3880 p->ring.curs_x >= p->frame_width + p->frame_bw ||
3881 p->ring.curs_y < -p->frame_bw ||
3882 p->ring.curs_y >= p->frame_height + p->frame_bw) {
3883 /* somehow out of window */
3884 p->ring.curs_x = p->frame_width / 2;
3885 p->ring.curs_y = p->frame_height / 2;
3886 }
3887 }
3888 }
3889 }
3890
3891
3892
WarpToWindow(t)3893 void WarpToWindow (t)
3894 TwmWindow *t;
3895 {
3896 int x, y;
3897
3898 /* if we have the virtual desktop, attempt to make the window
3899 * somewhat visible
3900 */
3901 if (Scr->VirtualDesktop)
3902 ScrollToQuadrant(t);
3903
3904 if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
3905 if (t->ring.cursor_valid) {
3906 x = t->ring.curs_x;
3907 y = t->ring.curs_y;
3908 } else {
3909 x = t->frame_width / 2;
3910 y = t->frame_height / 2;
3911 }
3912 XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
3913 }
3914
3915
3916
3917 /*
3918 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
3919 * client messages will have the following form:
3920 *
3921 * event type ClientMessage
3922 * message type _XA_WM_PROTOCOLS
3923 * window tmp->w
3924 * format 32
3925 * data[0] message atom
3926 * data[1] time stamp
3927 */
send_clientmessage(w,a,timestamp)3928 static void send_clientmessage (w, a, timestamp)
3929 Window w;
3930 Atom a;
3931 Time timestamp;
3932 {
3933 XClientMessageEvent ev;
3934
3935 ev.type = ClientMessage;
3936 ev.window = w;
3937 ev.message_type = _XA_WM_PROTOCOLS;
3938 ev.format = 32;
3939 ev.data.l[0] = a;
3940 ev.data.l[1] = timestamp;
3941 XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
3942 }
3943
SendDeleteWindowMessage(tmp,timestamp)3944 SendDeleteWindowMessage (tmp, timestamp)
3945 TwmWindow *tmp;
3946 Time timestamp;
3947 {
3948 send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
3949 }
3950
SendSaveYourselfMessage(tmp,timestamp)3951 SendSaveYourselfMessage (tmp, timestamp)
3952 TwmWindow *tmp;
3953 Time timestamp;
3954 {
3955 send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
3956 }
3957
3958
SendTakeFocusMessage(tmp,timestamp)3959 SendTakeFocusMessage (tmp, timestamp)
3960 TwmWindow *tmp;
3961 Time timestamp;
3962 {
3963 send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
3964 }
3965