Included new window structure flag w_closing_state and let window_close() set this flag - after drawing all windows, check them again and call window_do_close() which then actually closes the window(s) marked to. Solving all sorts of problems when windows close while being drawn (network error messageboxes, game_leave_menus(), etc.)

This commit is contained in:
zicodxx 2011-02-03 11:48:27 +01:00
parent 9a64614a04
commit c7a65c9313
4 changed files with 28 additions and 9 deletions

View file

@ -4,6 +4,7 @@ D2X-Rebirth Changelog
--------
main/automap.c, main/gamecntl.c: Little fixes for recent kconfig/event overhaul: Automap inputs read by kconfig should be processed by input rather than idle and automap frame calculations should be done while drawing; Fixed drop_bomb_count which could roll over to 255 dropping bombs without end
main/gauges: Corrected values for gr_ubox while drawing a window_view to not mess up at some widescreen resolutions
arch/include/window.h, arch/sdl/event.c, arch/sdl/window.c: Included new window structure flag w_closing_state and let window_close() set this flag - after drawing all windows, check them again and call window_do_close() which then actually closes the window(s) marked to. Solving all sorts of problems when windows close while being drawn (network error messageboxes, game_leave_menus(), etc.)
20110202
--------

View file

@ -19,6 +19,7 @@ typedef struct window window;
extern window *window_create(grs_canvas *src, int x, int y, int w, int h, int (*event_callback)(window *wind, d_event *event, void *data), void *data);
extern int window_close(window *wind);
extern int window_do_close(window *wind);
extern int window_exists(window *wind);
extern window *window_get_front(void);
extern window *window_get_first(void);

View file

@ -152,16 +152,19 @@ void event_process(void)
return;
event.type = EVENT_WINDOW_DRAW; // then draw all visible windows
wind = window_get_first();
while (wind != NULL)
{
window *next_wind = window_get_next(wind); // check this in now in case this window closes during EVENT_WINDOW_DRAW
for (wind = window_get_first(); wind != NULL; wind = window_get_next(wind))
if (window_is_visible(wind))
window_send_event(wind, &event);
wind = next_wind;
}
gr_flip();
wind = window_get_first();
while (wind != NULL) // go through all windows and actually close them if they want to
{
window *next_wind = window_get_next(wind);
window_do_close(wind);
wind = next_wind;
}
}
void event_toggle_focus(int activate_focus)

View file

@ -18,6 +18,7 @@ struct window
grs_canvas w_canv; // the window's canvas to draw to
int (*w_callback)(window *wind, d_event *event, void *data); // the event handler
int w_visible; // whether it's visible
ubyte w_closing_state;
void *data; // whatever the user wants (eg menu data for 'newmenu' menus)
struct window *prev; // the previous window in the doubly linked list
struct window *next; // the next window in the doubly linked list
@ -41,6 +42,7 @@ window *window_create(grs_canvas *src, int x, int y, int w, int h, int (*event_c
gr_init_sub_canvas(&wind->w_canv, src, x, y, w, h);
wind->w_callback = event_callback;
wind->w_visible = 1; // default to visible
wind->w_closing_state = 0;
wind->data = data;
if (FirstWindow == NULL)
@ -59,11 +61,20 @@ window *window_create(grs_canvas *src, int x, int y, int w, int h, int (*event_c
}
int window_close(window *wind)
{
wind->w_closing_state = 1; // mark this window to close
return 1;
}
int window_do_close(window *wind)
{
window *prev;
d_event event;
int (*w_callback)(window *wind, d_event *event, void *data) = wind->w_callback;
if (!wind->w_closing_state)
return 0;
if (wind == window_get_front())
WINDOW_SEND_EVENT(wind, EVENT_WINDOW_DEACTIVATED); // Deactivate first
@ -74,7 +85,10 @@ int window_close(window *wind)
{
// User 'handled' the event, cancelling close
if (wind == window_get_front())
WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); // Reactivate. May cause flashing of some sort, too bad
{
WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED);
wind->w_closing_state = 0;
}
return 0;
}
@ -88,8 +102,8 @@ int window_close(window *wind)
wind->prev->next = wind->next;
if ((prev = window_get_front()))
WINDOW_SEND_EVENT(prev, EVENT_WINDOW_ACTIVATED); // Reactivate. May cause flashing of some sort, too bad
WINDOW_SEND_EVENT(prev, EVENT_WINDOW_ACTIVATED);
d_free(wind);
event.type = EVENT_WINDOW_CLOSED;