1 /****************************************************************************
2  * This module is based on Twm, but has been siginificantly modified
3  * by Rob Nation
4  *
5  * later modified slightly for BowMan
6  * by Bo Yang
7  *
8  * later modified even more slightly for AfterStep
9  * by Frank Fejes
10  ****************************************************************************/
11 /*****************************************************************************/
12 /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
13 /**                          Salt Lake City, Utah                           **/
14 /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
15 /**                        Cambridge, Massachusetts                         **/
16 /**                                                                         **/
17 /**                           All Rights Reserved                           **/
18 /**                                                                         **/
19 /**    Permission to use, copy, modify, and distribute this software and    **/
20 /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
21 /**    granted, provided that the above copyright notice appear  in  all    **/
22 /**    copies and that both  that  copyright  notice  and  this  permis-    **/
23 /**    sion  notice appear in supporting  documentation,  and  that  the    **/
24 /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
25 /**    in publicity pertaining to distribution of the  software  without    **/
26 /**    specific, written prior permission.                                  **/
27 /**                                                                         **/
28 /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
29 /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
30 /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
31 /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
32 /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
33 /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
34 /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
35 /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
36 /*****************************************************************************/
37 /***********************************************************************
38  *
39  * afterstep menu code
40  *
41  ***********************************************************************/
42 
43 #include "../configure.h"
44 
45 #include <stdio.h>
46 #include <signal.h>
47 #include <string.h>
48 #include <ctype.h>
49 #include <unistd.h>
50 #include <limits.h>
51 
52 #include "afterstep.h"
53 #include "menus.h"
54 #include "misc.h"
55 #include "parse.h"
56 #include "screen.h"
57 #include "module.h"
58 
59 #ifndef SHADE_ANIMATION_STEPS
60 #define SHADE_ANIMATION_STEPS 15
61 #endif
62 
63 extern XEvent Event;
64 extern ASWindow *Tmp_win;
65 extern int menuFromFrameOrWindowOrTitlebar;
66 extern DoHandlePageing;
67 
68 extern char **g_argv;
69 
70 /***********************************************************************
71  *
72  *  Procedure:
73  *	ExecuteFunction - execute a afterstep built in function
74  *
75  *  Inputs:
76  *	func	- the function to execute
77  *	action	- the menu action to execute
78  *	w	- the window to execute this function on
79  *	tmp_win	- the afterstep window structure
80  *	event	- the event that caused the function
81  *	context - the context in which the button was pressed
82  *      val1,val2 - the distances to move in a scroll operation
83  *
84  ***********************************************************************/
ExecuteFunction(int func,char * action,Window in_w,ASWindow * tmp_win,XEvent * eventp,unsigned long context,long val1,long val2,int val1_unit,int val2_unit,MenuRoot * menu,int Module)85 void ExecuteFunction(int func,char *action, Window in_w, ASWindow *tmp_win,
86 		     XEvent *eventp, unsigned long context,long val1,long val2,
87 		     int val1_unit, int val2_unit, MenuRoot *menu, int Module)
88 {
89   ASWindow *t,*temp,*tmp=NULL;
90   char *junk, *junkC;
91   unsigned long junkN;
92   int junkD;
93   int x,y;
94   Window w;
95 #ifndef NON_VIRTUAL
96   int delta_x,delta_y;
97 #endif
98   int warp_x=0,warp_y=0;
99 #ifndef NO_PAGER
100   Pixel TextColor,BackColor;
101   Pixmap BackPixmap;
102 #endif
103 
104   /* Defer Execution may wish to alter this value */
105   w = in_w;
106 
107   switch (func)
108     {
109     case F_NOP:
110     case F_TITLE:
111       break;
112 
113     case F_BEEP:
114       XBell(dpy, Scr.screen);
115       break;
116 
117     case F_RESIZE:
118       if (DeferExecution(eventp,&w,&tmp_win,&context, MOVE, ButtonPress))
119 	break;
120 
121       if(tmp_win == NULL)
122 	break;
123       if(check_allowed_function2(func,tmp_win) == 0)
124 	{
125 	  XBell(dpy, Scr.screen);
126 	  break;
127 	}
128       tmp_win->flags &= ~MAXIMIZED;
129       resize_window(w,tmp_win,val1,val2,val1_unit,val2_unit);
130       break;
131 
132     case F_MOVE:
133       if (DeferExecution(eventp,&w,&tmp_win,&context, MOVE,ButtonPress))
134 	break;
135 
136       if(tmp_win == NULL)
137 	break;
138 
139       move_window(eventp,w,tmp_win,context,val1,val2,val1_unit,val2_unit);
140       break;
141 
142 #ifndef NON_VIRTUAL
143     case F_SCROLL:
144       if((val1 > -100000)&&(val1 < 100000))
145 	x=Scr.Vx + val1*val1_unit/100;
146       else
147 	x = Scr.Vx + (val1/1000)*val1_unit/100;
148 
149       if((val2 > -100000)&&(val2 < 100000))
150 	y=Scr.Vy + val2*val2_unit/100;
151       else
152 	y = Scr.Vy + (val2/1000)*val2_unit/100;
153 
154       if(((val1 <= -100000)||(val1 >= 100000))&&(x>Scr.VxMax))
155 	{
156 	  x = 0;
157 	  y += Scr.MyDisplayHeight;
158 	  if(y > Scr.VyMax)
159 	    y=0;
160 	}
161       if(((val1 <= -100000)||(val1 >= 100000))&&(x<0))
162 	{
163 	  x = Scr.VxMax;
164 	  y -= Scr.MyDisplayHeight;
165 	  if(y < 0)
166 	    y=Scr.VyMax;
167 	}
168       if(((val2 <= -100000)||(val2>= 100000))&&(y>Scr.VyMax))
169 	{
170 	  y = 0;
171 	  x += Scr.MyDisplayWidth;
172 	  if(x > Scr.VxMax)
173 	    x=0;
174 	}
175       if(((val2 <= -100000)||(val2>= 100000))&&(y<0))
176 	{
177 	  y = Scr.VyMax;
178 	  x -= Scr.MyDisplayWidth;
179 	  if(x < 0)
180 	    x=Scr.VxMax;
181 	}
182       MoveViewport(x,y,True);
183       break;
184 #endif
185     case F_MOVECURSOR:
186       XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
187 		    &x,&y,&JunkX, &JunkY, &JunkMask);
188 #ifndef NON_VIRTUAL
189       delta_x = 0;
190       delta_y = 0;
191       warp_x = 0;
192       warp_y = 0;
193       if(x >= Scr.MyDisplayWidth -2)
194 	{
195 	  delta_x = Scr.EdgeScrollX;
196 	  warp_x = Scr.EdgeScrollX - 4;
197 	}
198       if(y>= Scr.MyDisplayHeight -2)
199 	{
200 	  delta_y = Scr.EdgeScrollY;
201 	  warp_y = Scr.EdgeScrollY - 4;
202 	}
203       if(x < 2)
204 	{
205 	  delta_x = -Scr.EdgeScrollX;
206 	  warp_x =  -Scr.EdgeScrollX + 4;
207 	}
208       if(y < 2)
209 	{
210 	  delta_y = -Scr.EdgeScrollY;
211 	  warp_y =  -Scr.EdgeScrollY + 4;
212 	}
213       if(Scr.Vx + delta_x < 0)
214 	delta_x = -Scr.Vx;
215       if(Scr.Vy + delta_y < 0)
216 	delta_y = -Scr.Vy;
217       if(Scr.Vx + delta_x > Scr.VxMax)
218 	delta_x = Scr.VxMax - Scr.Vx;
219       if(Scr.Vy + delta_y > Scr.VyMax)
220 	delta_y = Scr.VyMax - Scr.Vy;
221       if((delta_x!=0)||(delta_y!=0))
222 	{
223 	  MoveViewport(Scr.Vx + delta_x,Scr.Vy+delta_y,True);
224 	  XWarpPointer(dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
225 		       Scr.MyDisplayHeight,
226 		       x - warp_x,
227 		       y - warp_y);
228 	}
229 #endif
230       XWarpPointer(dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
231 		   Scr.MyDisplayHeight, x + val1*val1_unit/100-warp_x,
232 		   y+val2*val2_unit/100 - warp_y);
233 
234       break;
235     case F_ICONIFY:
236       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, ButtonRelease))
237 	break;
238 
239       if(tmp_win == NULL)
240 	break;
241       if (tmp_win->flags & ICONIFIED)
242 	{
243 	  if(val1 <=0)
244 	    DeIconify(tmp_win);
245 	}
246       else
247 	{
248 	  if(check_allowed_function2(func,tmp_win) == 0)
249 	    {
250 	      XBell(dpy, Scr.screen);
251 	      break;
252 	    }
253 	  if(val1 >=0)
254 	    {
255 	      if(check_allowed_function2(func,tmp_win) == 0)
256 		{
257 		  XBell(dpy, Scr.screen);
258 		  break;
259 		}
260 	      Iconify(tmp_win,eventp->xbutton.x_root-5,eventp->xbutton.y_root-5);
261 	    }
262 	}
263       break;
264 
265     case F_RAISE:
266       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
267 	break;
268 
269       if(tmp_win)
270 		  RaiseWindow(tmp_win);
271       break;
272 
273    case F_PUTONTOP:
274       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
275         break;
276 
277       if(tmp_win->flags & STAYSONTOP_FLAG)
278           tmp_win->flags &= ~STAYSONTOP_FLAG;
279       else
280            tmp_win->flags |= STAYSONTOP_FLAG;
281       /* put the window to its new place above or below ontop windows */
282       if(tmp_win)
283 	  RaiseWindow(tmp_win);
284       break;
285 
286     case F_LOWER:
287       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, ButtonRelease))
288 	break;
289 
290       if(tmp_win == NULL)
291 	break;
292       LowerWindow(tmp_win);
293 
294       tmp_win->flags &= ~ONTOP;
295       break;
296 
297     case F_DESTROY:
298       if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY, ButtonRelease))
299 	break;
300 
301       if(tmp_win == NULL)
302 	break;
303       if(check_allowed_function2(func,tmp_win) == 0)
304 	{
305 	  XBell(dpy, Scr.screen);
306 	  break;
307 	}
308 #ifndef NO_PAGER
309       /* Dont delete the pager - it crashes the program! */
310       if((tmp_win->w == Scr.Pager_w)||(tmp_win == Scr.ASPager))
311 	break;
312 #endif
313 
314       if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
315 		       &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
316 	Destroy(tmp_win);
317       else
318 	XKillClient(dpy, tmp_win->w);
319       XSync(dpy,0);
320       break;
321 
322     case F_DELETE:
323       if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY,ButtonRelease))
324 	break;
325 
326       if(tmp_win == NULL)
327 	break;
328       if(check_allowed_function2(func,tmp_win) == 0)
329 	{
330 	  XBell(dpy, Scr.screen);
331 	  break;
332 	}
333 
334 #ifndef NO_PAGER
335       /* Dont delete the pager - it crashes the program! */
336       if((tmp_win->w == Scr.Pager_w)||(tmp_win == Scr.ASPager))
337 	break;
338 #endif
339       if (tmp_win->flags & DoesWmDeleteWindow)
340 	{
341 	  send_clientmessage (tmp_win->w, _XA_WM_DELETE_WINDOW, CurrentTime);
342 	  break;
343 	}
344       else
345 	XBell (dpy, Scr.screen);
346       XSync(dpy,0);
347       break;
348 
349     case F_CLOSE:
350       if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY,ButtonRelease))
351 	break;
352 
353       if(tmp_win == NULL)
354 	break;
355       if(check_allowed_function2(func,tmp_win) == 0)
356 	{
357 	  XBell(dpy, Scr.screen);
358 	  break;
359 	}
360 
361 #ifndef NO_PAGER
362       /* Dont delete the pager - it crashes the program! */
363       if((tmp_win->w == Scr.Pager_w)||(tmp_win == Scr.ASPager))
364 	break;
365 #endif
366       if (tmp_win->flags & DoesWmDeleteWindow)
367 	{
368 	  send_clientmessage (tmp_win->w, _XA_WM_DELETE_WINDOW, CurrentTime);
369 	  break;
370 	}
371       else if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
372 			    &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
373 	Destroy(tmp_win);
374       else
375 	XKillClient(dpy, tmp_win->w);
376       XSync(dpy,0);
377       break;
378 
379     case F_RESTART:
380       ClosePipes();
381       ResetShade(tmp);
382       Done(1, action);
383       break;
384 
385     case F_EXEC:
386       XGrabPointer(dpy, Scr.Root, True,
387 		   ButtonPressMask | ButtonReleaseMask,
388 		   GrabModeAsync, GrabModeAsync,
389 		   Scr.Root, Scr.ASCursors[WAIT], CurrentTime);
390       XSync (dpy,0);
391 
392       if (!(fork())) /* child process */
393 	if (execl("/bin/sh", "/bin/sh", "-c", action, (char *)0)==-1)
394 	  exit(100);
395       XUngrabPointer(dpy,CurrentTime);
396       XSync (dpy,0);
397       break;
398 
399     case F_REFRESH:
400       {
401 	XSetWindowAttributes attributes;
402 	unsigned long valuemask;
403 
404 	valuemask = (CWBackPixel);
405 	attributes.background_pixel = Scr.StdColors.fore;
406 	attributes.backing_store = NotUseful;
407 	w = XCreateWindow (dpy, Scr.Root, 0, 0,
408 			   (unsigned int) Scr.MyDisplayWidth,
409 			   (unsigned int) Scr.MyDisplayHeight,
410 			   (unsigned int) 0,
411 			   CopyFromParent, (unsigned int) CopyFromParent,
412 			   (Visual *) CopyFromParent, valuemask,
413 			   &attributes);
414 	XMapWindow (dpy, w);
415 	XDestroyWindow (dpy, w);
416 	XFlush (dpy);
417       }
418       break;
419 
420     case F_STICK:
421       /* stick/unstick a window */
422       if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
423 	break;
424 
425       if(tmp_win == NULL)
426 	break;
427 
428       if(tmp_win->flags & STICKY)
429 	{
430 	  tmp_win->flags &= ~STICKY;
431 	  if(tmp_win->BackPixel == Scr.StickyColors.back)
432 	    {
433 	      tmp_win->ReliefPixel = Scr.StdRelief.fore;
434 	      tmp_win->ShadowPixel = Scr.StdRelief.back;
435 	      tmp_win->BackPixel = Scr.StdColors.back;
436 	    }
437 	  if(tmp_win->TextPixel == Scr.StickyColors.fore)
438 	    tmp_win->TextPixel = Scr.StdColors.fore;
439 	}
440       else
441 	{
442 	  tmp_win->flags |=STICKY;
443 	  if(tmp_win->BackPixel == Scr.StdColors.back)
444 	    {
445 	      tmp_win->BackPixel = Scr.StickyColors.back;
446 	      tmp_win->ShadowPixel = Scr.StickyRelief.back;
447 	      tmp_win->ReliefPixel = Scr.StickyRelief.fore;
448 	    }
449 	  if(tmp_win->TextPixel == Scr.StdColors.fore)
450 	    tmp_win->TextPixel = Scr.StickyColors.fore;
451 	}
452       if(Scr.Hilite != tmp_win)
453 	{
454 	  /* Need to make SetBorder change the window back color */
455 	  temp=Scr.Hilite;
456 	  SetBorder(tmp_win,True,True,True,None);
457 	  SetBorder(tmp_win,False,True,True,None);
458 	  SetBorder(temp,True,True,True,None);
459 	}
460       BroadcastConfig(M_CONFIGURE_WINDOW,tmp_win);
461 #ifndef NO_PAGER
462       MoveResizePagerView(tmp_win);
463 
464       /* Need to re-draw pager_view in case the window
465        * is unsticking */
466       if(Scr.Hilite == tmp_win)
467 	{
468 	  TextColor = Scr.HiColors.fore;
469 	  BackPixmap= Scr.gray_pixmap;
470 	  BackColor = Scr.HiColors.back;
471 	}
472       else
473 	{
474 	  TextColor = Scr.StdColors.fore;
475 	  BackPixmap = Scr.light_gray_pixmap;
476 	  BackColor = Scr.StdColors.back;
477 	}
478       if(Scr.d_depth < 2)
479 	XSetWindowBackgroundPixmap(dpy,tmp_win->pager_view,BackPixmap);
480       else
481 	XSetWindowBackground(dpy,tmp_win->pager_view,BackColor);
482       XClearWindow(dpy,tmp_win->pager_view);
483       if((tmp_win->icon_name != NULL)&&(Scr.PagerFont.height > 0))
484 	{
485 	  NewFontAndColor(Scr.PagerFont.font->fid,TextColor,BackColor);
486 	  XDrawString (dpy, tmp_win->pager_view,Scr.FontGC,2,Scr.PagerFont.y+2,
487 		       tmp_win->icon_name, strlen(tmp_win->icon_name));
488 	}
489 #endif
490       break;
491 
492 #ifndef NON_VIRTUAL
493     case F_GOTO_PAGE:
494       /* back up 1 virtual desktop page */
495       x=val1*Scr.MyDisplayWidth;
496       y=val2*Scr.MyDisplayHeight;
497       MoveViewport(x,y,True);
498       break;
499 #endif
500 #ifndef NON_VIRTUAL
501     case F_TOGGLE_PAGE:
502       if (DoHandlePageing)
503 	{
504 	  DoHandlePageing = 0;
505 	  Broadcast(M_TOGGLE_PAGING,1,0,0,0,0,0,0,0);
506 	}
507       else
508 	{
509 	  DoHandlePageing = 1;
510 	  Broadcast(M_TOGGLE_PAGING,1,1,0,0,0,0,0,0);
511 	}
512       checkPanFrames();
513       break;
514 #endif
515 
516     case F_CIRCULATE_UP:
517       t=Circulate(tmp_win,action,UP);
518       if(t)FocusOn(t,0,True);
519       break;
520 
521     case F_CIRCULATE_DOWN:
522       t=Circulate(tmp_win,action,DOWN);
523       if(t)FocusOn(t,0,True);
524       break;
525 
526     case F_WARP:
527       t=Circulate(tmp_win,action,DOWN);
528       if((t)&&(t->flags & ICONIFIED))
529 	{
530 	  FocusOn(t,0,False);
531 	  DeIconify(t);
532 	}
533       if(t)FocusOn(t,0,True);
534       break;
535 
536     case F_WAIT:
537       {
538 	Bool done = False;
539 	if(val1 == 0)
540 	  val1 = 1;
541 	while(!done)
542 	  {
543 	    if(My_XNextEvent(dpy, &Event))
544 	      {
545 		DispatchEvent ();
546 		if(Event.type == MapNotify)
547 		  {
548 		    if((Tmp_win)&&(matchWildcards(action,Tmp_win->name)==True))
549 		      done = True;
550 		    if((Tmp_win)&&(Tmp_win->class.res_class)&&
551 		       (matchWildcards(action,Tmp_win->class.res_class)==True))
552 		      done = True;
553 		    if((Tmp_win)&&(Tmp_win->class.res_name)&&
554 		       (matchWildcards(action,Tmp_win->class.res_name)==True))
555 		      done = True;
556 		  }
557 	      }
558 	  }
559       }
560       XSync(dpy,0);
561       break;
562     case F_RAISE_IT:
563       if(val1 != 0)
564 	{
565  	  FocusOn((ASWindow *)val1,0,False);
566 	  if (((ASWindow *)(val1))->flags & ICONIFIED)
567 	    {
568 	      DeIconify((ASWindow *)val1);
569 	      FocusOn((ASWindow *)val1,0,False);
570 	    }
571 	}
572 
573       break;
574     case F_FOCUS:
575       if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
576 	break;
577       FocusOn(tmp_win,0,False);
578       break;
579 
580     case F_CHANGE_WINDOWS_DESK:
581       if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
582 	break;
583       if(tmp_win == NULL)
584 	break;
585 
586       changeWindowsDesk(tmp_win,val1);
587       break;
588     case F_DESK:
589       changeDesks(val1,val2);
590       break;
591     case F_MODULE:
592       if(eventp->type != KeyPress)
593 	UngrabEm();
594       if(tmp_win)
595 	executeModule(action, (FILE *)NULL,(char **)tmp_win->w,(int *)context);
596       else
597 	executeModule(action, (FILE *)NULL,(char **)0, (int *)context);
598       /* If we execute a module, don't wait for buttons to come up,
599        * that way, a pop-up menu could be implemented */
600       Module = 0;
601       break;
602 
603     case F_RAISELOWER:
604       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
605 	break;
606       if(tmp_win == NULL)
607 	break;
608 
609       if(tmp_win->flags & VISIBLE) /*|| (tmp_win->flags & MAXIMIZED)) fsf */
610 	{
611 	  tmp_win->flags &= ~ONTOP;
612 	  LowerWindow(tmp_win);
613 	}
614       else
615 	{
616 	  RaiseWindow(tmp_win);
617 	}
618       break;
619 
620     case F_POPUP:
621       ActiveItem = NULL;
622       ActiveMenu = NULL;
623       menuFromFrameOrWindowOrTitlebar = FALSE;
624       do_menu(menu);
625       break;
626 
627      case F_MAXIMIZE:
628       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
629 	break;
630       if(tmp_win == NULL)
631 	break;
632 
633       if(check_allowed_function2(func,tmp_win) == 0)
634 	{
635 	  XBell(dpy, Scr.screen);
636 	  break;
637 	}
638       Maximize(tmp_win,val1,val2,val1_unit,val2_unit);
639       break;
640 
641    case F_SHADE:
642       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
643         break;
644       if(tmp_win == NULL)
645         break;
646 
647       if(check_allowed_function2(func,tmp_win) == 0)
648         {
649           XBell(dpy, Scr.screen);
650           break;
651         }
652       Shade(tmp_win);
653       break;
654 
655     case F_QUIT:
656       Done(0, NULL);
657       break;
658 
659     case F_WINDOWLIST:
660       do_windowList(val1,val2);
661       break;
662 
663     case F_FUNCTION:
664       ComplexFunction(w, tmp_win, eventp, context,menu);
665       break;
666 
667     case F_QUICKIE:
668       QuickRestart();
669       break;
670     case F_SEND_WINDOW_LIST:
671       if(Module >= 0)
672 	{
673 	  SendPacket(Module,M_TOGGLE_PAGING,1,DoHandlePageing,0,0,0,0,0,0);
674 	  SendPacket(Module,M_NEW_DESK,1,Scr.CurrentDesk,0,0,0,0,0,0);
675 	  SendPacket(Module,M_NEW_PAGE,3,Scr.Vx,Scr.Vy,Scr.CurrentDesk,
676 		     0,0,0,0);
677 /*	  if(Scr.Hilite != NULL)
678 	    SendPacket(Module,M_FOCUS_CHANGE,3,Scr.Hilite->w,Scr.Hilite->frame,
679 		       (unsigned long)Scr.Hilite,0,0,0,0);
680 	  else
681 	    SendPacket(Module,M_FOCUS_CHANGE,3,0,0,0,0,0,0,0);
682 */
683 	  for (t = Scr.ASRoot.next; t != NULL; t = t->next)
684 	    {
685 	      SendConfig(Module,M_CONFIGURE_WINDOW,t);
686 	      SendName(Module,M_WINDOW_NAME,t->w,t->frame,
687 		       (unsigned long)t,t->name);
688 	      SendName(Module,M_ICON_NAME,t->w,t->frame,
689 		       (unsigned long)t,t->icon_name);
690 	      SendName(Module,M_RES_CLASS,t->w,t->frame,
691 		       (unsigned long)t,t->class.res_class);
692 	      SendName(Module,M_RES_NAME,t->w,t->frame,
693 		       (unsigned long)t,t->class.res_name);
694 
695 	      if((t->flags & ICONIFIED)&&(!(t->flags & ICON_UNMAPPED)))
696 		SendPacket(Module,M_ICONIFY,7,t->w,t->frame,
697 			   (unsigned long)t,
698 			   t->icon_x_loc,t->icon_y_loc,
699 			   t->icon_p_width,
700 			   t->icon_p_height);
701 	      if((t->flags & ICONIFIED) && (t->flags & ICON_UNMAPPED))
702 		SendPacket(Module,M_ICONIFY,7,t->w,t->frame,
703 			  (unsigned long)t,0,0,0,0);
704 	    }
705 /*	  if(Scr.Hilite == NULL)
706 	    {
707 	      Broadcast(M_FOCUS_CHANGE,3,0,0,0,0,0,0,0);
708 	    }
709 	  else
710 	    {
711 	      Broadcast(M_FOCUS_CHANGE,3,Scr.Hilite->w,
712 			Scr.Hilite->frame,(unsigned long)Scr.Hilite,0,0,0,0);
713 	    }
714 */
715 	  SendPacket(Module,M_END_WINDOWLIST,0,0,0,0,0,0,0,0);
716 	}
717     }
718 
719   /* Only wait for an all-buttons-up condition after calls from
720    * regular built-ins, not from complex-functions or modules. */
721   if(Module == -1)
722     WaitForButtonsUp();
723 
724   return;
725 }
726 
Circulate(ASWindow * tmp_win,char * action,Bool Direction)727 ASWindow *Circulate(ASWindow *tmp_win, char *action,Bool Direction)
728 {
729   ASWindow *t,*selected;
730   long best, worst, high;
731 
732   if (action && (*action == '\0'))  action = NULL;
733 
734   best = LONG_MIN;
735   for (t = Scr.ASRoot.next; t != NULL; t = t->next)
736 	{
737       if ((t->circulate_sequence > best)
738 	  && (t->Desk == Scr.CurrentDesk)
739 	  && ! (t->flags & CIRCULATESKIP)
740 	  && (!(Scr.flags & CirculateSkipIcons) || !(t->flags & ICONIFIED))
741 	  && (t->flags & BORDER))
742 	    {
743 	  best = t->circulate_sequence;
744 	  tmp_win = t;
745 	}
746     }
747   if (tmp_win == NULL)  return NULL;
748 
749   if (Direction == DOWN)
750 		{
751       best = high = LONG_MAX;	/* down: find smallest circulate_sequence */
752       worst = LONG_MIN;
753 		}
754 	      else
755     {
756       best = high = LONG_MIN;	/* up: find largest circulate_sequence */
757       worst = LONG_MAX;
758       tmp_win->circulate_sequence = LONG_MIN;  /* but ignore current */
759 	    }
760   selected = tmp_win;
761   for (t = Scr.ASRoot.next; t != NULL; t = t->next)
762 	    {
763       if (Direction == DOWN)
764 		{
765 	  if (t->circulate_sequence > worst)  worst = t->circulate_sequence;
766 	  if (t->circulate_sequence >= best)  continue;
767 		}
768 	      else
769         {
770 	  if ((t != tmp_win) && (t->circulate_sequence < worst))
771 	      worst = t->circulate_sequence;
772 	  if (t->circulate_sequence <= best)  continue;
773 	    }
774       high = t->circulate_sequence;
775 
776       if ((t->Desk != Scr.CurrentDesk) || (t->flags & CIRCULATESKIP)) continue;
777 
778 	  /* optional skip over icons */
779       if ((t->flags & ICONIFIED) && (Scr.flags & CirculateSkipIcons)) continue;
780       if ( !(t->flags & BORDER))  continue;
781 
782 	  /* Make CirculateUp and CirculateDown take args. by Y.NOMURA */
783       if (action && !matchWildcards(action, t->name)
784 	  && !matchWildcards(action, t->icon_name) && t->class.res_name
785 	  && !matchWildcards(action, t->class.res_name))  continue;
786 
787       best = t->circulate_sequence;
788 	      selected = t;
789 	    }
790 	  if(Direction == DOWN)
791       selected->circulate_sequence = worst + 1;
792 	  else
793 	    {
794       tmp_win->circulate_sequence = worst - 1;
795       selected->circulate_sequence = high + 1;
796     }
797 
798   return selected;
799 }
800 
801 
802 /***********************************************************************
803  *
804  *  Procedure:
805  *	DeferExecution - defer the execution of a function to the
806  *	    next button press if the context is C_ROOT
807  *
808  *  Inputs:
809  *      eventp  - pointer to XEvent to patch up
810  *      w       - pointer to Window to patch up
811  *      tmp_win - pointer to ASWindow Structure to patch up
812  *	context	- the context in which the mouse button was pressed
813  *	func	- the function to defer
814  *	cursor	- the cursor to display while waiting
815  *      finishEvent - ButtonRelease or ButtonPress; tells what kind of event to
816  *                    terminate on.
817  *
818  ***********************************************************************/
DeferExecution(XEvent * eventp,Window * w,ASWindow ** tmp_win,unsigned long * context,int cursor,int FinishEvent)819 int DeferExecution(XEvent *eventp, Window *w,ASWindow **tmp_win,
820 		   unsigned long *context, int cursor, int FinishEvent)
821 
822 {
823   int done;
824   int finished = 0;
825   Window dummy;
826   Window original_w;
827 
828   original_w = *w;
829 
830   if((*context != C_ROOT)&&(*context != C_NO_CONTEXT))
831     {
832       if((FinishEvent == ButtonPress)||((FinishEvent == ButtonRelease) &&
833 					(eventp->type != ButtonPress)))
834 	{
835 	  return FALSE;
836 	}
837     }
838   if(!GrabEm(cursor))
839     {
840       XBell(dpy,Scr.screen);
841       return True;
842     }
843 
844   while (!finished)
845     {
846       done = 0;
847       /* block until there is an event */
848       XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
849 		 ExposureMask | KeyPressMask |
850 		 ButtonMotionMask| PointerMotionMask/* | EnterWindowMask |
851 		 LeaveWindowMask*/, eventp);
852       StashEventTime(eventp);
853 
854       if(eventp->type == KeyPress)
855 	Keyboard_shortcuts(eventp,FinishEvent);
856       if(eventp->type == FinishEvent)
857 	finished = 1;
858       if(eventp->type == ButtonPress)
859 	{
860 	  XAllowEvents(dpy,ReplayPointer,CurrentTime);
861 	  done = 1;
862 	}
863       if(eventp->type == ButtonRelease)
864 	done = 1;
865       if(eventp->type == KeyPress)
866 	done = 1;
867 
868       if(!done)
869 	{
870 	  DispatchEvent();
871 	}
872     }
873 
874   *w = eventp->xany.window;
875   if(((*w == Scr.Root)||(*w == Scr.NoFocusWin))
876       && (eventp->xbutton.subwindow != (Window)0))
877     {
878       *w = eventp->xbutton.subwindow;
879       eventp->xany.window = *w;
880     }
881   if (*w == Scr.Root)
882     {
883       *context = C_ROOT;
884       XBell(dpy,Scr.screen);
885       UngrabEm();
886       return TRUE;
887     }
888   if (XFindContext (dpy, *w, ASContext, (caddr_t *)tmp_win) == XCNOENT)
889     {
890       *tmp_win = NULL;
891       XBell(dpy,Scr.screen);
892       UngrabEm();
893       return (TRUE);
894     }
895 
896   if(*w == (*tmp_win)->Parent)
897     *w = (*tmp_win)->w;
898 
899   if(original_w == (*tmp_win)->Parent)
900     original_w = (*tmp_win)->w;
901 
902   /* this ugly mess attempts to ensure that the release and press
903    * are in the same window. */
904   /* the windows are considered the same if any one of these is found true:
905      - the window IDs are identical
906      - the original window is Scr.Root, None, or NoFocusWin
907      - the original window is the client window and the current window
908        is the frame window
909    */
910 /*  if ((*w != original_w) && (original_w != Scr.Root) &&
911       (original_w != None) && (original_w != Scr.NoFocusWin) &&
912       (*w != (*tmp_win)->frame) && (original_w != (*tmp_win)->w))
913       {
914 	*context = C_ROOT;
915 	XBell(dpy,Scr.screen);
916 	UngrabEm();
917 	return TRUE;
918       }
919       */
920   *context = GetContext(*tmp_win,eventp,&dummy);
921 
922   UngrabEm();
923   return FALSE;
924 }
925 
926 
927 /****************************************************************************
928  *
929  * This is used to tell applications which windows on the screen are
930  * top level appication windows, and which windows are the icon windows
931  * that go with them.
932  *
933  ****************************************************************************/
SetMapStateProp(ASWindow * tmp_win,int state)934 void SetMapStateProp(ASWindow *tmp_win, int state)
935 {
936   unsigned long data[2];		/* "suggested" by ICCCM version 1 */
937 
938   data[0] = (unsigned long) state;
939   data[1] = (unsigned long) tmp_win->icon_pixmap_w;
940 
941   XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
942 		   PropModeReplace, (unsigned char *) data, 2);
943   return;
944 }
945 
946 
947 /***************************************************************************
948  *
949  *  Moves the viewport within thwe virtual desktop
950  *
951  ***************************************************************************/
952 #ifndef NON_VIRTUAL
MoveViewport(int newx,int newy,Bool grab)953 void MoveViewport(int newx, int newy, Bool grab)
954 {
955   ASWindow *t;
956   int deltax,deltay;
957 
958   if(grab)
959     XGrabServer(dpy);
960 
961 
962   if(newx > Scr.VxMax)
963     newx = Scr.VxMax;
964   if(newy > Scr.VyMax)
965     newy = Scr.VyMax;
966   if(newx <0)
967     newx = 0;
968   if(newy <0)
969     newy = 0;
970 
971   deltay = Scr.Vy - newy;
972   deltax = Scr.Vx - newx;
973 
974   Scr.Vx = newx;
975   Scr.Vy = newy;
976   Broadcast(M_NEW_PAGE,3,Scr.Vx,Scr.Vy,Scr.CurrentDesk,0,0,0,0);
977 
978   if((deltax!=0)||(deltay!=0))
979     {
980       for (t = Scr.ASRoot.next; t != NULL; t = t->next)
981 	{
982 	  /* If the window is iconified, and sticky Icons is set,
983 	   * then the window should essentially be sticky */
984 	  if(!((t->flags & ICONIFIED)&&(Scr.flags & StickyIcons)) &&
985 	     (!(t->flags & STICKY)))
986 	    {
987               if(!(Scr.flags & StickyIcons))
988 		{
989 		  t->icon_x_loc += deltax;
990 		  t->icon_y_loc += deltay;
991 		  if(t->icon_pixmap_w != None)
992 		    XMoveWindow(dpy,t->icon_pixmap_w,t->icon_x_loc,
993 				t->icon_y_loc);
994 		  if(!(t->flags &ICON_UNMAPPED))
995 		  Broadcast(M_ICON_LOCATION,7,t->w,t->frame,
996 			    (unsigned long)t,
997 			    t->icon_x_loc,t->icon_y_loc,
998 			    t->icon_p_width,
999 			    t->icon_p_height);
1000 		}
1001 	    }
1002 	  if(!(t->flags & STICKY))
1003 	    SetupFrame (t, t->frame_x+ deltax, t->frame_y + deltay,
1004 			t->frame_width, t->frame_height,FALSE);
1005 	}
1006       for (t = Scr.ASRoot.next; t != NULL; t = t->next)
1007 	{
1008 	  /* If its an icon, and its sticking, autoplace it so
1009 	   * that it doesn't wind up on top a a stationary
1010 	   * icon */
1011 	  if(((t->flags & STICKY)||(Scr.flags & StickyIcons))&&
1012 	     (t->flags & ICONIFIED)&&(!(t->flags & ICON_MOVED))&&
1013 	     (!(t->flags & ICON_UNMAPPED)))
1014 	    AutoPlace(t);
1015 	}
1016 
1017     }
1018   /* fix up the viewport indicator */
1019   MoveResizeViewPortIndicator();
1020 #ifndef NON_VIRTUAL
1021   checkPanFrames();
1022 
1023   /* do this with PanFrames too ??? HEDU */
1024   while(XCheckTypedEvent(dpy,MotionNotify,&Event))
1025     StashEventTime(&Event);
1026 #endif
1027   UpdateVisibility();
1028   if(grab)
1029     XUngrabServer(dpy);
1030 }
1031 #endif
1032 
1033 
1034 /**************************************************************************
1035  *
1036  * Moves focus to specified window
1037  *
1038  *************************************************************************/
FocusOn(ASWindow * t,int DeIconifyOnly,Bool circulating)1039 void FocusOn(ASWindow *t,int DeIconifyOnly, Bool circulating)
1040 {
1041 #ifndef NON_VIRTUAL
1042   int dx,dy;
1043   int cx,cy;
1044 #endif
1045   int x,y;
1046 
1047   if(t == (ASWindow *)0)
1048     return;
1049 
1050   if(t->Desk != Scr.CurrentDesk)
1051     {
1052       changeDesks(0,t->Desk);
1053     }
1054 
1055 #ifndef NON_VIRTUAL
1056   if(t->flags & ICONIFIED)
1057     {
1058       cx = t->icon_x_loc + t->icon_p_width/2;
1059       cy = t->icon_y_loc + t->icon_p_height/2;
1060     }
1061   else
1062     {
1063       cx = t->frame_x + t->frame_width/2;
1064       cy = t->frame_y + t->frame_height/2;
1065     }
1066 
1067   /* Put center of window on the visible screen */
1068   if((!DeIconifyOnly)&&(Scr.flags & CenterOnCirculate))
1069     {
1070       dx = cx - Scr.MyDisplayWidth/2 + Scr.Vx;
1071       dy = cy - Scr.MyDisplayHeight/2 + Scr.Vy;
1072     }
1073   else
1074     {
1075       dx = (cx + Scr.Vx)/Scr.MyDisplayWidth*Scr.MyDisplayWidth;
1076       dy = (cy +Scr.Vy)/Scr.MyDisplayHeight*Scr.MyDisplayHeight;
1077     }
1078   MoveViewport(dx,dy,True);
1079 #endif
1080 
1081   if(t->flags & ICONIFIED)
1082     {
1083       x = t->icon_x_loc + t->icon_p_width/2;
1084       y = t->icon_y_loc + t->icon_p_height/2;
1085     }
1086   else
1087     {
1088       x = t->frame_x;
1089       y = t->frame_y;
1090     }
1091   if(!(Scr.flags & ClickToFocus))
1092     XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, x+2,y+2);
1093   RaiseWindow(t);
1094 
1095   /* If the window is still not visible, make it visible! */
1096   if(((t->frame_x + t->frame_width)< 0)||(t->frame_y + t->frame_height < 0)||
1097      (t->frame_x >Scr.MyDisplayWidth)||(t->frame_y>Scr.MyDisplayHeight))
1098     {
1099       SetupFrame(t,0,0,t->frame_width, t->frame_height,False);
1100       if(!(Scr.flags & ClickToFocus))
1101 	XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, 2,2);
1102     }
1103   UngrabEm();
1104   SetFocus(t->w,t,circulating);
1105 }
1106 
1107 
1108 
1109 /***********************************************************************
1110  *
1111  *  Procedure:
1112  *	(Un)Maximize a window.
1113  *
1114  ***********************************************************************/
Maximize(ASWindow * tmp_win,int val1,int val2,int val1_unit,int val2_unit)1115 void Maximize(ASWindow *tmp_win,int val1,int val2,
1116 	      int val1_unit,int val2_unit)
1117 {
1118   int new_width, new_height,new_x,new_y;
1119 
1120   if (tmp_win->flags & MAXIMIZED)
1121     {
1122       tmp_win->flags &= ~MAXIMIZED;
1123       SetupFrame(tmp_win, tmp_win->orig_x, tmp_win->orig_y, tmp_win->orig_wd,
1124 		 tmp_win->orig_ht,TRUE);
1125       SetBorder(tmp_win,True,True,True,None);
1126     }
1127   else
1128     {
1129       new_width = tmp_win->frame_width;
1130       new_height = tmp_win->frame_height;
1131       new_x = tmp_win->frame_x;
1132       new_y = tmp_win->frame_y;
1133       if(val1 >0)
1134 	{
1135 	  new_width = val1*val1_unit/100-2;
1136 	  new_x = 0;
1137 	}
1138       if(val2 >0)
1139 	{
1140 	  new_height = val2*val2_unit/100-2;
1141 	  new_y = 0;
1142 	}
1143       if((val1==0)&&(val2==0))
1144 	{
1145 	  new_x = 0;
1146 	  new_y = 0;
1147 	  new_height = Scr.MyDisplayHeight-2;
1148 	  new_width = Scr.MyDisplayWidth-2;
1149 	}
1150       tmp_win->flags |= MAXIMIZED;
1151       ConstrainSize (tmp_win, &new_width, &new_height);
1152       SetupFrame(tmp_win,new_x,new_y,new_width,new_height,TRUE);
1153       SetBorder(tmp_win,True,True,True,tmp_win->right_w[0]);
1154     }
1155 #ifndef NO_PAGER
1156   RedrawPager();
1157 #endif
1158   UpdateVisibility();
1159   /*  UpdateVisibility(); */
1160 }
1161 
1162 /***********************************************************************
1163  *
1164  *  Procedure:
1165  *      (Un)Shade a window.
1166  *
1167  ***********************************************************************/
1168 #ifdef notdef
Shade(ASWindow * tmp_win)1169 void Shade(ASWindow *tmp_win)
1170 {
1171   int new_width, new_height;
1172 
1173   if ( tmp_win == NULL )
1174      return;
1175 
1176   if (tmp_win->wmhints)
1177       tmp_win->wmhints->flags |= StateHint;
1178 
1179   if ((tmp_win->wmhints && tmp_win->wmhints->initial_state == ZoomState)
1180       || (!tmp_win->wmhints && (tmp_win->flags & MAXIMIZED)))
1181     {
1182       tmp_win->flags &= ~MAXIMIZED;
1183       if (tmp_win->wmhints)
1184 	  tmp_win->wmhints->initial_state = NormalState;
1185       SetupFrame(tmp_win, tmp_win->frame_x, tmp_win->frame_y, tmp_win->orig_wd,
1186                  tmp_win->orig_ht,TRUE);
1187       SetBorder(tmp_win,True,True,True,None);
1188       Broadcast(M_UNSHADE,3,tmp_win->w,tmp_win->frame,(unsigned long)tmp_win,
1189 		0,0,0,0);
1190     }
1191   else
1192     {
1193       new_width = tmp_win->frame_width;
1194       new_height = 21;
1195       tmp_win->flags |= MAXIMIZED;
1196       if (tmp_win->wmhints)
1197 	  tmp_win->wmhints->initial_state = ZoomState;
1198 
1199       SetupFrame(tmp_win,tmp_win->frame_x,tmp_win->frame_y,new_width,
1200 	         new_height,TRUE);
1201       Broadcast(M_SHADE,3,tmp_win->w,tmp_win->frame,(unsigned long)tmp_win,
1202 		0,0,0,0);
1203     }
1204 #ifndef NO_PAGER
1205   RedrawPager();
1206 #endif
1207 }
1208 #endif /* notdef */
1209 
Shade(ASWindow * tmp_win)1210 void Shade(ASWindow *tmp_win)
1211 {
1212   int new_width, new_height;
1213   XWindowAttributes winattrs;
1214   unsigned long eventMask;
1215 #ifdef SHADE_ANIMATION
1216   int y, s, w, h;
1217 #endif
1218 
1219 
1220   if ( tmp_win == NULL )
1221      return;
1222 
1223   if (tmp_win->flags & SHADED)
1224     {
1225 	/* unshade window */
1226 	tmp_win->flags |= MAPPED;
1227 	XMapWindow(dpy, tmp_win->w);
1228 	SetMapStateProp(tmp_win, NormalState);
1229 #ifdef SHADE_ANIMATION
1230 	/* do the shading animation */
1231 	XMoveWindow(dpy, tmp_win->title_height, 0, -(tmp_win->frame_height-
1232 						     tmp_win->title_height));
1233 	h = tmp_win->title_height;
1234 	y = tmp_win->frame_height;
1235 	s = y/SHADE_ANIMATION_STEPS;
1236 	w = tmp_win->frame_width;
1237 	y = -(tmp_win->frame_height-tmp_win->title_height);
1238 	while (h<tmp_win->frame_height-tmp_win->title_height) {
1239 	    XResizeWindow(dpy, tmp_win->frame, w, h);
1240 	    XMoveWindow(dpy, tmp_win->w, 0, y);
1241 	    XSync(dpy, 0);
1242 	    h+=s;
1243 	    y+=s;
1244 	}
1245 	XMoveWindow(dpy, tmp_win->w, 0, 0);
1246 #endif /* SHADE_ANIMATION */
1247         XResizeWindow(dpy, tmp_win->frame, tmp_win->frame_width,
1248 		     tmp_win->frame_height);
1249 	if((Scr.flags & StubbornIcons)||(Scr.flags & ClickToFocus))
1250 	  FocusOn(tmp_win,1,True);
1251 	tmp_win->flags &= ~SHADED;
1252 	Broadcast(M_UNSHADE,3,tmp_win->w,tmp_win->frame,(unsigned long)tmp_win,
1253 		  0,0,0,0);
1254     }
1255   else
1256     {
1257       tmp_win->flags |= SHADED;
1258 
1259 	/* can't shade a window with no titlebar */
1260 	if ((!tmp_win->flags) & TITLE) return;
1261 
1262 #ifdef SHADE_ANIMATION
1263 	XLowerWindow(dpy, tmp_win->w);
1264 	h = tmp_win->frame_height;
1265 	s = h/SHADE_ANIMATION_STEPS;
1266 	w = tmp_win->frame_width;
1267 	y = tmp_win->title_height;
1268 
1269 	while (h>tmp_win->title_height) {
1270 	    XMoveWindow(dpy, tmp_win->w, 0, y);
1271 	    XResizeWindow(dpy, tmp_win->frame, w, h);
1272 	    XSync(dpy, 0);
1273 	    h-=s;
1274 	    y-=s;
1275 	}
1276 	XMoveWindow(dpy, tmp_win->w, 0, 0);
1277 #endif	/* SHADE_ANIMATION */
1278       XResizeWindow(dpy, tmp_win->frame, tmp_win->frame_width,
1279 		    tmp_win->title_height);
1280       XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
1281       eventMask = winattrs.your_event_mask;
1282 
1283 	/*
1284 	 * Prevent the receipt of an UnmapNotify, since that would
1285 	 * cause a transition to the Withdrawn state.
1286 	 */
1287 	tmp_win->flags &= ~MAPPED;
1288 	XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
1289 	XUnmapWindow(dpy, tmp_win->w);
1290 	XSelectInput(dpy, tmp_win->w, eventMask);
1291 
1292 	SetMapStateProp(tmp_win, IconicState);
1293       Broadcast(M_SHADE,3,tmp_win->w,tmp_win->frame,(unsigned long)tmp_win,
1294 		0,0,0,0);
1295     }
1296 #ifndef NO_PAGER
1297   RedrawPager();
1298 #endif
1299   UpdateVisibility();
1300 
1301 }
1302 
1303 
1304 
1305 /****************************************************************************
1306  *
1307  * Reset Shaded Windows on restart
1308  * Trying to fix a problem with afterstep crashing on some systems during
1309  * restart.
1310  *
1311  ***************************************************************************/
ResetShade(ASWindow * tw)1312 void ResetShade(ASWindow *tw)
1313 {
1314   for (tw = Scr.ASRoot.next; tw != NULL; tw = tw->next)
1315    {
1316      /*     if(tw->flags & MAXIMIZED && tw->wmhints && tw->wmhints->initial_state == ZoomState) */
1317       if (tw->flags & SHADED && tw->wmhints && tw->wmhints->initial_state == ZoomState)
1318       {
1319         Shade(tw);
1320       }
1321    }
1322 }
1323 
1324 
1325 /*****************************************************************************
1326  *
1327  * Grab the pointer and keyboard
1328  *
1329  ****************************************************************************/
GrabEm(int cursor)1330 Bool GrabEm(int cursor)
1331 {
1332   int i=0,val=0;
1333   unsigned int mask;
1334 
1335   XSync(dpy,0);
1336   /* move the keyboard focus prior to grabbing the pointer to
1337    * eliminate the enterNotify and exitNotify events that go
1338    * to the windows */
1339   if(Scr.PreviousFocus == NULL)
1340     Scr.PreviousFocus = Scr.Focus;
1341   SetFocus(Scr.NoFocusWin,NULL,False);
1342   mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask
1343     | EnterWindowMask | LeaveWindowMask;
1344   while((i<1000)&&(val=XGrabPointer(dpy, Scr.Root, True, mask,
1345 				    GrabModeAsync, GrabModeAsync, Scr.Root,
1346 				    Scr.ASCursors[cursor], CurrentTime)!=
1347 		   GrabSuccess))
1348     {
1349       i++;
1350       /* If you go too fast, other windows may not get a change to release
1351        * any grab that they have. */
1352       sleep_a_little(1000);
1353     }
1354 
1355   /* If we fall out of the loop without grabbing the pointer, its
1356      time to give up */
1357   XSync(dpy,0);
1358   if(val!=GrabSuccess)
1359     {
1360       return False;
1361     }
1362   return True;
1363 }
1364 
1365 
1366 /*****************************************************************************
1367  *
1368  * UnGrab the pointer and keyboard
1369  *
1370  ****************************************************************************/
UngrabEm()1371 void UngrabEm()
1372 {
1373   Window w;
1374 
1375   XSync(dpy,0);
1376   XUngrabPointer(dpy,CurrentTime);
1377 
1378   if(Scr.PreviousFocus != NULL)
1379     {
1380       w = Scr.PreviousFocus->w;
1381 
1382       /* if the window still exists, focus on it */
1383       if (w)
1384 	{
1385 	  SetFocus(w,Scr.PreviousFocus,True);
1386 	}
1387       Scr.PreviousFocus = NULL;
1388     }
1389   XSync(dpy,0);
1390 }
1391 
1392 
1393 /*****************************************************************************
1394  *
1395  * Waits Scr.ClickTime, or until it is evident that the user is not
1396  * clicking, but is moving the cursor
1397  *
1398  ****************************************************************************/
IsClick(int x,int y,unsigned EndMask,XEvent * d)1399 Bool IsClick(int x,int y,unsigned EndMask, XEvent *d)
1400 {
1401   int xcurrent,ycurrent,total = 0;
1402 
1403   xcurrent = x;
1404   ycurrent = y;
1405   while((total < Scr.ClickTime)&&
1406 	(x - xcurrent < 5)&&(x - xcurrent > -5)&&
1407 	(y - ycurrent < 5)&&(y - ycurrent > -5))
1408     {
1409       sleep_a_little(10000);
1410       total+=10;
1411       if(XCheckMaskEvent (dpy,EndMask, d))
1412 	{
1413 	  StashEventTime(d);
1414 	  return True;
1415 	}
1416       if(XCheckMaskEvent (dpy,ButtonMotionMask|PointerMotionMask, d))
1417 	{
1418 	  xcurrent = d->xmotion.x_root;
1419 	  ycurrent = d->xmotion.y_root;
1420 	  StashEventTime(d);
1421 	}
1422     }
1423   return False;
1424 }
1425 
1426 /*****************************************************************************
1427  *
1428  * Builtin which determines if the button press was a click or double click...
1429  *
1430  ****************************************************************************/
ComplexFunction(Window w,ASWindow * tmp_win,XEvent * eventp,unsigned long context,MenuRoot * mr)1431 void ComplexFunction(Window w, ASWindow *tmp_win, XEvent *eventp,
1432 		     unsigned long context, MenuRoot *mr)
1433 {
1434   char type = MOTION;
1435   char c;
1436   XEvent *ev;
1437   MenuItem *mi;
1438   XEvent d;
1439   Bool Persist = False;
1440   Bool HaveDoubleClick = False;
1441   Bool HaveTripleClick = False;
1442   Bool NeedsTarget = False;
1443   int x, y ;
1444 
1445   if(mr == NULL)
1446     return;
1447 
1448   /* These built-ins require a selected window
1449    * The function code is >= 100 and < 1000
1450    * F_RESIZE
1451    * F_MOVE
1452    * F_ICONIFY
1453    * F_RAISE
1454    * F_LOWER
1455    * F_DESTROY
1456    * F_DELETE
1457    * F_STICK
1458    * F_RAISELOWER
1459    * F_MAXIMIZE
1460    * F_SHADE
1461    * F_PUTONTOP
1462    * F_FOCUS
1463    *
1464    * These do not:
1465    * The function code is < 100
1466    * F_NOP
1467    * F_TITLE
1468    * F_BEEP
1469    * F_SCROLL
1470    * F_MOVECURSOR
1471    * F_RESTART
1472    * F_EXEC
1473    * F_REFRESH
1474    * F_GOTO_PAGE
1475    * F_TOGGLE_PAGE
1476    * F_CIRCULATE_UP
1477    * F_CIRCULATE_DOWN
1478    * F_WARP
1479    * F_DESK
1480    * F_MODULE
1481    * F_POPUP
1482    * F_QUIT
1483    * F_WINDOWLIST
1484    * F_FUNCTION
1485    * F_SEND_WINDOW_LIST
1486    */
1487 
1488   mi = mr->first;
1489   while(mi != NULL)
1490     {
1491       /* make lower case */
1492       c = *(mi->item);
1493       if((mi->func >= 100)&&(mi->func < 1000))
1494 	NeedsTarget = True;
1495       if(isupper(c))
1496 	c=tolower(c);
1497       if(c==DOUBLE_CLICK)
1498 	HaveDoubleClick = True;
1499       if(c==TRIPLE_CLICK)
1500         HaveTripleClick = True;
1501       else if(c == IMMEDIATE)
1502 	{
1503 	  if(tmp_win)
1504 	    w = tmp_win->frame;
1505 	  else
1506 	    w = None;
1507 	  ExecuteFunction(mi->func, mi->action,w,
1508 			  tmp_win, eventp, context,mi->val1,mi->val2,
1509 			  mi->val1_unit,mi->val2_unit,
1510 			  mi->menu,-1);
1511 	}
1512       else
1513 	Persist = True;
1514       mi = mi->next;
1515     }
1516 
1517   if(!Persist)
1518     return;
1519 
1520   /* Only defer execution if there is a possibility of needing
1521    * a window to operate on */
1522   if(NeedsTarget)
1523     {
1524       if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonPress))
1525 	{
1526 	  WaitForButtonsUp();
1527 	  return;
1528 	}
1529     }
1530 
1531   if(!GrabEm(SELECT))
1532     {
1533       XBell(dpy,Scr.screen);
1534       return;
1535     }
1536   XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
1537 		&x,&y,&JunkX, &JunkY, &JunkMask);
1538 
1539   /* A window has already been selected */
1540   ev = eventp;
1541 
1542   /* Wait and see if we have a click, or a move */
1543   /* wait 100 msec, see if the user releases the button */
1544   if(IsClick(x,y,ButtonReleaseMask,&d))
1545     {
1546       type = CLICK;
1547       ev = &d;
1548     }
1549 
1550   /* If it was a click, wait to see if its a double click */
1551   if((HaveDoubleClick) && (type == CLICK) &&
1552      (IsClick(x,y,ButtonPressMask, &d)))
1553     {
1554       type = ONE_AND_A_HALF_CLICKS;
1555       ev = &d;
1556     }
1557   if((HaveDoubleClick) && (type == ONE_AND_A_HALF_CLICKS) &&
1558      (IsClick(x,y,ButtonReleaseMask, &d)))
1559     {
1560       type = DOUBLE_CLICK;
1561       ev = &d;
1562     }
1563   if((HaveTripleClick) && (type == DOUBLE_CLICK) &&
1564      (IsClick(x,y,ButtonPressMask, &d)))
1565     {
1566       type = TWO_AND_A_HALF_CLICKS;
1567       ev = &d;
1568     }
1569   if((HaveTripleClick) && (type == TWO_AND_A_HALF_CLICKS) &&
1570      (IsClick(x,y,ButtonReleaseMask, &d)))
1571     {
1572       type = TRIPLE_CLICK;
1573       ev = &d;
1574     }
1575 
1576   /* some functions operate on button release instead of
1577    * presses. These gets really weird for complex functions ... */
1578   if(eventp->type == ButtonPress)
1579     eventp->type = ButtonRelease;
1580 
1581   mi = mr->first;
1582   while(mi != NULL)
1583     {
1584       /* make lower case */
1585       c = *(mi->item);
1586       if(isupper(c))
1587 	c=tolower(c);
1588       if(c == type)
1589 	{
1590 	  if(tmp_win)
1591 	    w = tmp_win->frame;
1592 	  else
1593 	    w = None;
1594 	  ExecuteFunction(mi->func, mi->action,w,
1595 			  tmp_win, eventp, context,
1596 			  mi->val1,mi->val2,
1597 			  mi->val1_unit,mi->val2_unit,mi->menu,-2);
1598 	}
1599       mi = mi->next;
1600     }
1601   WaitForButtonsUp();
1602   UngrabEm();
1603 }
1604 
1605 
1606 /* For Ultrix 4.2 */
1607 #include <sys/types.h>
1608 #include <sys/time.h>
1609 
1610 
1611 /**************************************************************************
1612  *
1613  * Move to a new desktop
1614  *
1615  *************************************************************************/
changeDesks(int val1,int val2)1616 void changeDesks(int val1,int val2)
1617 {
1618   int oldDesk;
1619   ASWindow *t;
1620   ASWindow *FocusWin = 0;
1621   static ASWindow *StickyWin = 0;
1622 
1623   oldDesk = Scr.CurrentDesk;
1624 
1625   if(val1 != 0)
1626     {
1627       Scr.CurrentDesk = Scr.CurrentDesk + val1;
1628     }
1629   else
1630     {
1631       Scr.CurrentDesk = val2;
1632       if(Scr.CurrentDesk == oldDesk)
1633 	return;
1634     }
1635 
1636   Broadcast(M_NEW_DESK,1,Scr.CurrentDesk,0,0,0,0,0,0);
1637   /* Scan the window list, mapping windows on the new Desk,
1638    * unmapping windows on the old Desk */
1639   XGrabServer(dpy);
1640   for (t = Scr.ASRoot.next; t != NULL; t = t->next)
1641     {
1642       /* Only change mapping for non-sticky windows */
1643       if(!((t->flags & ICONIFIED)&&(Scr.flags & StickyIcons)) &&
1644 	 (!(t->flags & STICKY))&&(!(t->flags & ICON_UNMAPPED)))
1645 	{
1646 	  if(t->Desk == oldDesk) {
1647 	    if (Scr.Focus == t)
1648 		t->FocusDesk = oldDesk;
1649 	    else
1650 		t->FocusDesk = -1;
1651 	    UnmapIt(t);
1652 	  } else if(t->Desk == Scr.CurrentDesk) {
1653 	    MapIt(t);
1654 	    if (t->FocusDesk == Scr.CurrentDesk) {
1655 		FocusWin = t;
1656 	    }
1657       }
1658 	}
1659       else
1660 	{
1661 	  /* Window is sticky */
1662 	  t->Desk = Scr.CurrentDesk;
1663 	  if (Scr.Focus == t) {
1664 	    t->FocusDesk = oldDesk;
1665 	    StickyWin = t;
1666 	  }
1667 	}
1668     }
1669   XUngrabServer(dpy);
1670   for (t = Scr.ASRoot.next; t != NULL; t = t->next)
1671     {
1672       /* If its an icon, and its sticking, autoplace it so
1673        * that it doesn't wind up on top a a stationary
1674        * icon */
1675       if(((t->flags & STICKY)||(Scr.flags & StickyIcons))&&
1676 	 (t->flags & ICONIFIED)&&(!(t->flags & ICON_MOVED))&&
1677 	 (!(t->flags & ICON_UNMAPPED)))
1678 	AutoPlace(t);
1679     }
1680   /* Better re-draw the pager now */
1681   RedrawPager();
1682 
1683   if(Scr.flags & ClickToFocus) {
1684 #ifndef NO_REMEMBER_FOCUS
1685     if (FocusWin)
1686 	SetFocus(FocusWin->w, FocusWin, False);
1687     else if (StickyWin && (StickyWin->flags && STICKY))
1688 	SetFocus(StickyWin->w, StickyWin, False);
1689     else
1690 #endif
1691 	SetFocus(Scr.NoFocusWin, NULL, False);
1692   }
1693   CorrectStackOrder();
1694 }
1695 
1696 
1697 
1698 /**************************************************************************
1699  *
1700  * Move to a new desktop
1701  *
1702  *************************************************************************/
changeWindowsDesk(ASWindow * t,int val1)1703 void changeWindowsDesk(ASWindow *t,int val1)
1704 {
1705   if(val1 == t->Desk)
1706     return;
1707 
1708   /* Scan the window list, mapping windows on the new Desk,
1709    * unmapping windows on the old Desk */
1710   /* Only change mapping for non-sticky windows */
1711   if(!((t->flags & ICONIFIED)&&(Scr.flags & StickyIcons)) &&
1712      (!(t->flags & STICKY))&&(!(t->flags & ICON_UNMAPPED)))
1713     {
1714       if(t->Desk == Scr.CurrentDesk)
1715 	{
1716 	  t->Desk = val1;
1717 	  UnmapIt(t);
1718 	}
1719       else if(val1 == Scr.CurrentDesk)
1720 	{
1721 	  t->Desk = val1;
1722 	  /* If its an icon, auto-place it */
1723 	  if(t->flags & ICONIFIED)
1724 	    AutoPlace(t);
1725 	  MapIt(t);
1726 	}
1727       else
1728 	t->Desk = val1;
1729 
1730     }
1731   /* Better re-draw the pager now */
1732   BroadcastConfig(M_CONFIGURE_WINDOW,t);
1733   RedrawPager();
1734   CorrectStackOrder();
1735 }
1736 
1737 
1738 /**************************************************************************
1739  *
1740  * Unmaps a window on transition to a new desktop
1741  *
1742  *************************************************************************/
UnmapIt(ASWindow * t)1743 void UnmapIt(ASWindow *t)
1744 {
1745   XWindowAttributes winattrs;
1746   unsigned long eventMask;
1747   /*
1748    * Prevent the receipt of an UnmapNotify, since that would
1749    * cause a transition to the Withdrawn state.
1750    */
1751   XGetWindowAttributes(dpy, t->w, &winattrs);
1752   eventMask = winattrs.your_event_mask;
1753   XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
1754   if(t->flags & ICONIFIED)
1755     {
1756       if(t->icon_pixmap_w != None)
1757 	XUnmapWindow(dpy,t->icon_pixmap_w);
1758     }
1759   else if(t->flags & (MAPPED|MAP_PENDING))
1760     {
1761       XUnmapWindow(dpy,t->frame);
1762     }
1763   XSelectInput(dpy, t->w, eventMask);
1764   MoveResizePagerView(t);
1765 }
1766 
1767 /**************************************************************************
1768  *
1769  * Maps a window on transition to a new desktop
1770  *
1771  *************************************************************************/
MapIt(ASWindow * t)1772 void MapIt(ASWindow *t)
1773 {
1774   if(t->flags & ICONIFIED)
1775     {
1776       if(t->icon_pixmap_w != None)
1777 	XMapWindow(dpy,t->icon_pixmap_w);
1778     }
1779   else if(t->flags & MAPPED)
1780     {
1781       XMapWindow(dpy,t->frame);
1782       t->flags |= MAP_PENDING;
1783       XMapWindow(dpy, t->Parent);
1784    }
1785   MoveResizePagerView(t);
1786 }
1787 
1788 extern void InitVariables(void);
1789 
QuickRestart(void)1790 void QuickRestart(void)
1791 {
1792 #ifdef M4
1793   extern char *m4_options;
1794 #endif
1795   extern char *display_name;
1796   int i;
1797   ASWindow *tmp,*next;
1798   extern unsigned PopupCount;
1799   extern int have_the_colors;
1800   MenuRoot *PopupTable[MAXPOPUPS];
1801   extern MenuRoot *ActiveMenu;
1802   extern MenuItem *ActiveItem;
1803   extern int menu_on;
1804   XEvent event;
1805 
1806   PopDownMenu();
1807   PopDownMenu();
1808   UngrabEm();
1809   InstallWindowColormaps (&Scr.ASRoot);	/* force reinstall */
1810 
1811   ClosePipes();
1812 
1813   Reborder();
1814   tmp = Scr.ASRoot.next;
1815   while (tmp != NULL)
1816     {
1817       next = tmp->next;
1818       Destroy(tmp);
1819       tmp = next;
1820     }
1821   XSync(dpy,0);
1822   for(i=0;i<PopupCount;i++)
1823     {
1824 /* The next line was commented out...readded 08/12/96 */
1825       free(PopupTable[i]);
1826       PopupTable[i] = NULL;
1827     }
1828 
1829   PopupCount = 0;
1830   ActiveMenu = NULL;
1831   ActiveItem = NULL;
1832   menu_on = 0;
1833   have_the_colors = 0;
1834 
1835   InitVariables();
1836 
1837 #ifdef M4
1838   MakeMenus(display_name, m4_options);
1839 #else
1840   MakeMenus(display_name, NULL);
1841 #endif
1842 #ifndef NON_VIRTUAL
1843   XUnmapWindow(dpy,Scr.PanFrameLeft.win);
1844   XUnmapWindow (dpy,Scr.PanFrameRight.win);
1845   XUnmapWindow (dpy,Scr.PanFrameBottom.win);
1846   XUnmapWindow(dpy,Scr.PanFrameTop.win);
1847   Scr.PanFrameBottom.isMapped=
1848     Scr.PanFrameTop.isMapped=
1849       Scr.PanFrameLeft.isMapped=
1850 	Scr.PanFrameRight.isMapped=
1851 	  False;
1852 #endif
1853   while(XPending(dpy))
1854     XNextEvent(dpy,&event);
1855 
1856   CaptureAllWindows();
1857 #ifndef NON_VIRTUAL
1858   checkPanFrames();
1859 #endif
1860   HandleEvents();
1861 
1862 }
1863