"Just mail it to the fvwm mailing list, is the best way I guess."  Hm.
Enclosed is a patch to fvwm-2.0.45 that will allow a set of menus to be
established, and then modified afterwards, by adding functions
"AddAboveInMenu", "ReplaceInMenu", and "DeleteFromMenu" to complement the
existing "AddToMenu" function. 
This is useful at my lab, because we are trying to modularize our standard
user config;  we want to be able to allow the users to change whatever
they like of their environment, while the admin staff is still able to
change the defaults and be sure that no one is inadvertently left out.
This is pretty easy in the case of shells and so forth, since each
variable can be overwritten individually.  Fvwm2 accommodates changes to
the Styles pretty well even without this patch---but as for menus, users
can only add to the end, and if they want to make minor changes to one of
the other items, well, they have to inline the whole menu, or worse, the
whole config. 
I'd appreciate any feedback from fvwm's maintainers (or anyone who knows
what they're talking about, for that matter).  Thanks,
-------------------------------------------------------------------------
Konrad Schroder           
http://www.hitl.washington.edu/people/perseant/
System Administrator                         perseant_at_hitl.washington.edu
Human Interface Technology Lab                      Voice: (206) 616-1478
Box 352142, University of Washington, 98195, USA      FAX: (206) 543-5380
*** fvwm/builtins.c.dist	Wed Jan 22 05:37:28 1997
--- fvwm/builtins.c	Fri Sep 05 14:09:14 1997
***************
*** 468,471 ****
--- 468,570 ----
  #endif
  char *last_menu = NULL;
+ char *last_menu_arg = NULL;
+ int last_menu_flag = MA_NORMAL;
+ 
+ 
+ void delete_item_from_menu(XEvent *eventp, Window w, FvwmWindow *tmp_win,
+                           unsigned long context, char *action, int *Module)
+ {
+   MenuRoot *mr;
+ 
+   char *token, *rest,*item;
+   char *flag, *arg;
+ 
+ #ifdef USEDECOR
+   last_decor = NULL;
+ #endif
+   if(last_menu != NULL)
+     free(last_menu);
+   last_menu = NULL;
+ 
+   rest = GetNextToken(action,&token);
+   mr = FindPopup(token);
+   rest = GetNextToken(rest,&item);
+ 
+   if(mr)
+   {
+       DeleteFromMenu(mr,item);
+       MakeMenu(mr);
+   }
+   free(item);
+ }
+ 
+ /* This is the same as below, but controls placement too */
+ void add_item_above_in_menu(XEvent *eventp, Window w, FvwmWindow *tmp_win,
+                           unsigned long context, char *action, int *Module)
+ {
+   MenuRoot *mr;
+ 
+   char *token, *rest,*item;
+   char *flag, *arg;
+ 
+ #ifdef USEDECOR
+   last_decor = NULL;
+ #endif
+ 
+   rest = GetNextToken(action,&token);
+   mr = FindPopup(token);
+   if(mr == NULL)
+     mr = NewMenuRoot(token, 0);
+   if(last_menu != NULL)
+     free(last_menu);
+   last_menu = token;
+ 
+   rest = GetNextToken(rest,&arg);   /* the reference item */
+ 
+   rest = GetNextToken(rest,&item);  /* now the new item */
+ 
+   last_menu_arg  = arg;
+   last_menu_flag = MA_ABOVE;
+ 
+   AddToMenu(mr, item, rest, MA_ABOVE, arg);
+   free(item);
+   
+   MakeMenu(mr);
+   return;
+ }
+ 
+ void replace_item_in_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ 		      unsigned long context,
+ 		      char *action, int *Module)
+ {
+   MenuRoot *mr;
+ 
+   char *token, *rest,*item;
+   char *flag, *arg;
+ 
+ #ifdef USEDECOR
+   last_decor = NULL;
+ #endif
+   last_menu = NULL;
+   last_menu_arg  = NULL;
+   last_menu_flag = MA_NORMAL;
+ 
+   rest = GetNextToken(action,&token);
+   mr = FindPopup(token);
+   if(mr == NULL)
+     mr = NewMenuRoot(token, 0);
+   if(last_menu != NULL)
+     free(last_menu);
+ 
+   rest = GetNextToken(rest,&arg);   /* the reference item */
+   rest = GetNextToken(rest,&item);  /* now the new item */
+ 
+   AddToMenu(mr, item, rest, MA_REPLACE, arg);
+   free(item);
+   
+   MakeMenu(mr);
+   return;
+ }
+ 
  void add_item_to_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
                        unsigned long context,
***************
*** 475,478 ****
--- 574,579 ----
  
    char *token, *rest,*item;
+   char *flag, *arg;
+   int i_flag = MA_NORMAL, i;
  
  #ifdef USEDECOR
***************
*** 487,493 ****
      free(last_menu);
    last_menu = token;
    rest = GetNextToken(rest,&item);
  
!   AddToMenu(mr, item,rest);
    free(item);
    
--- 588,597 ----
      free(last_menu);
    last_menu = token;
+   last_menu_arg  = NULL;
+   last_menu_flag = MA_NORMAL;
+ 
    rest = GetNextToken(rest,&item);
  
!   AddToMenu(mr, item, rest, MA_NORMAL, NULL);
    free(item);
    
***************
*** 517,521 ****
        rest = GetNextToken(action,&item);
        
!       AddToMenu(mr, item,rest);
        free(item);
        
--- 621,625 ----
        rest = GetNextToken(action,&item);
        
!       AddToMenu(mr, item, rest, last_menu_flag, last_menu_arg);
        free(item);
        
***************
*** 549,553 ****
    rest = GetNextToken(action,&item);
  
!   AddToMenu(mr, item,rest);
    free(item);
    
--- 653,657 ----
    rest = GetNextToken(action,&item);
  
!   AddToMenu(mr, item, rest, last_menu_flag, last_menu_arg);
    free(item);
    
***************
*** 591,595 ****
    rest = GetNextToken(rest,&item);
  
!   AddToMenu(mr, item,rest);
    free(item);
    
--- 695,699 ----
    rest = GetNextToken(rest,&item);
  
!   AddToMenu(mr, item, rest, MA_NORMAL, NULL);
    free(item);
    
*** fvwm/functions.c.dist	Fri Sep 05 13:16:50 1997
--- fvwm/functions.c	Fri Sep 05 14:15:08 1997
***************
*** 36,39 ****
--- 36,40 ----
  struct functions func_config[] =
  {
+   {"AddAboveInMenu",add_item_above_in_menu, F_ADDMENU_ABOVE, FUNC_NO_WINDOW},
  #ifdef MULTISTYLE
    {"AddButtonStyle",AddButtonStyle,  F_ADD_BUTTON_STYLE,    FUNC_NO_WINDOW},
***************
*** 68,71 ****
--- 69,73 ----
  #endif
    {"DestroyFunc",  destroy_menu,     F_DESTROY_MENU,        FUNC_NO_WINDOW},
+   {"DestroyMenuItem", delete_item_from_menu, F_DELMITEM,    FUNC_NO_WINDOW},
    {"DestroyMenu",  destroy_menu,     F_DESTROY_MENU,        FUNC_NO_WINDOW},
    {"DestroyModuleConfig", DestroyModConfig, F_DESTROY_MOD,  FUNC_NO_WINDOW},
***************
*** 112,115 ****
--- 114,118 ----
    {"Refresh",      refresh_function, F_REFRESH,             FUNC_NO_WINDOW},
    {"RefreshWindow",refresh_win_function, F_REFRESH,         FUNC_NEEDS_WINDOW},
+   {"ReplaceInMenu",replace_item_in_menu, F_REPLACEMENU,     FUNC_NO_WINDOW},
    {"Resize",       resize_window,    F_RESIZE,              FUNC_NEEDS_WINDOW},
    {"Restart",      restart_function, F_RESTART,             FUNC_NO_WINDOW},
*** fvwm/menus.c.dist	Thu Sep 04 12:08:52 1997
--- fvwm/menus.c	Fri Sep 05 13:02:24 1997
***************
*** 876,880 ****
--- 876,893 ----
  
  
+ MenuItem *DestroyMenuItem(MenuItem *mi)
+ {
+     MenuItem *tmp2 = mi->next;
  
+       if (mi->item != NULL) free(mi->item);
+       if (mi->item2 != NULL) free(mi->item2);
+       if (mi->action != NULL) free(mi->action);
+       if(mi->picture)
+ 	DestroyPicture(dpy,mi->picture);
+       if(mi->lpicture)
+ 	DestroyPicture(dpy,mi->lpicture);
+       free(mi);
+       return tmp2;
+ }
  
  void DestroyMenu(MenuRoot *mr)
***************
*** 908,921 ****
    while(mi != NULL)
      {
!       tmp2 = mi->next;
!       if (mi->item != NULL) free(mi->item);
!       if (mi->item2 != NULL) free(mi->item2);
!       if (mi->action != NULL) free(mi->action);
!       if(mi->picture)
! 	DestroyPicture(dpy,mi->picture);
!       if(mi->lpicture)
! 	DestroyPicture(dpy,mi->lpicture);
!       free(mi);
!       mi = tmp2;
      }
    free(mr);
--- 921,925 ----
    while(mi != NULL)
      {
!         mi = DestroyMenuItem(mi);
      }
    free(mr);
***************
*** 1167,1171 ****
--- 1171,1252 ----
  
  
+ /*
+  * GetReferenceMenuItem - get a reference menu item to delete, or add after.
+  */
  
+ MenuItem *GetReferenceMenuItem(MenuRoot *menu, char *ref)
+ {
+     MenuItem *mi_ref;
+ 
+     if(ref==NULL || ref[0]=='\0')
+         mi_ref = menu->first;
+     else
+     {
+         if(menu->first == NULL)
+             mi_ref = NULL;
+         else
+         {
+             for(mi_ref=menu->first; mi_ref; mi_ref = mi_ref->next)
+             {
+                 if(mi_ref->item && strcasecmp(mi_ref->item,ref)==0)
+                     break;
+             }
+             if(mi_ref==NULL)
+             {
+                 /* try again with item2 */
+                 for(mi_ref=menu->first; mi_ref; mi_ref = mi_ref->next)
+                 {
+                     if(mi_ref->item2 && strcasecmp(mi_ref->item2,ref)==0)
+                         break;
+                 }
+             }
+             if(mi_ref==NULL)
+             {
+                 /* now we're desperate...try partial matches */
+                 for(mi_ref=menu->first; mi_ref; mi_ref = mi_ref->next)
+                 {
+                     if((mi_ref->item
+                         && strncasecmp(mi_ref->item,ref,strlen(ref))==0)
+                        || (mi_ref->item2
+                            && strncasecmp(mi_ref->item2,ref,strlen(ref))==0))
+                         break;
+                 }
+             }
+         }
+     }
+     return mi_ref;
+ }
+ 
+ /*
+  * DeleteFromMenu - delete an item from a menu
+  */
+ 
+ void DeleteFromMenu(MenuRoot *menu, char *item)
+ {
+     MenuItem *delenda, *t;
+ 
+     delenda = GetReferenceMenuItem(menu,item);
+     if(delenda)
+     {
+         /* detach */
+         if(delenda->prev)
+             delenda->prev->next = delenda->next;
+         else
+             menu->first = delenda->next;
+         if(delenda->next)
+             delenda->next->prev = delenda->prev;
+         else
+             menu->last = delenda->prev;
+ 
+         /* destroy */
+         DestroyMenuItem(delenda);
+ 
+         /* clean up numbering */
+         menu->items=0;
+         for(t=menu->first; t; t=t->next)
+             t->item_num = menu->items++;
+     }
+ }
+ 
  /***********************************************************************
   *
***************
*** 1181,1184 ****
--- 1262,1267 ----
   *	action	- the string to possibly execute
   *	func	- the numeric function
+  * (ks) how     - additional flags to control placement
+  * (ks) ref     - menu item relative to which placement is done
   *
   * ckh - need to add boolean to say whether or not to expand for pixmaps,
***************
*** 1186,1193 ****
   *
   ***********************************************************************/
! void AddToMenu(MenuRoot *menu, char *item, char *action)
  {
!   MenuItem *tmp;
    char *start,*end;
  
    if(item == NULL)
--- 1269,1277 ----
   *
   ***********************************************************************/
! void AddToMenu(MenuRoot *menu, char *item, char *action, int how, char *ref)
  {
!   MenuItem *tmp, *mi_ref, *t;
    char *start,*end;
+   int i;
  
    if(item == NULL)
***************
*** 1195,1209 ****
  
    tmp = (MenuItem *)safemalloc(sizeof(MenuItem));
!   if (menu->first == NULL)
!     {
!       menu->first = tmp;
!       tmp->prev = NULL;
!     }
!   else
!     {
!       menu->last->next = tmp;
!       tmp->prev = menu->last;
!     }
!   menu->last = tmp;
    tmp->picture=NULL;
    tmp->lpicture=NULL;
--- 1279,1337 ----
  
    tmp = (MenuItem *)safemalloc(sizeof(MenuItem));
! 
!   /* If we need a reference, get one here.  NULL means none was available */
!   if(how!=MA_NORMAL)
!   {
!       mi_ref = GetReferenceMenuItem(menu,ref);
!   }
! 
!   switch(how)
!   {
!       /* all of these cases fall through to the standard case, if  */
!       /* no reference menu item could be found */
!   case MA_REPLACE:
!       if(mi_ref)
!       {
!           tmp->prev = mi_ref->prev;
!           tmp->next = mi_ref->next;
!           if(tmp->prev)
!               tmp->prev->next = tmp;
!           else
!               menu->first = tmp;
!           if(tmp->next)
!               tmp->next->prev = tmp;
!           else
!               menu->last = tmp;
!           DestroyMenuItem(mi_ref);
!           break;
!       }
!   case MA_ABOVE:
!       if(mi_ref)
!       {
!           tmp->next = mi_ref;
!           tmp->prev = mi_ref->prev;
!           mi_ref->prev = tmp;
!           if(tmp->prev)
!               tmp->prev->next = tmp;
!           else
!               menu->first = tmp;
!           break;
!       }
!   case MA_NORMAL:
!   default:
!       if (menu->first == NULL)
!       {
!           menu->first = tmp;
!           tmp->prev = NULL;
!       }
!       else
!       {
!           menu->last->next = tmp;
!           tmp->prev = menu->last;
!       }
!       menu->last = tmp;
!       break;
!   }
! 
    tmp->picture=NULL;
    tmp->lpicture=NULL;
***************
*** 1258,1265 ****
  
    tmp->action = stripcpy(action);
-   tmp->next = NULL;
    tmp->state = 0;
    tmp->func_type = find_func_type(tmp->action);
!   tmp->item_num = menu->items++;
  }
  
--- 1386,1401 ----
  
    tmp->action = stripcpy(action);
    tmp->state = 0;
    tmp->func_type = find_func_type(tmp->action);
!   if(how == MA_NORMAL)
!   {
!       tmp->next = NULL;
!       tmp->item_num = menu->items++;
!   }
!   else
!       for(menu->items=0, tmp=menu->first; tmp; tmp=tmp->next)
!       {
!           tmp->item_num = menu->items++;
!       }
  }
  
*** fvwm/menus.h.dist	Thu Sep 04 12:45:19 1997
--- fvwm/menus.h	Thu Sep 04 12:47:09 1997
***************
*** 54,57 ****
--- 54,62 ----
  #include "../libs/fvwmlib.h"
  
+ #define MA_NORMAL 0
+ #define MA_ABOVE  1
+ #define MA_BENEATH 2
+ #define MA_REPLACE 3
+ 
  typedef struct MenuItem
  {
*** fvwm/misc.h.dist	Thu Sep 04 13:41:18 1997
--- fvwm/misc.h	Fri Sep 05 14:17:11 1997
***************
*** 224,228 ****
  extern void       UngrabEm(void);
  extern MenuRoot   *NewMenuRoot(char *name, int function_or_popup);
! extern void       AddToMenu(MenuRoot *, char *, char *);
  extern void       MakeMenu(MenuRoot *);
  extern void       CaptureAllWindows(void);
--- 224,228 ----
  extern void       UngrabEm(void);
  extern MenuRoot   *NewMenuRoot(char *name, int function_or_popup);
! extern void       AddToMenu(MenuRoot *, char *, char *, int, char *);
  extern void       MakeMenu(MenuRoot *);
  extern void       CaptureAllWindows(void);
***************
*** 468,472 ****
--- 468,481 ----
  void GetMenuXPMFile(char *name, MenuItem *it);
  void GetMenuBitmapFile(char *name, MenuItem *it);
+ void delete_item_from_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ 		      unsigned long context,
+ 		      char *action, int *Module);
+ void add_item_above_in_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ 		      unsigned long context,
+ 		      char *action, int *Module);
  void add_item_to_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ 		      unsigned long context,
+ 		      char *action, int *Module);
+ void replace_item_in_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
                        unsigned long context,
                        char *action, int *Module);
*** fvwm/parse.h.dist	Fri Sep 05 13:16:33 1997
--- fvwm/parse.h	Fri Sep 05 14:06:30 1997
***************
*** 74,77 ****
--- 74,82 ----
  #define F_TITLESTYLE            56
  #define F_EXEC_SETUP            57
+ 
+ #define F_ADDMENU_ABOVE         58
+ #define F_DELMITEM              59
+ #define F_REPLACEMENU           60
+ 
  /* Functions which require a target window */
  #define F_RESIZE		100
*** fvwm/windows.c.dist	Thu Sep 04 13:33:13 1997
--- fvwm/windows.c	Thu Sep 04 13:34:04 1997
***************
*** 135,139 ****
    }
    mr=NewMenuRoot(tlabel,0);
!   AddToMenu(mr, tlabel, "TITLE");      
  
    next_desk = 0;
--- 135,139 ----
    }
    mr=NewMenuRoot(tlabel,0);
!   AddToMenu(mr, tlabel, "TITLE", MA_NORMAL, NULL);      
  
    next_desk = 0;
***************
*** 227,231 ****
          else
            sprintf(tlabel,"WindowListFunc %ld",t->w);
!         AddToMenu(mr, t_hot, tlabel);
  #ifdef MINI_ICONS
          /* Add the title pixmap */
--- 227,231 ----
          else
            sprintf(tlabel,"WindowListFunc %ld",t->w);
!         AddToMenu(mr, t_hot, tlabel, MA_NORMAL, NULL);
  #ifdef MINI_ICONS
          /* Add the title pixmap */
--
Visit the official FVWM web page at <URL:http://www.hpc.uh.edu/fvwm/>.
To unsubscribe from the list, send "unsubscribe fvwm" in the body of a
message to majordomo_at_hpc.uh.edu.
To report problems, send mail to fvwm-owner_at_hpc.uh.edu.
Received on Fri Sep 05 1997 - 20:00:55 BST