Subject: FvwmButtons Patch: animated menu only

From: Jui-Hsuan Joshua Feng <[email-masked]>
Date: Wed, 11 Feb 1998 23:13:12 -0600

Hi,

This is for the animated menu feature only (fixed version).
If you have any comments or suggestions, please let me know.

-- 
Jui-Hsuan Joshua Feng                         (O)608/262-3640 
Electrical & Computer Engr, University of Wisconsin - Madison    
http://www.cae.wisc.edu/~fengj           [email-masked]
diff -u -b -B old/fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.c fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.c
--- old/fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.c	Thu Jun 26 16:32:31 1997
+++ fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.c	Wed Feb 11 23:05:02 1998
@@ -100,6 +100,9 @@
 
 void DebugEvents(XEvent*);
 
+panel_info *seekpanel(button_info *);
+void Slide(panel_info *, button_info *);
+
 /* -------------------------------- globals ---------------------------------*/
 
 Display *Dpy;
@@ -136,6 +139,9 @@
 
 button_info *UberButton=NULL;
 
+panel_info *MainPanel = NULL, *CurrentPanel = NULL, *PanelIndex;
+int dpw, dph;
+
 /* ------------------------------ Misc functions ----------------------------*/
 
 #ifdef DEBUG
@@ -485,11 +491,26 @@
   UberButton->BHeight=1;
   MakeContainer(UberButton);
 
+  dpw = DisplayWidth(Dpy,screen);
+  dph = DisplayHeight(Dpy,screen);
+
 # ifdef DEBUG_INIT
   fprintf(stderr,"%s: Parsing...",MyName);
 # endif
 
+  CurrentPanel = MainPanel
+               = (panel_info *) mymalloc(sizeof(panel_info));
+  MainPanel->next = NULL;
+  MainPanel->uber = UberButton;
+  UberButton->title   = MyName;
+  UberButton->swallow = 1; /* the panel is shown */
+
   ParseOptions(UberButton);
+
+  CurrentPanel = MainPanel; /* reassign CurrentPanel */
+  while (CurrentPanel)
+  { UberButton = CurrentPanel->uber;
+
   if(UberButton->c->num_buttons==0)
     {
       fprintf(stderr,"%s: No buttons defined. Quitting\n", MyName);
@@ -518,6 +539,10 @@
 
   CreateWindow(UberButton,maxx,maxy);
 
+    CurrentPanel->uber->IconWinParent = MyWindow;
+    CurrentPanel->uber->icon_w = maxx;
+    CurrentPanel->uber->icon_h = maxy;
+
 # ifdef DEBUG_INIT
   fprintf(stderr,"OK\n%s: Creating icon windows...",MyName);
 # endif
@@ -548,6 +573,13 @@
     SetTransparentBackground(UberButton,Width,Height);
 # endif
 
+    CurrentPanel = CurrentPanel->next;
+  }
+  CurrentPanel = MainPanel;
+  UberButton   = CurrentPanel->uber;
+  MyWindow     = UberButton->IconWinParent;
+
+
 # ifdef DEBUG_INIT
   fprintf(stderr,"OK\n%s: Mapping windows...",MyName);
 # endif
@@ -594,8 +626,16 @@
 	switch(Event.type)
 	  {
 	  case Expose:
-	    if(Event.xany.window==MyWindow)
-	      {
+            PanelIndex = MainPanel;
+            while (PanelIndex && (PanelIndex->uber->IconWinParent != Event.xany.window))
+              PanelIndex = PanelIndex->next;
+            if (PanelIndex)
+            { UberButton = PanelIndex->uber;
+              MyWindow   = UberButton->IconWinParent;
+            }
+            else
+              break;
+
 #ifdef OLD_EXPOSE
 		if(Event.xexpose.count == 0)
 		  {
@@ -644,11 +684,10 @@
 		    ex=ey=10000;ex2=ey2=0;
 		  }
 #endif
-              }
 	    break;
 
 	  case ConfigureNotify:
-	    XGetGeometry(Dpy,MyWindow,&root,&x,&y,
+	    /* XGetGeometry(Dpy, MyWindow, &root, &x, &y,
 			 (ushort*)&tw,(ushort*)&th,
 			 (ushort*)&border_width,(ushort*)&depth);
 	    if(tw!=Width || th!=Height)
@@ -660,7 +699,7 @@
 		while(NextButton(&ub,&b,&button,0))
 		  MakeButton(b);
                 RedrawWindow(NULL);
-	      }
+	      } */ /* I don't like to change its size after it started */
 	    break;
 
 	  case KeyPress:
@@ -668,30 +707,68 @@
 	    if(keysym!=XK_Return && keysym!=XK_KP_Enter && keysym!=XK_Linefeed)
 	      break;	                /* fall through to ButtonPress */
 	  case ButtonPress:
+            PanelIndex = MainPanel;
+            b = NULL;
+            do
+              if (PanelIndex->uber->swallow)
+              {
+                UberButton = PanelIndex->uber;
+                MyWindow   = UberButton->IconWinParent;
+                if (Event.xany.window == MyWindow)
 	    CurrentButton = b = 
 	      select_button(UberButton,Event.xbutton.x,Event.xbutton.y);
+
+              }
+            while (!b && PanelIndex->next && (PanelIndex = PanelIndex->next));
+
 	    if(!b || !(b->flags&b_Action))
 	      {
 		CurrentButton=NULL;
 		break;
 	      }
+
+            CurrentPanel = PanelIndex; /* record which panel, the button pressed */
+            UberButton = CurrentPanel->uber;
+            MyWindow   = UberButton->IconWinParent;
+
 	    RedrawButton(b,0);
 	    if(!(act=GetButtonAction(b,Event.xbutton.button)))
 	      act=GetButtonAction(b,0);
 	    if(mystrncasecmp(act,"popup",5)!=0)
+	    { if (mystrncasecmp(act, "panel", 5) == 0)
+                Slide(seekpanel(b), b);
 	      break;
+            }
 	    else /* i.e. action is Popup */
 	      XUngrabPointer(Dpy,CurrentTime); /* And fall through */
 
 	  case KeyRelease:
 	  case ButtonRelease:
+            PanelIndex = MainPanel;
+            b = NULL;
+            while (PanelIndex && !b)
+            { if (PanelIndex->uber->swallow)
+              { UberButton = PanelIndex->uber;
+                MyWindow   = UberButton->IconWinParent;
+                if (Event.xany.window == MyWindow)
 	    b=select_button(UberButton,Event.xbutton.x,Event.xbutton.y);
+              }
+              PanelIndex = PanelIndex->next;
+            }
+
 	    if(!(act=GetButtonAction(b,Event.xbutton.button)))
 	      act=GetButtonAction(b,0);
 	    if(b && b==CurrentButton && act)
 	      {
 		if(mystrncasecmp(act,"Exec",4)==0)
 		  {
+                    /* close all subpanels */
+                    PanelIndex = MainPanel->next;
+                    while (PanelIndex)
+                    { if (PanelIndex->uber->swallow) Slide(PanelIndex, NULL);
+                      PanelIndex = PanelIndex->next;
+                    }
+
 		    /* Look for Exec "identifier", in which case the button
 		       stays down until window "identifier" materializes */
 		    i=4;
@@ -728,9 +805,14 @@
 		  DumpButtons(UberButton);
 		else if(mystrncasecmp(act,"SaveButtons",11)==0)
 		  SaveButtons(UberButton);
-		else
+		else if(mystrncasecmp(act,"panel",5))
 		  MySendText(fd,act,0);
 	      }
+
+            /* recover the old record */
+            UberButton = CurrentPanel->uber; /* the panel, the button pressed */
+            MyWindow   = UberButton->IconWinParent;
+
 	    b=CurrentButton;
 	    CurrentButton=NULL;
 	    if(b)
@@ -1041,6 +1123,11 @@
   unsigned long gcm;
   XClassHint myclasshints;
 
+  x = CurrentPanel->uber->x; /* Geometry x where to put the panel */
+  y = CurrentPanel->uber->y; /* Geometry y where to put the panel */
+  xneg = CurrentPanel->uber->w;
+  yneg = CurrentPanel->uber->h;
+
   if(maxx<16)
     maxx=16;
   if(maxy<16)
@@ -1160,13 +1247,15 @@
 # endif
   XSetWMProtocols(Dpy,MyWindow,&_XA_WM_DEL_WIN,1);
 
-  myclasshints.res_name=strdup(MyName);
-  myclasshints.res_class=strdup("FvwmButtons");
+  myclasshints.res_name=strdup((CurrentPanel == MainPanel)
+                                 ? MyName : CurrentPanel->uber->title);
+  myclasshints.res_class=strdup((CurrentPanel == MainPanel)
+                                 ? "FvwmButtons" : "FvwmButtonsPanel");
 
   {
     XTextProperty mynametext;
     char *list[]={NULL,NULL};
-    list[0]=MyName;
+    list[0]=(CurrentPanel == MainPanel) ? MyName : CurrentPanel->uber->title;
     if(!XStringListToTextProperty(list,1,&mynametext))
       {
 	fprintf(stderr,"%s: Failed to convert name to XText\n",MyName);
@@ -1652,3 +1741,114 @@
       }
 }
 
+/*
+ * Button
+ *   b->flags     |= b_Action (though b->hangon is ilegally used)
+ *   b->action[0]  = "panel-h" or "panel-v"
+ *   b->hangon     = panel title (case sensitive)
+ * Panel
+ *   uber->flags  |= b_Container (though the following fields are ilegally used)
+ *   uber->title   = the title of the panel
+ *   uber->IconWinParent = the panel window, will be assigned to MyWindow
+ *   uber->swallow = 0:hidden 1:shown
+ *   uber->icon_w  = panel width
+ *   uber->icon_h  = panel height
+ *   uber->x       = x position to start the panel wrt the button b
+ *   uber->y       = y position to start the panel wrt the button b
+ *   uber->w       = xneg
+ *   uber->h       = yneg
+ *   CurrentPanel  = the panel where the button b was pressed to popup a new panel
+ */
+
+#define PanelPopUpStep 32
+
+panel_info *seekpanel (button_info *b)
+{
+  panel_info *PanelIndex = MainPanel->next; /* skip the main panel */
+
+  while (PanelIndex && strcmp(b->hangon, PanelIndex->uber->title))
+    PanelIndex = PanelIndex->next;
+  
+  return PanelIndex;
+}
+
+void Slide (panel_info *p, button_info *b)
+{
+  Window PanelWin;
+  Window root;
+  int x, y, iw, ih, BW, depth;
+
+  if (!p) return;                            /* no such panel */
+  else    PanelWin = p->uber->IconWinParent; /* PanelWin is found */
+
+  if (p->uber->swallow)
+  { /* shown ---> hidden */
+    root = GetRealGeometry(Dpy, PanelWin, &x, &y,
+                           (ushort*)&iw, (ushort*)&ih,
+                           (ushort*)&BW, (ushort*)&depth);
+
+    if (b && b->action[0][6] == 'h')
+      while (PanelPopUpStep < iw)  /* horizontal */
+      { iw -= PanelPopUpStep;
+        x  += PanelPopUpStep;
+        XMoveResizeWindow(Dpy, PanelWin, x, y, iw, ih);
+      }
+    else
+      while (PanelPopUpStep < ih)  /* vertical */
+      { ih -= PanelPopUpStep;
+        y  += PanelPopUpStep;
+        XMoveResizeWindow(Dpy, PanelWin, x, y, iw, ih);
+      }
+
+    XUnmapWindow(Dpy, PanelWin);
+    p->uber->swallow = 0;
+  } 
+  else
+  { /* hidden ---> shown */
+    int ix = buttonXPos(b, b->n);  /* button in the CurrentPanel */
+    int iy = buttonYPos(b, b->n);  /* button in the CurrentPanel */
+
+    int mw = p->uber->icon_w; /* panel menu width */
+    int mh = p->uber->icon_h; /* panel menu height */
+    int w;                    /* current width */
+    int h;                    /* current height */
+
+    root = GetRealGeometry(Dpy, CurrentPanel->uber->IconWinParent, &x, &y,
+                           (ushort*)&iw, (ushort*)&ih,
+                           (ushort*)&BW, (ushort*)&depth);
+
+    x += p->uber->x + ix;
+    y += p->uber->y + iy;
+
+    /* initial position and size */
+    if (b->action[0][6] == 'h')
+    { w = mw % PanelPopUpStep;      /* horizontal */
+      if (w == 0) w = PanelPopUpStep;
+      x -= w;
+      XMoveResizeWindow(Dpy, PanelWin, x, y, w, mh);
+    }
+    else
+    { h = mh % PanelPopUpStep;      /* vertical */
+      if (h == 0) h = PanelPopUpStep;
+      y -= h;
+      XMoveResizeWindow(Dpy, PanelWin, x, y, mw, h);
+    }
+ 
+    XMapSubwindows(Dpy, PanelWin);
+    XMapWindow(Dpy, PanelWin);
+
+    if (b->action[0][6] == 'h')
+      while (w < mw)            /* horizontal */
+      { x -= PanelPopUpStep;
+        w += PanelPopUpStep;
+        XMoveResizeWindow(Dpy, PanelWin, x, y, w, mh);
+      }
+    else
+      while (h < mh)            /* vertical */
+      { y -= PanelPopUpStep;
+        h += PanelPopUpStep;
+        XMoveResizeWindow(Dpy, PanelWin, x, y, mw, h);
+      }
+    p->uber->swallow = 1;
+  }
+}
diff -u -b -B old/fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.h fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.h
--- old/fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.h	Thu Jun 26 16:32:32 1997
+++ fvwm-2.0.46/modules/FvwmButtons/FvwmButtons.h	Mon Feb  2 22:19:39 1998
@@ -69,6 +69,7 @@
 #define b_TitleHoriz  0x03 /* Mask for title x positioning info */
 #define b_Horizontal  0x04 /* HACK: stack title and iconwin horizontally */
 
+typedef struct panel_info_struct panel_info;
 typedef struct button_info_struct button_info;
 typedef struct container_info_struct container_info;
 #define ushort unsigned int
@@ -143,6 +144,11 @@
   ushort w,h,bw;           /* b_Swallow */
 };
 
+struct panel_info_struct
+{ button_info  *uber;      /* panel */
+  panel_info   *next;
+};
+
 #include "button.h"
 
 /* -------------------------------- other macros --------------------------- */
@@ -173,6 +179,7 @@
 extern Window MyWindow;
 extern char *MyName;
 extern button_info *UberButton,*CurrentButton;
+extern panel_info *MainPanel, *CurrentPanel;
 
 extern char *iconPath;
 extern char *pixmapPath;
Only in fvwm-2.0.46/modules/FvwmButtons: Makefile
diff -u -b -B old/fvwm-2.0.46/modules/FvwmButtons/parse.c fvwm-2.0.46/modules/FvwmButtons/parse.c
--- old/fvwm-2.0.46/modules/FvwmButtons/parse.c	Thu Jun 26 16:32:33 1997
+++ fvwm-2.0.46/modules/FvwmButtons/parse.c	Wed Feb 11 23:05:38 1998
@@ -28,7 +28,7 @@
 #include "FvwmButtons.h"
 #include "button.h"
 
-extern int w,h,x,y,xneg,yneg;
+extern int w,h,x,y,xneg,yneg; /* used in ParseConfigLine */ 
 extern char *config_file;
 
 /* ----------------------------------- macros ------------------------------ */
@@ -400,6 +400,7 @@
     {
       char *opts[]={"back","fore","font","title","icon","frame","padding",
 		      "swallow","action","container","end","nosize","size",
+                      "panel",
 		      NULL};
       trimleft(s);
       while(*s && *s!=')')
@@ -620,6 +621,42 @@
 		fprintf(stderr,"%s: Illegal size arguments\n",MyName);
 	      break;
 
+	      /* --------------------------- panel ------------------------ */
+	     
+	    case 13: /* Panel */
+	      trimleft(s);
+	      i=0;
+	      if(*s=='(')
+		{
+		  s++;
+		  i=strtol(s,&t,10);
+		  s=t;
+		  while(*s && *s!=')') 
+		    s++;
+		  if(*s==')')s++;
+		}
+              if (i == 1)
+              { /* horizontal */
+                AddButtonAction(b,0,strdup("panel-h"));
+                if ((~b->flags)&(b_Title | b_Icon))
+		{ b->icon_file = strdup("arrow_left.xpm");
+		  b->IconWin   = None;
+		  b->flags    |= b_Icon;
+                }
+              }
+	      else
+              { /* vertical */
+                AddButtonAction(b,0,strdup("panel-v"));
+                if ((~b->flags)&(b_Title | b_Icon))
+		{ b->icon_file = strdup("arrow_up.xpm");
+		  b->IconWin   = None;
+		  b->flags    |= b_Icon;
+                }
+              }
+	      t = seekright(&s);
+              b->hangon = strdup(t);  /* which panel to popup */
+	      break;
+
 	    default:
 	      t=seekright(&s);
 	      fprintf(stderr,"%s: Illegal button option \"%s\"\n",MyName,t);
@@ -695,7 +732,7 @@
 {
   button_info *ub=*ubb;
   char *opts[]={"geometry","font","padding","columns","rows","back","fore",
-		  "frame","file","pixmap",NULL};
+		  "frame","file","pixmap","panel",NULL};
   int i,j,k;
 
   switch(MatchSeveralLines(s,opts,&s))
@@ -711,10 +748,10 @@
 	    flags=XParseGeometry(geom,&g_x,&g_y,&width,&height);
 	    if(flags&WidthValue) w=width;
 	    if(flags&HeightValue) h=height;
-	    if(flags&XValue) x=g_x;
-	    if(flags&YValue) y=g_y;
-	    if(flags&XNegative) xneg=1;
-	    if(flags&YNegative) yneg=1;
+	    if(flags&XValue)    UberButton->x = g_x;
+	    if(flags&YValue)    UberButton->y = g_y;
+	    if(flags&XNegative) UberButton->w = 1;
+	    if(flags&YNegative) UberButton->h = 1;
 	  }
 	break;
       }
@@ -755,6 +792,22 @@
       else
         CopyString(&(ub->c->back_file),s);
       ub->c->flags|=b_IconBack;
+      break;
+    case 10:/* Panel */
+      trimleft(s);
+      CurrentPanel->next = (panel_info *) mymalloc(sizeof(panel_info));
+      CurrentPanel = CurrentPanel->next;
+      CurrentPanel->next = NULL;
+      CurrentPanel->uber = UberButton
+                         = (button_info *) mymalloc(sizeof(button_info));
+      UberButton->title = seekright(&s);
+      UberButton->flags = 0;
+      UberButton->parent = NULL;
+      UberButton->BWidth = 1;
+      UberButton->BHeight = 1;
+      UberButton->swallow = 0; /* subpanel is hidden initially */
+      MakeContainer(UberButton);
+      *ubb = UberButton;
       break;
     default:
       trimleft(s);