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());