Re: [AD] non blocking menu bug

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


> Ok, then what I'd like is basically to be able to do the following, if I
> need to get the control of the dialog engine back:
>
>     dialog_message(dlg, MSG_CLOSE_MENU, 0, NULL);
>
> any d_menu_proc object would then close their currently active menu if
> any.

d_menu_proc will do that for MSG_LOSTMOUSE and MSG_END but I don't think the 
user needs to know it.

> I'm not too sure what you mean, so I'll let you do it, you have a better
> understanding of the engine than me. Attached is what I have done so far.

After thinking a little more about this stuff, I realized that close_menu() 
can be merged with shutdown_menu(), thus bringing about two advantages:
- we don't add yet another API function,
- the construct:

      volatile int terminate = FALSE;

      MENU_PLAYER *player = init_menu(menu, x, y);

      while (update_menu(player)) {
         if (terminate)
            break;
      }

      return shutdown_menu(player);

is now supported.

Then I tweaked dialog_message() so that it first sends the message to any 
active d_menu_proc object, and added MSG_END to the list of messages handled 
by a d_menu_proc object. This had the nice side-effect that the construct:

      volatile int terminate = FALSE;

      DIALOG_PLAYER *player = init_dialog(dialog, focus_obj);

      while (update_dialog(player)) {
         if (terminate)
            break;
      }

      return shutdown_dialog(player);

is now supported, so your original testcase doesn't crash anymore :-)

Patch applied to mainline.

-- 
Eric Botcazou
Index: src/gui.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/gui.c,v
retrieving revision 1.62
diff -u -p -r1.62 gui.c
--- src/gui.c	15 Mar 2003 08:51:10 -0000	1.62
+++ src/gui.c	1 Apr 2003 09:22:43 -0000
@@ -354,7 +354,7 @@ int object_message(DIALOG *dialog, int m
  */
 int dialog_message(DIALOG *dialog, int msg, int c, int *obj)
 {
-   int count, res, r, force;
+   int count, res, r, force, try;
    ASSERT(dialog);
 
    if (msg == MSG_DRAW)
@@ -364,21 +364,40 @@ int dialog_message(DIALOG *dialog, int m
 
    res = D_O_K;
 
-   for (count=0; dialog[count].proc; count++) { 
-      if ((force) || (!(dialog[count].flags & D_HIDDEN))) {
-	 r = object_message(dialog+count, msg, c);
-
-	 if (r != D_O_K) {
-	    res |= r;
-	    if (obj)
-	       *obj = count;
-	 }
+   /* If a menu spawned by a d_menu_proc object is active, the dialog engine
+    * has effectively been shutdown for the sake of safety. This means that
+    * we can't send the message to the other objects in the dialog. So try
+    * first to send the message to the d_menu_proc object and, if the menu
+    * is then not active anymore, send it to the other objects as well.
+    */
+   if (active_menu_player)
+      try = 2;
+   else
+      try = 1;
+
+   for (; try > 0; try--) {
+      for (count=0; dialog[count].proc; count++) {
+         if ((try == 2) && (&dialog[count] != active_menu_player->dialog))
+	    continue;
+
+	 if ((force) || (!(dialog[count].flags & D_HIDDEN))) {
+	    r = object_message(&dialog[count], msg, c);
+
+	    if (r != D_O_K) {
+	       res |= r;
+	       if (obj)
+		  *obj = count;
+	    }
 
-	 if ((msg == MSG_IDLE) && (dialog[count].flags & (D_DIRTY | D_HIDDEN)) == D_DIRTY) {
-	    dialog[count].flags &= ~D_DIRTY;
-	    object_message(dialog+count, MSG_DRAW, 0);
+	    if ((msg == MSG_IDLE) && (dialog[count].flags & (D_DIRTY | D_HIDDEN)) == D_DIRTY) {
+	       dialog[count].flags &= ~D_DIRTY;
+	       object_message(dialog+count, MSG_DRAW, 0);
+	    }
 	 }
       }
+
+      if (active_menu_player)
+	 break;
    }
 
    if (msg == MSG_DRAW)
@@ -1579,10 +1598,10 @@ int do_menu(MENU *menu, int x, int y)
 
 
 
-/* _init_menu:
+/* init_single_menu:
  *  Worker function for initialising a menu.
  */
-static MENU_PLAYER *_init_menu(MENU *menu, MENU_PLAYER *parent, DIALOG *dialog, int bar, int x, int y, int repos, int minw, int minh)
+static MENU_PLAYER *init_single_menu(MENU *menu, MENU_PLAYER *parent, DIALOG *dialog, int bar, int x, int y, int repos, int minw, int minh)
 {
    MENU_PLAYER *player;
    ASSERT(menu);
@@ -1639,7 +1658,7 @@ static MENU_PLAYER *_init_menu(MENU *men
  */ 
 MENU_PLAYER *init_menu(MENU *menu, int x, int y)
 {
-   return _init_menu(menu, NULL, NULL, FALSE, x, y, TRUE, 0, 0);
+   return init_single_menu(menu, NULL, NULL, FALSE, x, y, TRUE, 0, 0);
 }
 
 
@@ -1656,6 +1675,8 @@ MENU_PLAYER *init_menu(MENU *menu, int x
  */
 int update_menu(MENU_PLAYER *player)
 {
+   static int shutdown_single_menu(MENU_PLAYER *, int *);
+
    MENU_PLAYER *i;
    int c, c2;
    int old_sel, child_ret;
@@ -1866,13 +1887,13 @@ int update_menu(MENU_PLAYER *player)
 	 }
 
 	 /* recursively call child menu */
-	 player->child = _init_menu(player->menu[player->ret].child, player, NULL, FALSE, child_x, child_y, TRUE, 0, 0);
+	 player->child = init_single_menu(player->menu[player->ret].child, player, NULL, FALSE, child_x, child_y, TRUE, 0, 0);
 	 return TRUE;  /* continue */
       }
       
       while (player->parent) {  /* parent menu? */
 	 player = player->parent;
-	 shutdown_menu(player->child);
+	 shutdown_single_menu(player->child, NULL);
 	 player->child = NULL;
       }
       
@@ -1883,7 +1904,7 @@ int update_menu(MENU_PLAYER *player)
       if (player->parent) {
 	 child_ret = player->ret;  /* needed below */
 	 player = player->parent;
-	 shutdown_menu(player->child);
+	 shutdown_single_menu(player->child, NULL);
 	 player->child = NULL;
 	 player->ret = -1;
 	 player->mouse_button_was_pressed = FALSE;
@@ -1908,13 +1929,13 @@ int update_menu(MENU_PLAYER *player)
    
    return TRUE;
 }
-   
 
 
-/* _shutdown_menu:
+
+/* shutdown_single_menu:
  *  Worker function for shutting down a menu.
  */
-static int _shutdown_menu(MENU_PLAYER *player, int *dret)
+static int shutdown_single_menu(MENU_PLAYER *player, int *dret)
 {
    int ret;
    ASSERT(player);
@@ -1956,13 +1977,32 @@ static int _shutdown_menu(MENU_PLAYER *p
 
 
 
-/* shutdown_menu:
- *  Destroys a menu player object returned by init_menu(), returning the
+/* shutdown_tree_menu:
+ *  Destroys a menu player object returned by init_single_menu(), after
+ *  recursively closing all the sub-menus if necessary, and returns the
  *  index of the item that was selected, or -1 if it was dismissed.
  */
+static int shutdown_tree_menu(MENU_PLAYER *player, int *dret)
+{
+   ASSERT(player);
+
+   if (player->child) {
+      shutdown_tree_menu(player->child, dret);
+      player->child = NULL;
+   }
+
+   return shutdown_single_menu(player, dret);
+}
+
+
+
+/* shutdown_menu:
+ *  Destroys a menu player object returned by init_menu() and returns
+ *  the index of the item that was selected, or -1 if it was dismissed.
+ */
 int shutdown_menu(MENU_PLAYER *player)
 {
-   return _shutdown_menu(player, NULL);
+   return shutdown_tree_menu(player, NULL);
 }
 
 
@@ -2015,15 +2055,16 @@ int d_menu_proc(int msg, DIALOG *d, int 
 	    }
 
 	 /* initialize the menu */
-	 active_menu_player = _init_menu(d->dp, NULL, d, TRUE, d->x, d->y, FALSE, d->w, d->h);
+	 active_menu_player = init_single_menu(d->dp, NULL, d, TRUE, d->x, d->y, FALSE, d->w, d->h);
 	 break;
-	 
+
       case MSG_LOSTMOUSE:
+      case MSG_END:
 	 if (active_menu_player) {
-	    /* _shutdown_menu may call nested dialogs */
+	    /* shutdown_tree_menu may call nested dialogs */
 	    mp = active_menu_player;
 	    active_menu_player = NULL;
-	    _shutdown_menu(mp, &x);
+	    shutdown_tree_menu(mp, &x);
 
 	    do {
 	    } while (gui_mouse_b());


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/