Mercurial > hg > openttd
changeset 5124:fe6d669699bf draft
(svn r7205) -Fix [FS#350, SF#1560913]: Window allocation and deletion messed with the actual window
structs inside their array, and possibly invalidating pointers higher up.
Meaning that any function called within an wndproc could cause unknown/invalid pointers
once control was returned to this function. Solved by the introduction of an extra
abstraction layer, an array of z-window positions that is only concerned with the
pointers.
author | Darkvater <Darkvater@openttd.org> |
---|---|
date | Sat, 18 Nov 2006 16:47:02 +0000 |
parents | 9cddbe5b6739 |
children | 23f9c36e71e9 |
files | sound.c station_gui.c train_gui.c vehicle_gui.c viewport.c window.c window.h |
diffstat | 7 files changed, 302 insertions(+), 234 deletions(-) [+] |
line wrap: on
line diff
--- a/sound.c +++ b/sound.c @@ -194,12 +194,12 @@ static void SndPlayScreenCoordFx(SoundFx sound, int x, int y) { - const Window *w; + const Window* const *wz; if (msf.effect_vol == 0) return; - for (w = _windows; w != _last_window; w++) { - const ViewPort* vp = w->viewport; + FOR_ALL_WINDOWS(wz) { + const ViewPort *vp = (*wz)->viewport; if (vp != NULL && IS_INSIDE_1D(x, vp->virtual_left, vp->virtual_width) &&
--- a/station_gui.c +++ b/station_gui.c @@ -148,9 +148,10 @@ void RebuildStationLists(void) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; ++w) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class == WC_STATION_LIST) { WP(w, plstations_d).flags |= SL_REBUILD; SetWindowDirty(w); @@ -160,9 +161,10 @@ void ResortStationLists(void) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; ++w) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class == WC_STATION_LIST) { WP(w, plstations_d).flags |= SL_RESORT; SetWindowDirty(w);
--- a/train_gui.c +++ b/train_gui.c @@ -664,8 +664,7 @@ DeleteWindowById(WC_BUILD_VEHICLE, tile); - w = AllocateWindowDesc(&_new_rail_vehicle_desc); - w->window_number = tile; + w = AllocateWindowDescFront(&_new_rail_vehicle_desc, tile); w->vscroll.cap = 8; w->widget[BUILD_TRAIN_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
--- a/vehicle_gui.c +++ b/vehicle_gui.c @@ -102,32 +102,40 @@ void RebuildVehicleLists(void) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; ++w) + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; + switch (w->window_class) { - case WC_TRAINS_LIST: case WC_ROADVEH_LIST: - case WC_SHIPS_LIST: case WC_AIRCRAFT_LIST: - WP(w, vehiclelist_d).l.flags |= VL_REBUILD; - SetWindowDirty(w); - break; - default: break; + case WC_TRAINS_LIST: + case WC_ROADVEH_LIST: + case WC_SHIPS_LIST: + case WC_AIRCRAFT_LIST: + WP(w, vehiclelist_d).l.flags |= VL_REBUILD; + SetWindowDirty(w); + break; } + } } void ResortVehicleLists(void) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; ++w) + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; + switch (w->window_class) { - case WC_TRAINS_LIST: case WC_ROADVEH_LIST: - case WC_SHIPS_LIST: case WC_AIRCRAFT_LIST: - WP(w, vehiclelist_d).l.flags |= VL_RESORT; - SetWindowDirty(w); - break; - default: break; + case WC_TRAINS_LIST: + case WC_ROADVEH_LIST: + case WC_SHIPS_LIST: + case WC_AIRCRAFT_LIST: + WP(w, vehiclelist_d).l.flags |= VL_RESORT; + SetWindowDirty(w); + break; } + } } static void BuildVehicleList(vehiclelist_d* vl, PlayerID owner, StationID station, OrderID order, uint16 depot_airport_index, uint16 window_type)
--- a/viewport.c +++ b/viewport.c @@ -183,35 +183,38 @@ static Point _vp_move_offs; -static void DoSetViewportPosition(const Window *w, int left, int top, int width, int height) +static void DoSetViewportPosition(const Window* const *wz, int left, int top, int width, int height) { - for (; w < _last_window; w++) { + + for (; wz != _last_z_window; wz++) { + const Window *w = *wz; + if (left + width > w->left && w->left + w->width > left && top + height > w->top && w->top + w->height > top) { if (left < w->left) { - DoSetViewportPosition(w, left, top, w->left - left, height); - DoSetViewportPosition(w, left + (w->left - left), top, width - (w->left - left), height); + DoSetViewportPosition(wz, left, top, w->left - left, height); + DoSetViewportPosition(wz, left + (w->left - left), top, width - (w->left - left), height); return; } if (left + width > w->left + w->width) { - DoSetViewportPosition(w, left, top, (w->left + w->width - left), height); - DoSetViewportPosition(w, left + (w->left + w->width - left), top, width - (w->left + w->width - left) , height); + DoSetViewportPosition(wz, left, top, (w->left + w->width - left), height); + DoSetViewportPosition(wz, left + (w->left + w->width - left), top, width - (w->left + w->width - left) , height); return; } if (top < w->top) { - DoSetViewportPosition(w, left, top, width, (w->top - top)); - DoSetViewportPosition(w, left, top + (w->top - top), width, height - (w->top - top)); + DoSetViewportPosition(wz, left, top, width, (w->top - top)); + DoSetViewportPosition(wz, left, top + (w->top - top), width, height - (w->top - top)); return; } if (top + height > w->top + w->height) { - DoSetViewportPosition(w, left, top, width, (w->top + w->height - top)); - DoSetViewportPosition(w, left, top + (w->top + w->height - top), width , height - (w->top + w->height - top)); + DoSetViewportPosition(wz, left, top, width, (w->top + w->height - top)); + DoSetViewportPosition(wz, left, top + (w->top + w->height - top), width , height - (w->top + w->height - top)); return; } @@ -294,7 +297,7 @@ i = top + height - _screen.height; if (i >= 0) height -= i; - if (height > 0) DoSetViewportPosition(w + 1, left, top, width, height); + if (height > 0) DoSetViewportPosition(FindWindowZPosition(w) + 1, left, top, width, height); } }
--- a/window.c +++ b/window.c @@ -18,6 +18,10 @@ // delta between mouse cursor and upper left corner of dragged window static Point _drag_delta; +static Window _windows[25]; +Window *_z_windows[lengthof(_windows)]; +Window **_last_z_window; // always points to the next free space in the z-array + void CDECL SetWindowWidgetsDisabledState(Window *w, bool disab_stat, int widgets, ...) { va_list wdg_list; @@ -81,8 +85,8 @@ } -static Window *StartWindowDrag(Window *w); -static Window *StartWindowSizing(Window *w); +static void StartWindowDrag(Window *w); +static void StartWindowSizing(Window *w); static void DispatchLeftClickEvent(Window *w, int x, int y) { @@ -122,13 +126,13 @@ } if (e.we.click.widget == 1) { /* 'Title bar' */ - StartWindowDrag(w); // if not return then w = StartWindowDrag(w); to get correct pointer + StartWindowDrag(w); return; } } if (w->desc_flags & WDF_RESIZABLE && wi->type == WWT_RESIZEBOX) { - StartWindowSizing(w); // if not return then w = StartWindowSizing(w); to get correct pointer + StartWindowSizing(w); return; } @@ -197,55 +201,58 @@ } } -static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom); +static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom); void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) { - Window *w; + Window* const *wz; DrawPixelInfo bk; _cur_dpi = &bk; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (right > w->left && bottom > w->top && left < w->left + w->width && top < w->top + w->height) { - DrawOverlappedWindow(w, left, top, right, bottom); + DrawOverlappedWindow(wz, left, top, right, bottom); } } } -static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) +static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom) { - const Window *v = w; + const Window* const *vz = wz; int x; - while (++v != _last_window) { + while (++vz != _last_z_window) { + const Window *v = *vz; + if (right > v->left && bottom > v->top && left < v->left + v->width && top < v->top + v->height) { if (left < (x=v->left)) { - DrawOverlappedWindow(w, left, top, x, bottom); - DrawOverlappedWindow(w, x, top, right, bottom); + DrawOverlappedWindow(wz, left, top, x, bottom); + DrawOverlappedWindow(wz, x, top, right, bottom); return; } if (right > (x=v->left + v->width)) { - DrawOverlappedWindow(w, left, top, x, bottom); - DrawOverlappedWindow(w, x, top, right, bottom); + DrawOverlappedWindow(wz, left, top, x, bottom); + DrawOverlappedWindow(wz, x, top, right, bottom); return; } if (top < (x=v->top)) { - DrawOverlappedWindow(w, left, top, right, x); - DrawOverlappedWindow(w, left, x, right, bottom); + DrawOverlappedWindow(wz, left, top, right, x); + DrawOverlappedWindow(wz, left, x, right, bottom); return; } if (bottom > (x=v->top + v->height)) { - DrawOverlappedWindow(w, left, top, right, x); - DrawOverlappedWindow(w, left, x, right, bottom); + DrawOverlappedWindow(wz, left, top, right, x); + DrawOverlappedWindow(wz, left, x, right, bottom); return; } @@ -257,12 +264,12 @@ DrawPixelInfo *dp = _cur_dpi; dp->width = right - left; dp->height = bottom - top; - dp->left = left - w->left; - dp->top = top - w->top; + dp->left = left - (*wz)->left; + dp->top = top - (*wz)->top; dp->pitch = _screen.pitch; dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left; dp->zoom = 0; - CallWindowEventNP(w, WE_PAINT); + CallWindowEventNP(*wz, WE_PAINT); } } @@ -280,13 +287,21 @@ SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height); } +/** Find the z-value of a window. A window must already be open + * or the behaviour is undefined but function should never fail */ +Window **FindWindowZPosition(const Window *w) +{ + Window **wz; + + for (wz = _z_windows;; wz++) { + assert(wz < _last_z_window); + if (*wz == w) return wz; + } +} + void DeleteWindow(Window *w) { - WindowClass wc; - WindowNumber wn; - Window *v; - int count; - + Window **wz; if (w == NULL) return; if (_thd.place_mode != VHM_NONE && @@ -295,29 +310,26 @@ ResetObjectToPlace(); } - wc = w->window_class; - wn = w->window_number; - CallWindowEventNP(w, WE_DESTROY); - - w = FindWindowById(wc, wn); - if (w->viewport != NULL) DeleteWindowViewport(w); SetWindowDirty(w); - free(w->widget); + w->widget = NULL; - v = --_last_window; - count = (byte*)v - (byte*)w; - memmove(w, w + 1, count); + /* Find the window in the z-array, and effectively remove it + * by moving all windows after it one to the left */ + wz = FindWindowZPosition(w); + memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz); + _last_z_window--; } Window *FindWindowById(WindowClass cls, WindowNumber number) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class == cls && w->window_number == number) return w; } @@ -331,12 +343,14 @@ void DeleteWindowByClass(WindowClass cls) { - Window *w; + Window* const *wz; restart_search: /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others */ - for (w = _windows; w != _last_window; w++) { + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class == cls) { DeleteWindow(w); goto restart_search; @@ -350,12 +364,14 @@ * @param id PlayerID player identifier */ void DeletePlayerWindows(PlayerID id) { - Window *w; + Window* const *wz; restart_search: /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others */ - for (w = _windows; w != _last_window; w++) { + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->caption_color == id) { DeleteWindow(w); goto restart_search; @@ -373,9 +389,11 @@ * @param new_player PlayerID of the new owner of the window */ void ChangeWindowOwner(PlayerID old_player, PlayerID new_player) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; + if (w->caption_color != old_player) continue; if (w->window_class == WC_PLAYER_COLOR) continue; if (w->window_class == WC_FINANCES) continue; @@ -391,17 +409,20 @@ } } +static void BringWindowToFront(const Window *w); -static Window *BringWindowToFront(Window *w); - +/** Find a window and make it the top-window on the screen. The window + * gets a white border for a brief period of time to visualize its + * "activation" + * @return a pointer to the window thus activated */ Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) { Window *w = FindWindowById(cls, number); if (w != NULL) { w->flags4 |= WF_WHITE_BORDER_MASK; + BringWindowToFront(w); SetWindowDirty(w); - w = BringWindowToFront(w); } return w; @@ -419,29 +440,27 @@ * - New window, Chatbar (only if open) * The window is marked dirty for a repaint if the window is actually moved * @param w window that is put into the foreground - * @return pointer to the window, can be different! + * @return pointer to the window, the same as the input pointer */ -static Window *BringWindowToFront(Window *w) +static void BringWindowToFront(const Window *w) { - Window *v; - Window temp; - - v = _last_window; - do { - if (--v < _windows) return w; - } while (IsVitalWindow(v)); + Window *tempz; + Window **wz = FindWindowZPosition(w); + Window **vz = _last_z_window; - if (w == v) return w; - - assert(w < v); + /* Bring the window just below the vital windows */ + do { + if (--vz < _z_windows) return; + } while (IsVitalWindow(*vz)); - temp = *w; - memmove(w, w + 1, (v - w) * sizeof(Window)); - *v = temp; + if (wz == vz) return; // window is already in the right position + assert(wz < vz); - SetWindowDirty(v); + tempz = *wz; + memmove(wz, wz + 1, (byte*)vz - (byte*)wz); + *vz = tempz; - return v; + SetWindowDirty(w); } /** We have run out of windows, so find a suitable candidate for replacement. @@ -453,9 +472,10 @@ */ static Window *FindDeletableWindow(void) { - Window *w; + Window* const *wz; - for (w = _windows; w < endof(_windows); w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) { return w; } @@ -466,15 +486,17 @@ /** A window must be freed, and all are marked as important windows. Ease the * restriction a bit by allowing to delete sticky windows. Keep important/vital * windows intact (Main window, Toolbar, Statusbar, News Window, Chatbar) + * Start finding an appropiate candidate from the lowest z-values (bottom) * @see FindDeletableWindow() * @return w Pointer to the window that is being deleted */ static Window *ForceFindDeletableWindow(void) { - Window *w; + Window* const *wz; - for (w = _windows;; w++) { - assert(w < _last_window); + for (wz = _z_windows;; wz++) { + Window *w = *wz; + assert(wz < _last_z_window); if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w; } } @@ -502,6 +524,28 @@ } } +static Window *FindFreeWindow(void) +{ + Window *w; + + for (w = _windows; w < endof(_windows); w++) { + Window* const *wz; + bool window_in_use = false; + + FOR_ALL_WINDOWS(wz) { + if (*wz == w) { + window_in_use = true; + break; + } + } + + if (!window_in_use) return w; + } + + assert(_last_z_window == endof(_z_windows)); + return NULL; +} + /* Open a new window. * This function is called from AllocateWindow() or AllocateWindowDesc() * See descriptions for those functions for usage @@ -512,47 +556,13 @@ int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const Widget *widget, int window_number) { - Window *w = _last_window; // last window keeps track of the highest open window - - // We have run out of windows, close one and use that as the place for our new one - if (w >= endof(_windows)) { - w = FindDeletableWindow(); - - if (w == NULL) w = ForceFindDeletableWindow(); - - DeleteWindow(w); - w = _last_window; - } - - /* XXX - This very strange construction makes sure that the chatbar is always - * on top of other windows. Why? It is created as last_window (so, on top). - * Any other window will go below toolbar/statusbar/news window, which implicitely - * also means it is below the chatbar. Very likely needs heavy improvement - * to de-braindeadize */ - if (w != _windows && cls != WC_SEND_NETWORK_MSG) { - Window *v; + Window *w = FindFreeWindow(); - /* XXX - if not this order (toolbar/statusbar and then news), game would - * crash because it will try to copy a negative size for the news-window. - * Eg. window was already moved BELOW news (which is below toolbar/statusbar) - * and now needs to move below those too. That is a negative move. */ - v = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (v != NULL) { - memmove(v+1, v, (byte*)w - (byte*)v); - w = v; - } - - v = FindWindowById(WC_STATUS_BAR, 0); - if (v != NULL) { - memmove(v+1, v, (byte*)w - (byte*)v); - w = v; - } - - v = FindWindowById(WC_NEWS_WINDOW, 0); - if (v != NULL) { - memmove(v+1, v, (byte*)w - (byte*)v); - w = v; - } + /* We have run out of windows, close one and use that as the place for our new one */ + if (w == NULL) { + w = FindDeletableWindow(); + if (w == NULL) w = ForceFindDeletableWindow(); + DeleteWindow(w); } // Set up window properties @@ -572,10 +582,32 @@ w->resize.step_height = 1; w->window_number = window_number; - _last_window++; + { + Window **wz = _last_z_window; + + /* Hacky way of specifying always-on-top windows. These windows are + * always above other windows because they are moved below them. + * status-bar is above news-window because it has been created earlier. + * Also, as the chat-window is excluded from this, it will always be + * the last window, thus always on top. + * XXX - Yes, ugly, probably needs something like w->always_on_top flag + * to implement correctly, but even then you need some kind of distinction + * between on-top of chat/news and status windows, because these conflict */ + if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) { + if (FindWindowById(WC_MAIN_TOOLBAR, 0) != NULL) wz--; + if (FindWindowById(WC_STATUS_BAR, 0) != NULL) wz--; + if (FindWindowById(WC_NEWS_WINDOW, 0) != NULL) wz--; + if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--; + + assert(wz >= _z_windows); + if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz); + } + + *wz = w; + _last_z_window++; + } SetWindowDirty(w); - CallWindowEventNP(w, WE_CREATE); return w; @@ -612,7 +644,7 @@ static bool IsGoodAutoPlace1(int left, int top) { int right,bottom; - Window *w; + Window* const *wz; _awap_r.left= left; _awap_r.top = top; @@ -623,7 +655,8 @@ return false; // Make sure it is not obscured by any window. - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (w->window_class == WC_MAIN_WINDOW) continue; if (right > w->left && @@ -640,7 +673,7 @@ static bool IsGoodAutoPlace2(int left, int top) { int width,height; - Window *w; + Window* const *wz; _awap_r.left= left; _awap_r.top = top; @@ -651,7 +684,8 @@ if (top < 22 || top > _screen.height - (height>>2)) return false; // Make sure it is not obscured by any window. - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (w->window_class == WC_MAIN_WINDOW) continue; if (left + width > w->left && @@ -667,7 +701,7 @@ static Point GetAutoPlacePosition(int width, int height) { - Window *w; + Window* const *wz; Point pt; _awap_r.width = width; @@ -675,7 +709,8 @@ if (IsGoodAutoPlace1(0, 24)) goto ok_pos; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (w->window_class == WC_MAIN_WINDOW) continue; if (IsGoodAutoPlace1(w->left+w->width+2,w->top)) goto ok_pos; @@ -688,7 +723,8 @@ if (IsGoodAutoPlace1(w->left+w->width-width,w->top- height-2)) goto ok_pos; } - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (w->window_class == WC_MAIN_WINDOW) continue; if (IsGoodAutoPlace2(w->left+w->width+2,w->top)) goto ok_pos; @@ -701,7 +737,9 @@ int left=0,top=24; restart:; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; + if (w->left == left && w->top == top) { left += 5; top += 5; @@ -810,10 +848,10 @@ * @return a pointer to the found window if any, NULL otherwise */ Window *FindWindowFromPt(int x, int y) { - Window *w; + Window* const *wz; - for (w = _last_window; w != _windows;) { - --w; + for (wz = _last_z_window; wz != _z_windows;) { + Window *w = *--wz; if (IS_INSIDE_1D(x, w->left, w->width) && IS_INSIDE_1D(y, w->top, w->height)) { return w; } @@ -827,18 +865,18 @@ IConsoleClose(); memset(&_windows, 0, sizeof(_windows)); - _last_window = _windows; + _last_z_window = _z_windows; InitViewports(); _no_scroll = 0; } void UnInitWindowSystem(void) { - Window *w; + Window* const *wz; // delete all malloced widgets - for (w = _windows; w != _last_window; w++) { - free(w->widget); - w->widget = NULL; + FOR_ALL_WINDOWS(wz) { + free((*wz)->widget); + (*wz)->widget = NULL; } } @@ -855,10 +893,10 @@ static void DecreaseWindowCounters(void) { Window *w; - + Window* const *wz; - for (w = _last_window; w != _windows;) { - --w; + for (wz = _last_z_window; wz != _z_windows;) { + w = *--wz; // Unclick scrollbar buttons if they are pressed. if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) { w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP); @@ -867,8 +905,8 @@ CallWindowEventNP(w, WE_MOUSELOOP); } - for (w = _last_window; w != _windows;) { - --w; + for (wz = _last_z_window; wz != _z_windows;) { + w = *--wz; if (w->flags4&WF_TIMEOUT_MASK && !(--w->flags4&WF_TIMEOUT_MASK)) { CallWindowEventNP(w, WE_TIMEOUT); @@ -990,12 +1028,14 @@ static bool HandleWindowDragging(void) { - Window *w; + Window* const *wz; // Get out immediately if no window is being dragged at all. if (!_dragging_window) return true; // Otherwise find the window... - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; + if (w->flags4 & WF_DRAGGING) { const Widget *t = &w->widget[1]; // the title bar ... ugh const Window *v; @@ -1018,11 +1058,15 @@ ny = y; if (_patches.window_snap_radius != 0) { + const Window* const *vz; + int hsnap = _patches.window_snap_radius; int vsnap = _patches.window_snap_radius; int delta; - for (v = _windows; v != _last_window; ++v) { + FOR_ALL_WINDOWS(vz) { + const Window *v = *vz; + if (v == w) continue; // Don't snap at yourself if (y + w->height > v->top && y < v->top + v->height) { @@ -1220,7 +1264,7 @@ return false; } -static Window *StartWindowDrag(Window *w) +static void StartWindowDrag(Window *w) { w->flags4 |= WF_DRAGGING; _dragging_window = true; @@ -1228,12 +1272,11 @@ _drag_delta.x = w->left - _cursor.pos.x; _drag_delta.y = w->top - _cursor.pos.y; - w = BringWindowToFront(w); + BringWindowToFront(w); DeleteWindowById(WC_DROPDOWN_MENU, 0); - return w; } -static Window *StartWindowSizing(Window *w) +static void StartWindowSizing(Window *w) { w->flags4 |= WF_SIZING; _dragging_window = true; @@ -1241,16 +1284,14 @@ _drag_delta.x = _cursor.pos.x; _drag_delta.y = _cursor.pos.y; - w = BringWindowToFront(w); + BringWindowToFront(w); DeleteWindowById(WC_DROPDOWN_MENU, 0); - SetWindowDirty(w); - return w; } static bool HandleScrollbarScrolling(void) { - Window *w; + Window* const *wz; int i; int pos; Scrollbar *sb; @@ -1259,7 +1300,9 @@ if (!_scrolling_scrollbar) return true; // Find the scrolling window - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; + if (w->flags4 & WF_SCROLL_MIDDLE) { // Abort if no button is clicked any more. if (!_left_button_down) { @@ -1325,18 +1368,22 @@ return false; } -static Window *MaybeBringWindowToFront(Window *w) +static void MaybeBringWindowToFront(const Window *w) { - Window *u; + const Window* const *wz; + const Window* const *uz; if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || w->window_class == WC_TOOLTIPS || w->window_class == WC_DROPDOWN_MENU) { - return w; + return; } - for (u = w; ++u != _last_window;) { + wz = FindWindowZPosition(w); + for (uz = wz; ++uz != _last_z_window;) { + const Window *u = *uz; + if (u->window_class == WC_MAIN_WINDOW || IsVitalWindow(u) || u->window_class == WC_TOOLTIPS || @@ -1351,10 +1398,9 @@ continue; } - return BringWindowToFront(w); + BringWindowToFront(w); + return; } - - return w; } /** Send a message from one window to another. The receiving window is found by @@ -1397,10 +1443,10 @@ */ void SendWindowMessageClass(WindowClass wnd_class, uint msg, uint wparam, uint lparam) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; w++) { - if (w->window_class == wnd_class) SendWindowMessageW(w, msg, wparam, lparam); + FOR_ALL_WINDOWS(wz) { + if ((*wz)->window_class == wnd_class) SendWindowMessageW(*wz, msg, wparam, lparam); } } @@ -1409,7 +1455,7 @@ * 16 bits the keycode */ void HandleKeypress(uint32 key) { - Window *w; + Window* const *wz; WindowEvent e; /* Stores if a window with a textfield for typing is open * If this is the case, keypress events are only passed to windows with text fields and @@ -1443,8 +1489,9 @@ } // Call the event, start with the uppermost window. - for (w = _last_window; w != _windows;) { - --w; + for (wz = _last_z_window; wz != _z_windows;) { + Window *w = *--wz; + // if a query window is open, only call the event for certain window types if (query_open && w->window_class != WC_QUERY_STRING && @@ -1459,7 +1506,7 @@ } if (e.we.keypress.cont) { - w = FindWindowById(WC_MAIN_TOOLBAR, 0); + Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); // When there is no toolbar w is null, check for that if (w != NULL) w->wndproc(w, &e); } @@ -1532,7 +1579,7 @@ w = FindWindowFromPt(x, y); if (w == NULL) return; - w = MaybeBringWindowToFront(w); + MaybeBringWindowToFront(w); vp = IsPtInWindowViewport(w, x, y); /* Don't allow any action in a viewport if either in menu of in generating world */ @@ -1631,21 +1678,20 @@ void UpdateWindows(void) { - Window *w; + Window* const *wz; static int we4_timer = 0; int t = we4_timer + 1; if (t >= 100) { - for (w = _last_window; w != _windows;) { - w--; - CallWindowEventNP(w, WE_4); + for (wz = _last_z_window; wz != _z_windows;) { + CallWindowEventNP(*--wz, WE_4); } t = 0; } we4_timer = t; - for (w = _last_window; w != _windows;) { - w--; + for (wz = _last_z_window; wz != _z_windows;) { + Window *w = *--wz; if (w->flags4 & WF_WHITE_BORDER_MASK) { w->flags4 -= WF_WHITE_BORDER_ONE; @@ -1655,8 +1701,8 @@ DrawDirtyBlocks(); - for (w = _windows; w != _last_window; w++) { - if (w->viewport != NULL) UpdateViewportPosition(w); + FOR_ALL_WINDOWS(wz) { + if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz); } DrawTextMessage(); // Redraw mouse cursor in case it was hidden @@ -1679,9 +1725,10 @@ void InvalidateWindow(WindowClass cls, WindowNumber number) { - const Window *w; + const Window* const *wz; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (w->window_class == cls && w->window_number == number) SetWindowDirty(w); } } @@ -1698,9 +1745,10 @@ void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index) { - const Window *w; + const Window* const *wz; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + const Window *w = *wz; if (w->window_class == cls && w->window_number == number) { InvalidateWidget(w, widget_index); } @@ -1709,10 +1757,10 @@ void InvalidateWindowClasses(WindowClass cls) { - const Window *w; + const Window* const *wz; - for (w = _windows; w != _last_window; w++) { - if (w->window_class == cls) SetWindowDirty(w); + FOR_ALL_WINDOWS(wz) { + if ((*wz)->window_class == cls) SetWindowDirty(*wz); } } @@ -1723,40 +1771,42 @@ void InvalidateWindowData(WindowClass cls, WindowNumber number) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w); } } void InvalidateWindowClassesData(WindowClass cls) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; w++) { - if (w->window_class == cls) InvalidateThisWindowData(w); + FOR_ALL_WINDOWS(wz) { + if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz); } } void CallWindowTickEvent(void) { - Window *w; + Window* const *wz; - for (w = _last_window; w != _windows;) { - --w; - CallWindowEventNP(w, WE_TICK); + for (wz = _last_z_window; wz != _z_windows;) { + CallWindowEventNP(*--wz, WE_TICK); } } void DeleteNonVitalWindows(void) { - Window *w; + Window* const *wz; restart_search: /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others */ - for (w = _windows; w != _last_window; w++) { + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_SELECT_GAME && w->window_class != WC_MAIN_TOOLBAR && @@ -1764,6 +1814,7 @@ w->window_class != WC_TOOLBAR_MENU && w->window_class != WC_TOOLTIPS && (w->flags4 & WF_STICKY) == 0) { // do not delete windows which are 'pinned' + DeleteWindow(w); goto restart_search; } @@ -1777,16 +1828,18 @@ * that standard windows (status bar, etc.) are not stickied, so these aren't affected */ void DeleteAllNonVitalWindows(void) { - Window *w; + Window* const *wz; /* Delete every window except for stickied ones, then sticky ones as well */ DeleteNonVitalWindows(); + restart_search: /* When we find the window to delete, we need to restart the search - * as deleting this window could cascade in deleting (many) others */ - for (w = _windows; w != _last_window; w++) { - if (w->flags4 & WF_STICKY) { - DeleteWindow(w); + * as deleting this window could cascade in deleting (many) others + * anywhere in the z-array */ + FOR_ALL_WINDOWS(wz) { + if ((*wz)->flags4 & WF_STICKY) { + DeleteWindow(*wz); goto restart_search; } } @@ -1818,9 +1871,10 @@ void RelocateAllWindows(int neww, int newh) { - Window *w; + Window* const *wz; - for (w = _windows; w != _last_window; w++) { + FOR_ALL_WINDOWS(wz) { + Window *w = *wz; int left, top; if (w->window_class == WC_MAIN_WINDOW) {
--- a/window.h +++ b/window.h @@ -833,10 +833,12 @@ void DeleteAllNonVitalWindows(void); void HideVitalWindows(void); void ShowVitalWindows(void); +Window **FindWindowZPosition(const Window *w); /* window.c */ -VARDEF Window _windows[25]; -VARDEF Window *_last_window; +extern Window *_z_windows[]; +extern Window **_last_z_window; +#define FOR_ALL_WINDOWS(wz) for (wz = _z_windows; wz != _last_z_window; wz++) VARDEF Point _cursorpos_drag_start;