Index: src/window.cpp =================================================================== --- src/window.cpp (revision 22729) +++ src/window.cpp (working copy) @@ -813,7 +813,7 @@ static void BringWindowToFront(Window *w); /** - * Find a window and make it the top-window on the screen. + * Find a window and make it the relative top-window on the screen. * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation". * @param cls WindowClass of the window to activate * @param number WindowNumber of the window to activate @@ -849,20 +849,64 @@ } /** - * On clicking on a window, make it the frontmost window of all. However - * there are certain windows that always need to be on-top; these include - * - Toolbar, Statusbar (always on) - * - 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 + * Get the z-priority for a given window. This is defined as an arbitrary integer value which is used only in + * comparison with other z-priority values; a window with a given z-priority will appear above other windows with + * a lower value, and below those with a higher one. (The ordering within z-priorities can be mixed). + * @param w The window to get the z-priority for + * @pre w->window_class != WC_INVALID + * @return The window's z-priority + */ +static inline int GetWindowZPriority(const Window *w) +{ + assert(w->window_class != WC_INVALID); + + switch (w->window_class) { + case WC_ENDSCREEN: + return 8; + + case WC_HIGHSCORE: + return 7; + + case WC_TOOLTIPS: + return 6; + + case WC_CONSOLE: + return 5; + + case WC_DROPDOWN_MENU: + return 4; + + case WC_MAIN_TOOLBAR: + case WC_STATUS_BAR: + return 3; + + case WC_SAVELOAD: + return 2; + + case WC_SEND_NETWORK_MSG: + case WC_NEWS_WINDOW: + return 1; + + default: + return 0; + + case WC_MAIN_WINDOW: + return -1; + } +} + +/** + * On clicking on a window, make it the frontmost window of all windows with an equal + * or lower z-priority. The window is marked dirty for a repaint if the window is actually moved + * @param w window that is put into the relative foreground * @return pointer to the window, the same as the input pointer */ static void BringWindowToFront(Window *w) { Window *v = _z_front_window; - /* Bring the window just below the vital windows */ - for (; v != NULL && v != w && IsVitalWindow(v); v = v->z_back) { } + /* Bring the window just below the windows that have a greater z-priority */ + for (; v != NULL && v != w && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w)); v = v->z_back) { } if (v == NULL || w == v) return; // window is already in the right position @@ -929,20 +973,14 @@ * window has a text box, then take focus anyway. */ if (this->window_class != WC_OSK && (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL)) SetFocusedWindow(this); - /* 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 */ + /* Insert the window into the correct location in the z-ordering. */ Window *w = _z_front_window; - if (w != NULL && this->window_class != WC_SEND_NETWORK_MSG && this->window_class != WC_HIGHSCORE && this->window_class != WC_ENDSCREEN) { - if (FindWindowById(WC_MAIN_TOOLBAR, 0) != NULL) w = w->z_back; - if (FindWindowById(WC_STATUS_BAR, 0) != NULL) w = w->z_back; - if (FindWindowById(WC_NEWS_WINDOW, 0) != NULL) w = w->z_back; - if (FindWindowByClass(WC_SEND_NETWORK_MSG) != NULL) w = w->z_back; + if (w != NULL) { + while (w != NULL && (w->window_class == WC_INVALID || GetWindowZPriority(w) > GetWindowZPriority(this))) { + assert(!w->z_front || w->z_front->window_class == WC_INVALID || w->window_class == WC_INVALID || + GetWindowZPriority(w->z_front) >= GetWindowZPriority(w)); + w = w->z_back; + } if (w == NULL) { _z_back_window->z_front = this; @@ -1930,13 +1968,13 @@ } /** - * Check if a window can be made top-most window, and if so do + * Check if a window can be made relative top-most window, and if so do * it. If a window does not obscure any other windows, it will not * be brought to the foreground. Also if the only obscuring windows * are so-called system-windows, the window will not be moved. * The function will return false when a child window of this window is a * modal-popup; function returns a false and child window gets a white border - * @param w Window to bring on-top + * @param w Window to bring relatively on-top * @return false if the window has an active modal child, true otherwise */ static bool MaybeBringWindowToFront(Window *w)