(svn r1225) -Feature: SHIFT+DEL now deletes all non-vital windows (only status bar and main bar remain)
authordarkvater
Wed, 22 Dec 2004 17:37:21 +0000
changeset 763 ced9fcae239d
parent 762 ef014856bd88
child 764 7e1e17b7c7d4
(svn r1225) -Feature: SHIFT+DEL now deletes all non-vital windows (only status bar and main bar remain)
-Fix: For everyone who tried to crash the game by opening a huge amount of windows and stickying all of them; bad luck. It's fixed now (thanks Tron for the helpful criticism). First all normal windows are a candidate for replacement, then if none are found, sticky windows. Then..well that should not happen :)
main_gui.c
window.c
window.h
--- a/main_gui.c	Wed Dec 22 16:54:55 2004 +0000
+++ b/main_gui.c	Wed Dec 22 17:37:21 2004 +0000
@@ -152,26 +152,6 @@
 	SndPlayFx(SND_15_BEEP);
 }
 
-/* It is possible that a stickied window gets to a position where the 
- * 'close' button is outside the gaming area. You cannot close it then; except
- * with this function. It closes all windows calling the standard function,
- * then, does a little hacked loop of closing all stickied windows. Note
- * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
-static void CloseEveryWindow(void)
-{
-	Window *w;
-	// Delete every window except for stickied ones
-	DeleteNonVitalWindows();
-	// Delete all sticked windows
-	for (w = _windows; w != _last_window;) {
-		if (w->flags4 & WF_STICKY) {
-			DeleteWindow(w);
-			w = _windows;
-		} else
-			w++;
-	}
-}
-
 typedef void MenuClickedProc(int index);
 
 
@@ -183,7 +163,7 @@
 	case 2: ShowPatchesSelection(); return;
 	case 3: ShowNewgrf(); return;
 
-	case 5: CloseEveryWindow(); return; 
+	case 5: DeleteAllNonVitalWindows(); return; 
 	case 6: _display_opt ^= DO_SHOW_TOWN_NAMES; MarkWholeScreenDirty(); return;
 	case 7: _display_opt ^= DO_SHOW_STATION_NAMES; MarkWholeScreenDirty(); return;
 	case 8: _display_opt ^= DO_SHOW_SIGNS; MarkWholeScreenDirty(); return;
@@ -2330,6 +2310,7 @@
 
 		case WKC_ESC: ResetObjectToPlace(); break;
 		case WKC_DELETE: DeleteNonVitalWindows(); break;
+		case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
 		case 'Q' | WKC_CTRL: AskExitGame(); break;
 		case 'Q' | WKC_META: AskExitGame(); break; // this enables command + Q on mac
 		case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
--- a/window.c	Wed Dec 22 16:54:55 2004 +0000
+++ b/window.c	Wed Dec 22 17:37:21 2004 +0000
@@ -285,6 +285,34 @@
 	return v;
 }
 
+/* We have run out of windows, so find a suitable candidate for replacement.
+ * Keep all important windows intact */
+static Window *FindDeletableWindow(void)
+{
+	Window *w;
+	for (w = _windows; w < endof(_windows); w++) {
+		if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_MAIN_TOOLBAR &&
+			  w->window_class != WC_STATUS_BAR && w->window_class != WC_NEWS_WINDOW &&
+				!(w->flags4 & WF_STICKY) )
+				return w;
+	}
+	return NULL;
+}
+
+/* A window must be freed, and all are marked as important windows. Ease the
+ * restriction a bit by allowing to delete sticky windows */
+static Window *ForceFindDeletableWindow(void)
+{
+	Window *w;
+	for (w = _windows;; w++) {
+		assert(w < _last_window);
+
+		if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_MAIN_TOOLBAR &&
+			  w->window_class != WC_STATUS_BAR && w->window_class != WC_NEWS_WINDOW)
+				return w;
+	}
+}
+
 Window *AllocateWindow(
 							int x,
 							int y,
@@ -296,21 +324,16 @@
 {
 	Window *w;
 
-restart:;
 	w = _last_window;
 
 	if (w >= endof(_windows)) {
-		for(w=_windows; ;w++) {
-			assert(w < _last_window);
+		w = FindDeletableWindow();
 
-			if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_MAIN_TOOLBAR &&
-			    w->window_class != WC_STATUS_BAR && w->window_class != WC_NEWS_WINDOW &&
-					!(w->flags4 & WF_STICKY) ) {
+		if (w == NULL) // no window found, force it!
+			w = ForceFindDeletableWindow();
 
-					DeleteWindow(w);
-					goto restart;
-			}
-		}
+		DeleteWindow(w);
+		w = _last_window;
 	}
 
 	if (w != _windows && cls != WC_NEWS_WINDOW) {
@@ -1343,6 +1366,26 @@
 	}
 }
 
+/* It is possible that a stickied window gets to a position where the 
+ * 'close' button is outside the gaming area. You cannot close it then; except
+ * with this function. It closes all windows calling the standard function,
+ * then, does a little hacked loop of closing all stickied windows. Note
+ * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
+void DeleteAllNonVitalWindows(void)
+{
+	Window *w;
+	// Delete every window except for stickied ones
+	DeleteNonVitalWindows();
+	// Delete all sticked windows
+	for (w = _windows; w != _last_window;) {
+		if (w->flags4 & WF_STICKY) {
+			DeleteWindow(w);
+			w = _windows;
+		} else
+			w++;
+	}
+}
+
 int PositionMainToolbar(Window *w)
 {
 	DEBUG(misc, 1) ("Repositioning Main Toolbar...");
--- a/window.h	Wed Dec 22 16:54:55 2004 +0000
+++ b/window.h	Wed Dec 22 17:37:21 2004 +0000
@@ -459,6 +459,7 @@
 
 Window *GetCallbackWnd();
 void DeleteNonVitalWindows();
+void DeleteAllNonVitalWindows(void);
 
 /* window.c */
 VARDEF Window _windows[25];